blob: 86f3c1f8cc27e14faac7c80002c76546eae80da0 [file] [log] [blame]
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm>
#include <ctime>
#include <fcntl.h>
#include <list>
#include <memory>
#include <string>
#include <json/reader.h>
#include <json/writer.h>
#include <unicode/calendar.h>
#include <unicode/datefmt.h>
#include <unicode/decimfmt.h>
#include <unicode/dtfmtsym.h>
#include <unicode/smpdtfmt.h>
#include "globalization_ndk.hpp"
#include "globalization_js.hpp"
/*
* The following constants are defined based on Cordova Globalization
* plugin definition. They should match exactly.
* https://github.com/apache/cordova-plugin-globalization/blob/master/doc/index.md
*/
const int UNKNOWN_ERROR = 0;
const int FORMATTING_ERROR = 1;
const int PARSING_ERROR = 2;
const int PATTERN_ERROR = 3;
namespace webworks {
std::string errorInJson(int code, const std::string& message)
{
Json::Value error;
error["code"] = code;
error["message"] = message;
Json::Value root;
root["error"] = error;
Json::FastWriter writer;
return writer.write(root);
}
std::string resultInJson(const std::string& value)
{
Json::Value root;
root["result"] = value;
Json::FastWriter writer;
return writer.write(root);
}
std::string resultInJson(bool value)
{
Json::Value root;
root["result"] = value;
Json::FastWriter writer;
return writer.write(root);
}
std::string resultInJson(int value)
{
Json::Value root;
root["result"] = value;
Json::FastWriter writer;
return writer.write(root);
}
std::string resultInJson(double value)
{
Json::Value root;
root["result"] = value;
Json::FastWriter writer;
return writer.write(root);
}
std::string resultDateInJson(const UDate& date)
{
UErrorCode status = U_ZERO_ERROR;
Calendar* cal = Calendar::createInstance(status);
if (!cal) {
return errorInJson(UNKNOWN_ERROR, "Failed to create Calendar instance!");
}
std::auto_ptr<Calendar> deleter(cal);
cal->setTime(date, status);
if (status != U_ZERO_ERROR && status != U_ERROR_WARNING_START) {
return errorInJson(UNKNOWN_ERROR, "Failed to set Calendar time!");
}
Json::Value result;
result["year"] = cal->get(UCAL_YEAR, status);
result["month"] = cal->get(UCAL_MONTH, status);
result["day"] = cal->get(UCAL_DAY_OF_MONTH, status);
result["hour"] = cal->get(UCAL_HOUR, status);
result["minute"] = cal->get(UCAL_MINUTE, status);
result["second"] = cal->get(UCAL_SECOND, status);
result["millisecond"] = cal->get(UCAL_MILLISECOND, status);
Json::Value root;
root["result"] = result;
Json::FastWriter writer;
return writer.write(root);
}
std::string resultInJson(const std::string& pattern, const std::string& timezone, int utc_offset, int dst_offset)
{
Json::Value result;
result["pattern"] = pattern;
result["timezone"] = timezone;
result["utc_offset"] = utc_offset;
result["dst_offset"] = dst_offset;
Json::Value root;
root["result"] = result;
Json::FastWriter writer;
return writer.write(root);
}
std::string resultInJson(const std::string& pattern, const std::string& symbol, int fraction,
double rounding, const std::string& positive, const std::string& negative,
const std::string& decimal, const std::string& grouping)
{
Json::Value result;
result["pattern"] = pattern;
result["symbol"] = symbol;
result["fraction"] = fraction;
result["rounding"] = rounding;
result["positive"] = positive;
result["negative"] = negative;
result["decimal"] = decimal;
result["grouping"] = grouping;
Json::Value root;
root["result"] = result;
Json::FastWriter writer;
return writer.write(root);
}
std::string resultInJson(const std::string& pattern, const std::string& code,
int fraction, double rounding,
const std::string& decimal, const std::string& grouping)
{
Json::Value result;
result["pattern"] = pattern;
result["code"] = code;
result["fraction"] = fraction;
result["rounding"] = rounding;
result["decimal"] = decimal;
result["grouping"] = grouping;
Json::Value root;
root["result"] = result;
Json::FastWriter writer;
return writer.write(root);
}
std::string resultInJson(const std::list<std::string>& names)
{
Json::Value result;
std::list<std::string>::const_iterator end = names.end();
std::list<std::string>::const_iterator iter = names.begin();
for (; iter != end; ++iter)
result.append(*iter);
Json::Value root;
root["result"] = result;
Json::FastWriter writer;
return writer.write(root);
}
GlobalizationNDK::GlobalizationNDK(GlobalizationJS *parent) {
m_pParent = parent;
}
GlobalizationNDK::~GlobalizationNDK() {
}
static int isspace_safe(int ch) {
return std::isspace(ch & 0xff);
}
static std::string& trimRight(std::string& str)
{
str.erase(std::find_if(str.rbegin(), str.rend(), std::not1(std::ptr_fun<int, int>(isspace_safe))).base(), str.end());
return str;
}
static std::string readLanguageFromPPS()
{
static const char* langfile = "/pps/services/confstr/_CS_LOCALE";
int fd = ::open(langfile, O_RDONLY);
if (fd < 0) {
return std::string();
}
static const int PPS_BUFFER_READ_SIZE = 2048;
char buffer[PPS_BUFFER_READ_SIZE];
ssize_t read = ::read(fd, buffer, PPS_BUFFER_READ_SIZE - 1);
::close(fd);
if (read <= 0) {
return std::string();
}
std::string content(buffer, read);
size_t pos = content.find_first_of("::");
if (pos == std::string::npos) {
return std::string();
}
std::string lang = content.substr(pos + 2);// 2 is strlen("::");
return trimRight(lang);
}
std::string GlobalizationNDK::getPreferredLanguage()
{
Locale loc = Locale::getDefault();
std::string ppslang = readLanguageFromPPS();
if (!ppslang.empty())
loc = Locale::createFromName(ppslang.c_str());
const char* lang = loc.getLanguage();
if (!lang || !strlen(lang)) {
lang = "en";
}
const char* country = loc.getCountry();
if (!country || !strlen(country)) {
country = "US";
}
return resultInJson(std::string(lang) + "-" + country);
}
std::string GlobalizationNDK::getLocaleName()
{
const Locale& loc = Locale::getDefault();
const char* lang = loc.getLanguage();
if (!lang) {
lang = "en";
}
const char* country = loc.getCountry();
if (!country) {
country = "US";
}
return resultInJson(std::string(lang) + "-" + country);
}
static bool handleDateOptions(const Json::Value& options, DateFormat::EStyle& dateStyle, DateFormat::EStyle& timeStyle, std::string& error)
{
// This is the default value when no options provided.
dateStyle = DateFormat::kShort;
timeStyle = DateFormat::kShort;
if (options.isNull())
return true;
if (!options.isObject()) {
error = "Options is invalid!";
return false;
}
Json::Value flv = options["formatLength"];
if (!flv.isNull()) {
if (!flv.isString()) {
error = "formatLength is invalid!";
return false;
}
std::string format = flv.asString();
if (format.empty()) {
error = "formatLength is empty!";
return false;
}
if (format == "full") {
dateStyle = DateFormat::kFull;
timeStyle = dateStyle;
} else if (format == "long") {
dateStyle = DateFormat::kLong;
timeStyle = dateStyle;
} else if (format == "medium") {
dateStyle = DateFormat::kMedium;
timeStyle = dateStyle;
} else if (format == "short") {
// Nothing to change here.
} else {
error = "Unsupported formatLength!";
return false;
}
}
Json::Value slv = options["selector"];
if (!slv.isNull()) {
if (!slv.isString()) {
error = "selector is invalid!";
return false;
}
std::string selector = slv.asString();
if (selector.empty()) {
error = "selector is empty!";
return false;
}
if (selector == "date")
timeStyle = DateFormat::kNone;
// Nothing to change here
else if (selector == "time")
dateStyle = DateFormat::kNone;
else if (selector == "date and time") {
// Nothing to do here.
} else {
error = "Unsupported selector!";
return false;
}
}
return true;
}
std::string GlobalizationNDK::dateToString(const std::string& args)
{
if (args.empty())
return errorInJson(PARSING_ERROR, "No date provided!");
Json::Reader reader;
Json::Value root;
bool parse = reader.parse(args, root);
if (!parse) {
return errorInJson(PARSING_ERROR, "Parameters not valid json format!");
}
Json::Value date = root["date"];
if (date.isNull()) {
return errorInJson(PARSING_ERROR, "No date provided!");
}
if (!date.isNumeric()) {
return errorInJson(PARSING_ERROR, "Date in wrong format!");
}
Json::Value options = root["options"];
DateFormat::EStyle dstyle, tstyle;
std::string error;
if (!handleDateOptions(options, dstyle, tstyle, error))
return errorInJson(PARSING_ERROR, error);
UErrorCode status = U_ZERO_ERROR;
const Locale& loc = Locale::getDefault();
DateFormat* df = DateFormat::createDateTimeInstance(dstyle, tstyle, loc);
if (!df) {
return errorInJson(UNKNOWN_ERROR, "Unable to create DateFormat instance!");
}
std::auto_ptr<DateFormat> deleter(df);
UnicodeString result;
df->format(date.asDouble(), result);
std::string utf8;
result.toUTF8String(utf8);
return resultInJson(utf8);
}
std::string GlobalizationNDK::stringToDate(const std::string& args)
{
if (args.empty())
return errorInJson(PARSING_ERROR, "No dateString provided!");
Json::Reader reader;
Json::Value root;
bool parse = reader.parse(args, root);
if (!parse) {
return errorInJson(PARSING_ERROR, "Parameters not valid json format!");
}
Json::Value dateString = root["dateString"];
if (!dateString.isString()) {
return errorInJson(PARSING_ERROR, "dateString not a string!");
}
std::string dateValue = dateString.asString();
if (dateValue.empty()) {
return errorInJson(PARSING_ERROR, "dateString is empty!");
}
Json::Value options = root["options"];
DateFormat::EStyle dstyle, tstyle;
std::string error;
if (!handleDateOptions(options, dstyle, tstyle, error))
return errorInJson(PARSING_ERROR, error);
const Locale& loc = Locale::getDefault();
DateFormat* df = DateFormat::createDateTimeInstance(dstyle, tstyle, loc);
if (!df) {
return errorInJson(UNKNOWN_ERROR, "Unable to create DateFormat instance!");
}
std::auto_ptr<DateFormat> deleter(df);
UnicodeString uDate = UnicodeString::fromUTF8(dateValue);
UErrorCode status = U_ZERO_ERROR;
UDate date = df->parse(uDate, status);
// Note: not sure why U_ERROR_WARNING_START is returned when parse succeeded.
if (status != U_ZERO_ERROR && status != U_ERROR_WARNING_START) {
return errorInJson(PARSING_ERROR, "Failed to parse dateString!");
}
return resultDateInJson(date);
}
std::string GlobalizationNDK::getDatePattern(const std::string& args)
{
DateFormat::EStyle dstyle = DateFormat::kShort, tstyle = DateFormat::kShort;
if (!args.empty()) {
Json::Reader reader;
Json::Value root;
bool parse = reader.parse(args, root);
if (!parse) {
return errorInJson(PARSING_ERROR, "Parameters not valid json format!");
}
Json::Value options = root["options"];
std::string error;
if (!handleDateOptions(options, dstyle, tstyle, error))
return errorInJson(PARSING_ERROR, error);
}
UErrorCode status = U_ZERO_ERROR;
const Locale& loc = Locale::getDefault();
DateFormat* df = DateFormat::createDateTimeInstance(dstyle, tstyle, loc);
if (!df) {
return errorInJson(UNKNOWN_ERROR, "Unable to create DateFormat instance!");
}
std::auto_ptr<DateFormat> deleter(df);
if (df->getDynamicClassID() != SimpleDateFormat::getStaticClassID()) {
return errorInJson(UNKNOWN_ERROR, "DateFormat instance not SimpleDateFormat!");
}
SimpleDateFormat* sdf = (SimpleDateFormat*) df;
UnicodeString pt;
sdf->toPattern(pt);
std::string ptUtf8;
pt.toUTF8String(ptUtf8);
const TimeZone& tz = sdf->getTimeZone();
UnicodeString tzName;
tz.getDisplayName(tzName);
std::string tzUtf8;
tzName.toUTF8String(tzUtf8);
int utc_offset = tz.getRawOffset() / 1000; // UTC_OFFSET in seconds.
int dst_offset = tz.getDSTSavings() / 1000; // DST_OFFSET in seconds;
return resultInJson(ptUtf8, tzUtf8, utc_offset, dst_offset);
}
enum ENamesType {
kNamesWide,
kNamesNarrow,
kNameWidthCount
};
enum ENamesItem {
kNamesMonths,
kNamesDays,
kNamesTypeCount
};
static bool handleNamesOptions(const Json::Value& options, ENamesType& type, ENamesItem& item, std::string& error)
{
// This is the default value when no options provided.
type = kNamesWide;
item = kNamesMonths;
if (options.isNull())
return true;
if (!options.isObject()) {
error = "Options is invalid!";
return false;
}
Json::Value tv = options["type"];
if (!tv.isNull()) {
if (!tv.isString()) {
error = "type is invalid!";
return false;
}
std::string tstr = tv.asString();
if (tstr.empty()) {
error = "type is empty!";
return false;
}
if (tstr == "narrow") {
type = kNamesNarrow;
} else if (tstr == "wide") {
// Nothing to change here.
} else {
error = "Unsupported type!";
return false;
}
}
Json::Value iv = options["item"];
if (!iv.isNull()) {
if (!iv.isString()) {
error = "item is invalid!";
return false;
}
std::string istr = iv.asString();
if (istr.empty()) {
error = "item is empty!";
return false;
}
if (istr == "days") {
item = kNamesDays;
} else if (istr == "months") {
// Nothing to change here.
} else {
error = "Unsupported item!";
return false;
}
}
return true;
}
std::string GlobalizationNDK::getDateNames(const std::string& args)
{
ENamesType type = kNamesWide;
ENamesItem item = kNamesMonths;
if (!args.empty()) {
Json::Reader reader;
Json::Value root;
bool parse = reader.parse(args, root);
if (!parse) {
return errorInJson(PARSING_ERROR, "Parameters not valid json format!");
}
Json::Value options = root["options"];
std::string error;
if (!handleNamesOptions(options, type, item, error))
return errorInJson(PARSING_ERROR, error);
}
int count;
const char* pattern;
DateFormat::EStyle dstyle;
// Check ICU SimpleDateFormat document for patterns for months and days.
// http://www.icu-project.org/apiref/icu4c/classicu_1_1SimpleDateFormat.html
if (item == kNamesMonths) {
count = 12;
if (type == kNamesWide) {
dstyle = DateFormat::kLong;
pattern = "MMMM";
} else {
dstyle = DateFormat::kShort;
pattern = "MMM";
}
} else {
count = 7;
if (type == kNamesWide) {
dstyle = DateFormat::kLong;
pattern = "eeee";
} else {
dstyle = DateFormat::kShort;
pattern = "eee";
}
}
UErrorCode status = U_ZERO_ERROR;
const Locale& loc = Locale::getDefault();
DateFormat* df = DateFormat::createDateInstance(dstyle, loc);
if (!df) {
return errorInJson(UNKNOWN_ERROR, "Unable to create DateFormat instance!");
}
std::auto_ptr<DateFormat> deleter(df);
if (df->getDynamicClassID() != SimpleDateFormat::getStaticClassID()) {
return errorInJson(UNKNOWN_ERROR, "DateFormat instance not SimpleDateFormat!");
}
SimpleDateFormat* sdf = (SimpleDateFormat*) df;
sdf->applyLocalizedPattern(UnicodeString(pattern, -1), status);
Calendar* cal = Calendar::createInstance(status);
if (!cal) {
return errorInJson(UNKNOWN_ERROR, "Unable to create Calendar instance!");
}
std::auto_ptr<Calendar> caldeleter(cal);
UCalendarDaysOfWeek ud = cal->getFirstDayOfWeek(status);
if (status != U_ZERO_ERROR && status != U_ERROR_WARNING_START) {
return errorInJson(PARSING_ERROR, "Failed to getFirstDayOfWeek!");
}
if (ud == UCAL_SUNDAY)
cal->set(2014, 0, 5);
else
cal->set(2014, 0, 6);
std::list<std::string> utf8Names;
for (int i = 0; i < count; ++i) {
UnicodeString ucs;
sdf->format(cal->getTime(status), ucs);
if (item == kNamesMonths)
cal->add(UCAL_MONTH, 1, status);
else
cal->add(UCAL_DAY_OF_MONTH, 1, status);
if (ucs.isEmpty())
continue;
std::string utf8;
ucs.toUTF8String(utf8);
utf8Names.push_back(utf8);
}
if (!utf8Names.size()) {
return errorInJson(UNKNOWN_ERROR, "Unable to get symbols!");
}
return resultInJson(utf8Names);
}
std::string GlobalizationNDK::isDayLightSavingsTime(const std::string& args)
{
if (args.empty()) {
return errorInJson(UNKNOWN_ERROR, "No date is provided!");
}
Json::Reader reader;
Json::Value root;
bool parse = reader.parse(args, root);
if (!parse) {
return errorInJson(PARSING_ERROR, "Parameters not valid json format!");
}
Json::Value dv = root["date"];
if (!dv.isNumeric()) {
return errorInJson(PARSING_ERROR, "Invalid date format!");
}
double date = dv.asDouble();
UErrorCode status = U_ZERO_ERROR;
SimpleDateFormat* sdf = new SimpleDateFormat(status);
if (!sdf) {
return errorInJson(UNKNOWN_ERROR, "Unable to create SimpleDateFormat instance!");
}
const TimeZone& tz = sdf->getTimeZone();
bool result = tz.inDaylightTime(date, status);
return resultInJson(result);
}
std::string GlobalizationNDK::getFirstDayOfWeek()
{
UErrorCode status = U_ZERO_ERROR;
Calendar* cal = Calendar::createInstance(status);
if (!cal) {
return errorInJson(UNKNOWN_ERROR, "Failed to create Calendar instance!");
}
UCalendarDaysOfWeek d = cal->getFirstDayOfWeek(status);
if (status != U_ZERO_ERROR && status != U_ERROR_WARNING_START) {
return errorInJson(UNKNOWN_ERROR, "Failed to call getFirstDayOfWeek!");
}
return resultInJson(d);
}
enum ENumberType {
kNumberDecimal,
kNumberCurrency,
kNumberPercent,
kNumberTypeCount
};
static bool handleNumberOptions(const Json::Value& options, ENumberType& type, std::string& error)
{
if (options.isNull())
return true;
if (!options.isObject()) {
error = "Invalid options type!";
return false;
}
Json::Value tv = options["type"];
if (tv.isNull()) {
error = "No type found!";
return false;
}
if (!tv.isString()) {
error = "Invalid type type!";
return false;
}
std::string tstr = tv.asString();
if (tstr.empty()) {
error = "Empty type!";
return false;
}
if (tstr == "currency") {
type = kNumberCurrency;
} else if (tstr == "percent") {
type = kNumberPercent;
} else if (tstr == "decimal") {
type = kNumberDecimal;
} else {
error = "Unsupported type!";
return false;
}
return true;
}
std::string GlobalizationNDK::numberToString(const std::string& args)
{
if (args.empty()) {
return errorInJson(UNKNOWN_ERROR, "No arguments provided!");
}
Json::Reader reader;
Json::Value root;
bool parse = reader.parse(args, root);
if (!parse) {
return errorInJson(PARSING_ERROR, "Invalid json data!");
}
Json::Value nv = root["number"];
if (nv.isNull()) {
return errorInJson(FORMATTING_ERROR, "No number provided!");
}
if (!nv.isNumeric()) {
return errorInJson(FORMATTING_ERROR, "Invalid number type!");
}
// This is the default value when no options provided.
ENumberType type = kNumberDecimal;
Json::Value options = root["options"];
std::string error;
if (!handleNumberOptions(options, type, error))
return errorInJson(PARSING_ERROR, error);
UErrorCode status = U_ZERO_ERROR;
NumberFormat* nf;
switch (type) {
case kNumberDecimal:
default:
nf = NumberFormat::createInstance(status);
break;
case kNumberCurrency:
nf = NumberFormat::createCurrencyInstance(status);
break;
case kNumberPercent:
nf = NumberFormat::createPercentInstance(status);
break;
}
if (!nf) {
return errorInJson(UNKNOWN_ERROR, "Failed to create NumberFormat instance!");
}
std::auto_ptr<NumberFormat> deleter(nf);
UnicodeString result;
nf->format(nv.asDouble(), result);
std::string utf8;
result.toUTF8String(utf8);
return resultInJson(utf8);
}
std::string GlobalizationNDK::stringToNumber(const std::string& args)
{
if (args.empty()) {
return errorInJson(PARSING_ERROR, "No arguments provided!");
}
Json::Reader reader;
Json::Value root;
bool parse = reader.parse(args, root);
if (!parse) {
return errorInJson(PARSING_ERROR, "Invalid json data!");
}
Json::Value sv = root["numberString"];
if (sv.isNull()) {
return errorInJson(FORMATTING_ERROR, "No numberString provided!");
}
if (!sv.isString()) {
return errorInJson(FORMATTING_ERROR, "Invalid numberString type!");
}
std::string str = sv.asString();
if (str.empty()) {
return errorInJson(FORMATTING_ERROR, "Empty numberString!");
}
// This is the default value when no options provided.
ENumberType type = kNumberDecimal;
Json::Value options = root["options"];
std::string error;
if (!handleNumberOptions(options, type, error))
return errorInJson(PARSING_ERROR, error);
UErrorCode status = U_ZERO_ERROR;
NumberFormat* nf;
switch (type) {
case kNumberDecimal:
default:
nf = NumberFormat::createInstance(status);
break;
case kNumberCurrency:
nf = NumberFormat::createCurrencyInstance(status);
break;
case kNumberPercent:
nf = NumberFormat::createPercentInstance(status);
break;
}
if (!nf) {
return errorInJson(UNKNOWN_ERROR, "Failed to create NumberFormat instance!");
}
std::auto_ptr<NumberFormat> deleter(nf);
UnicodeString uStr = UnicodeString::fromUTF8(str);
Formattable value;
if (type == kNumberCurrency) {
ParsePosition pos;
CurrencyAmount* ca = nf->parseCurrency(uStr, pos);
if (ca)
value = ca->getNumber();
else
nf->parse(uStr, value, status);
} else
nf->parse(uStr, value, status);
if (status != U_ZERO_ERROR && status != U_ERROR_WARNING_START) {
return errorInJson(PARSING_ERROR, "Failed to parse string!");
}
if (!value.isNumeric()) {
return errorInJson(FORMATTING_ERROR, "String is not numeric!");
}
return resultInJson(value.getDouble());
}
std::string GlobalizationNDK::getNumberPattern(const std::string& args)
{
// This is the default value when no options provided.
ENumberType type = kNumberDecimal;
if (!args.empty()) {
Json::Reader reader;
Json::Value root;
bool parse = reader.parse(args, root);
if (!parse) {
return errorInJson(PARSING_ERROR, "Invalid json data!");
}
Json::Value options = root["options"];
std::string error;
if (!handleNumberOptions(options, type, error))
return errorInJson(PARSING_ERROR, error);
}
std::string pattern, symbol, positive, negative, decimal, grouping;
int fraction;
double rounding;
UErrorCode status = U_ZERO_ERROR;
NumberFormat* nf;
switch (type) {
case kNumberDecimal:
default:
nf = NumberFormat::createInstance(status);
break;
case kNumberCurrency:
nf = NumberFormat::createCurrencyInstance(status);
break;
case kNumberPercent:
nf = NumberFormat::createPercentInstance(status);
break;
}
if (!nf) {
return errorInJson(UNKNOWN_ERROR, "Failed to create NumberFormat instance!");
}
std::auto_ptr<NumberFormat> deleter(nf);
if (nf->getDynamicClassID() != DecimalFormat::getStaticClassID()) {
return errorInJson(UNKNOWN_ERROR, "DecimalFormat expected!");
}
DecimalFormat* df = (DecimalFormat*) nf;
const DecimalFormatSymbols* dfs = df->getDecimalFormatSymbols();
if (!dfs) {
return errorInJson(UNKNOWN_ERROR, "Failed to get DecimalFormatSymbols instance!");
}
UnicodeString ucs;
df->toPattern(ucs);
ucs.toUTF8String(pattern);
ucs.remove();
df->getPositivePrefix(ucs);
if (ucs.isEmpty())
df->getPositiveSuffix(ucs);
ucs.toUTF8String(positive);
ucs.remove();
df->getNegativePrefix(ucs);
if (ucs.isEmpty())
df->getNegativeSuffix(ucs);
ucs.toUTF8String(negative);
ucs.remove();
rounding = df->getRoundingIncrement();
fraction = df->getMaximumFractionDigits();
ucs = dfs->getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
ucs.toUTF8String(decimal);
ucs.remove();
ucs = dfs->getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
ucs.toUTF8String(grouping);
ucs.remove();
if (type == kNumberPercent)
ucs = dfs->getSymbol(DecimalFormatSymbols::kPercentSymbol);
else if (type == kNumberCurrency)
ucs = dfs->getSymbol(DecimalFormatSymbols::kCurrencySymbol);
else
ucs = dfs->getSymbol(DecimalFormatSymbols::kDigitSymbol);
ucs.toUTF8String(symbol);
ucs.remove();
return resultInJson(pattern, symbol, fraction, rounding, positive, negative, decimal, grouping);
}
std::string GlobalizationNDK::getCurrencyPattern(const std::string& args)
{
if (args.empty()) {
return errorInJson(UNKNOWN_ERROR, "No arguments provided!");
}
Json::Reader reader;
Json::Value root;
bool parse = reader.parse(args, root);
if (!parse) {
return errorInJson(PARSING_ERROR, "Invalid json data!");
}
Json::Value ccv = root["currencyCode"];
if (ccv.isNull()) {
return errorInJson(FORMATTING_ERROR, "No currencyCode provided!");
}
if (!ccv.isString()) {
return errorInJson(FORMATTING_ERROR, "Invalid currencyCode type!");
}
std::string cc = ccv.asString();
if (cc.empty()) {
return errorInJson(FORMATTING_ERROR, "Empty currencyCode!");
}
UnicodeString ucc = UnicodeString::fromUTF8(cc);
DecimalFormat* df = 0;
int count = 0;
const Locale* locs = Locale::getAvailableLocales(count);
for (int i = 0; i < count; ++i) {
UErrorCode status = U_ZERO_ERROR;
NumberFormat* nf = NumberFormat::createCurrencyInstance(*(locs + i), status);
if (!nf) {
continue;
}
std::auto_ptr<NumberFormat> ndeleter(nf);
const UChar* currency = nf->getCurrency();
if (!currency) {
continue;
}
if (!ucc.compare(currency, -1)) {
df = (DecimalFormat*) ndeleter.release();
break;
}
}
if (!df)
return errorInJson(UNKNOWN_ERROR, "Currency not supported!");
std::auto_ptr<DecimalFormat> deleter(df);
const DecimalFormatSymbols* dfs = df->getDecimalFormatSymbols();
if (!dfs) {
return errorInJson(UNKNOWN_ERROR, "Failed to get DecimalFormatSymbols!");
}
UnicodeString ucs;
std::string pattern;
df->toPattern(ucs);
ucs.toUTF8String(pattern);
ucs.remove();
int fraction = df->getMaximumFractionDigits();
double rounding = df->getRoundingIncrement();
std::string decimal;
ucs = dfs->getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
ucs.toUTF8String(decimal);
ucs.remove();
std::string grouping;
ucs = dfs->getSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
ucs.toUTF8String(grouping);
ucs.remove();
return resultInJson(pattern, cc, fraction, rounding, decimal, grouping);
}
} /* namespace webworks */