mirror of
https://github.com/classilla/tenfourfox.git
synced 2025-01-12 20:30:18 +00:00
closes #502: CVE-2016-6293/7415 CVE-2017-7867/7868/14952/15422
This commit is contained in:
parent
8a97adc59a
commit
7af97d2dfd
@ -42,6 +42,7 @@
|
|||||||
#include "uhash.h"
|
#include "uhash.h"
|
||||||
#include "ucln_cmn.h"
|
#include "ucln_cmn.h"
|
||||||
#include "ustr_imp.h"
|
#include "ustr_imp.h"
|
||||||
|
#include "charstr.h"
|
||||||
|
|
||||||
U_CDECL_BEGIN
|
U_CDECL_BEGIN
|
||||||
static UBool U_CALLCONV locale_cleanup(void);
|
static UBool U_CALLCONV locale_cleanup(void);
|
||||||
@ -57,6 +58,12 @@ static UMutex gDefaultLocaleMutex = U_MUTEX_INITIALIZER;
|
|||||||
static UHashtable *gDefaultLocalesHashT = NULL;
|
static UHashtable *gDefaultLocalesHashT = NULL;
|
||||||
static Locale *gDefaultLocale = NULL;
|
static Locale *gDefaultLocale = NULL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def ULOC_STRING_LIMIT
|
||||||
|
* strings beyond this value crash in CharString
|
||||||
|
*/
|
||||||
|
#define ULOC_STRING_LIMIT 357913941
|
||||||
|
|
||||||
U_NAMESPACE_END
|
U_NAMESPACE_END
|
||||||
|
|
||||||
typedef enum ELocalePos {
|
typedef enum ELocalePos {
|
||||||
@ -283,13 +290,12 @@ Locale::Locale( const char * newLanguage,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MaybeStackArray<char, ULOC_FULLNAME_CAPACITY> togo;
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
int32_t size = 0;
|
int32_t size = 0;
|
||||||
int32_t lsize = 0;
|
int32_t lsize = 0;
|
||||||
int32_t csize = 0;
|
int32_t csize = 0;
|
||||||
int32_t vsize = 0;
|
int32_t vsize = 0;
|
||||||
int32_t ksize = 0;
|
int32_t ksize = 0;
|
||||||
char *p;
|
|
||||||
|
|
||||||
// Calculate the size of the resulting string.
|
// Calculate the size of the resulting string.
|
||||||
|
|
||||||
@ -297,13 +303,23 @@ Locale::Locale( const char * newLanguage,
|
|||||||
if ( newLanguage != NULL )
|
if ( newLanguage != NULL )
|
||||||
{
|
{
|
||||||
lsize = (int32_t)uprv_strlen(newLanguage);
|
lsize = (int32_t)uprv_strlen(newLanguage);
|
||||||
|
if ( lsize < 0 || lsize > ULOC_STRING_LIMIT ) { // int32 wrap
|
||||||
|
setToBogus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
size = lsize;
|
size = lsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CharString togo(newLanguage, lsize, status); // start with newLanguage
|
||||||
|
|
||||||
// _Country
|
// _Country
|
||||||
if ( newCountry != NULL )
|
if ( newCountry != NULL )
|
||||||
{
|
{
|
||||||
csize = (int32_t)uprv_strlen(newCountry);
|
csize = (int32_t)uprv_strlen(newCountry);
|
||||||
|
if ( csize < 0 || csize > ULOC_STRING_LIMIT ) { // int32 wrap
|
||||||
|
setToBogus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
size += csize;
|
size += csize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,6 +334,10 @@ Locale::Locale( const char * newLanguage,
|
|||||||
|
|
||||||
// remove trailing _'s
|
// remove trailing _'s
|
||||||
vsize = (int32_t)uprv_strlen(newVariant);
|
vsize = (int32_t)uprv_strlen(newVariant);
|
||||||
|
if ( vsize < 0 || vsize > ULOC_STRING_LIMIT ) { // int32 wrap
|
||||||
|
setToBogus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
while( (vsize>1) && (newVariant[vsize-1] == SEP_CHAR) )
|
while( (vsize>1) && (newVariant[vsize-1] == SEP_CHAR) )
|
||||||
{
|
{
|
||||||
vsize--;
|
vsize--;
|
||||||
@ -342,70 +362,56 @@ Locale::Locale( const char * newLanguage,
|
|||||||
if ( newKeywords != NULL)
|
if ( newKeywords != NULL)
|
||||||
{
|
{
|
||||||
ksize = (int32_t)uprv_strlen(newKeywords);
|
ksize = (int32_t)uprv_strlen(newKeywords);
|
||||||
|
if ( ksize < 0 || ksize > ULOC_STRING_LIMIT ) {
|
||||||
|
setToBogus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
size += ksize + 1;
|
size += ksize + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// NOW we have the full locale string..
|
// 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.
|
// Now, copy it back.
|
||||||
p = togo.getAlias();
|
|
||||||
if ( lsize != 0 )
|
// newLanguage is already copied
|
||||||
{
|
|
||||||
uprv_strcpy(p, newLanguage);
|
|
||||||
p += lsize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ( vsize != 0 ) || (csize != 0) ) // at least: __v
|
if ( ( vsize != 0 ) || (csize != 0) ) // at least: __v
|
||||||
{ // ^
|
{ // ^
|
||||||
*p++ = SEP_CHAR;
|
togo.append(SEP_CHAR, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( csize != 0 )
|
if ( csize != 0 )
|
||||||
{
|
{
|
||||||
uprv_strcpy(p, newCountry);
|
togo.append(newCountry, status);
|
||||||
p += csize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( vsize != 0)
|
if ( vsize != 0)
|
||||||
{
|
{
|
||||||
*p++ = SEP_CHAR; // at least: __v
|
togo.append(SEP_CHAR, status)
|
||||||
|
.append(newVariant, vsize, status);
|
||||||
uprv_strncpy(p, newVariant, vsize); // Must use strncpy because
|
|
||||||
p += vsize; // of trimming (above).
|
|
||||||
*p = 0; // terminate
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ksize != 0)
|
if ( ksize != 0)
|
||||||
{
|
{
|
||||||
if (uprv_strchr(newKeywords, '=')) {
|
if (uprv_strchr(newKeywords, '=')) {
|
||||||
*p++ = '@'; /* keyword parsing */
|
togo.append('@', status); /* keyword parsing */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
*p++ = '_'; /* Variant parsing with a script */
|
togo.append('_', status); /* Variant parsing with a script */
|
||||||
if ( vsize == 0) {
|
if ( vsize == 0) {
|
||||||
*p++ = '_'; /* No country found */
|
togo.append('_', status); /* No country found */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uprv_strcpy(p, newKeywords);
|
togo.append(newKeywords, status);
|
||||||
p += ksize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (U_FAILURE(status)) {
|
||||||
|
// Something went wrong with appending, etc.
|
||||||
|
setToBogus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
// Parse it, because for example 'language' might really be a complete
|
// Parse it, because for example 'language' might really be a complete
|
||||||
// string.
|
// string.
|
||||||
init(togo.getAlias(), FALSE);
|
init(togo.data(), FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2246,7 +2246,7 @@ _uloc_strtod(const char *start, char **end) {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
float q;
|
float q;
|
||||||
int32_t dummy; /* to avoid uninitialized memory copy from qsort */
|
int32_t dummy; /* to avoid uninitialized memory copy from qsort */
|
||||||
char *locale;
|
char locale[ULOC_FULLNAME_CAPACITY+1];
|
||||||
} _acceptLangItem;
|
} _acceptLangItem;
|
||||||
|
|
||||||
static int32_t U_CALLCONV
|
static int32_t U_CALLCONV
|
||||||
@ -2288,9 +2288,7 @@ uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult
|
|||||||
UEnumeration* availableLocales,
|
UEnumeration* availableLocales,
|
||||||
UErrorCode *status)
|
UErrorCode *status)
|
||||||
{
|
{
|
||||||
_acceptLangItem *j;
|
icu::MaybeStackArray<_acceptLangItem, 4> items; // Struct for collecting items.
|
||||||
_acceptLangItem smallBuffer[30];
|
|
||||||
char **strs;
|
|
||||||
char tmp[ULOC_FULLNAME_CAPACITY +1];
|
char tmp[ULOC_FULLNAME_CAPACITY +1];
|
||||||
int32_t n = 0;
|
int32_t n = 0;
|
||||||
const char *itemEnd;
|
const char *itemEnd;
|
||||||
@ -2300,11 +2298,7 @@ uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult
|
|||||||
int32_t res;
|
int32_t res;
|
||||||
int32_t i;
|
int32_t i;
|
||||||
int32_t l = (int32_t)uprv_strlen(httpAcceptLanguage);
|
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)) {
|
if(U_FAILURE(*status)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -2332,93 +2326,61 @@ uloc_acceptLanguageFromHTTP(char *result, int32_t resultAvailable, UAcceptResult
|
|||||||
while(isspace(*t)) {
|
while(isspace(*t)) {
|
||||||
t++;
|
t++;
|
||||||
}
|
}
|
||||||
j[n].q = (float)_uloc_strtod(t,NULL);
|
items[n].q = (float)_uloc_strtod(t,NULL);
|
||||||
} else {
|
} else {
|
||||||
/* no semicolon - it's 1.0 */
|
/* no semicolon - it's 1.0 */
|
||||||
j[n].q = 1.0f;
|
items[n].q = 1.0f;
|
||||||
paramEnd = itemEnd;
|
paramEnd = itemEnd;
|
||||||
}
|
}
|
||||||
j[n].dummy=0;
|
items[n].dummy=0;
|
||||||
/* eat spaces prior to semi */
|
/* eat spaces prior to semi */
|
||||||
for(t=(paramEnd-1);(paramEnd>s)&&isspace(*t);t--)
|
for(t=(paramEnd-1);(paramEnd>s)&&isspace(*t);t--)
|
||||||
;
|
;
|
||||||
/* Check for null pointer from uprv_strndup */
|
int32_t slen = ((t+1)-s);
|
||||||
tempstr = uprv_strndup(s,(int32_t)((t+1)-s));
|
if(slen > ULOC_FULLNAME_CAPACITY) {
|
||||||
if (tempstr == NULL) {
|
*status = U_BUFFER_OVERFLOW_ERROR;
|
||||||
*status = U_MEMORY_ALLOCATION_ERROR;
|
return -1; // too big
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
j[n].locale = tempstr;
|
uprv_strncpy(items[n].locale, s, slen);
|
||||||
uloc_canonicalize(j[n].locale,tmp,sizeof(tmp)/sizeof(tmp[0]),status);
|
items[n].locale[slen]=0; // terminate
|
||||||
if(strcmp(j[n].locale,tmp)) {
|
int32_t clen = uloc_canonicalize(items[n].locale, tmp, UPRV_LENGTHOF(tmp)-1, status);
|
||||||
uprv_free(j[n].locale);
|
if(U_FAILURE(*status)) return -1;
|
||||||
j[n].locale=uprv_strdup(tmp);
|
if((clen!=slen) || (uprv_strncmp(items[n].locale, tmp, slen))) {
|
||||||
|
// canonicalization had an effect- copy back
|
||||||
|
uprv_strncpy(items[n].locale, tmp, clen);
|
||||||
|
items[n].locale[clen] = 0; // terminate
|
||||||
}
|
}
|
||||||
#if defined(ULOC_DEBUG)
|
#if defined(ULOC_DEBUG)
|
||||||
/*fprintf(stderr,"%d: s <%s> q <%g>\n", n, j[n].locale, j[n].q);*/
|
/*fprintf(stderr,"%d: s <%s> q <%g>\n", n, items[n].locale, items[n].q);*/
|
||||||
#endif
|
#endif
|
||||||
n++;
|
n++;
|
||||||
s = itemEnd;
|
s = itemEnd;
|
||||||
while(*s==',') { /* eat duplicate commas */
|
while(*s==',') { /* eat duplicate commas */
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
if(n>=jSize) {
|
if(n>=items.getCapacity()) { // If we need more items
|
||||||
if(j==smallBuffer) { /* overflowed the small buffer. */
|
if(NULL == items.resize(items.getCapacity()*2, items.getCapacity())) {
|
||||||
j = static_cast<_acceptLangItem *>(uprv_malloc(sizeof(j[0])*(jSize*2)));
|
*status = U_MEMORY_ALLOCATION_ERROR;
|
||||||
if(j!=NULL) {
|
return -1;
|
||||||
uprv_memcpy(j,smallBuffer,sizeof(j[0])*jSize);
|
}
|
||||||
}
|
|
||||||
#if defined(ULOC_DEBUG)
|
#if defined(ULOC_DEBUG)
|
||||||
fprintf(stderr,"malloced at size %d\n", jSize);
|
fprintf(stderr,"malloced at size %d\n", items.getCapacity());
|
||||||
#endif
|
#endif
|
||||||
} else {
|
|
||||||
j = static_cast<_acceptLangItem *>(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);
|
uprv_sortArray(items.getAlias(), n, sizeof(items[0]), uloc_acceptLanguageCompare, NULL, TRUE, status);
|
||||||
|
icu::LocalArray<const char*> strs(new const char*[n], *status);
|
||||||
if(U_FAILURE(*status)) {
|
if(U_FAILURE(*status)) {
|
||||||
if(j != smallBuffer) {
|
return -1;
|
||||||
#if defined(ULOC_DEBUG)
|
|
||||||
fprintf(stderr,"freeing j %p\n", j);
|
|
||||||
#endif
|
|
||||||
uprv_free(j);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
strs = static_cast<char **>(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++) {
|
for(i=0;i<n;i++) {
|
||||||
#if defined(ULOC_DEBUG)
|
#if defined(ULOC_DEBUG)
|
||||||
/*fprintf(stderr,"%d: s <%s> q <%g>\n", i, j[i].locale, j[i].q);*/
|
/*fprintf(stderr,"%d: s <%s> q <%g>\n", i, items[i].locale, items[i].q);*/
|
||||||
#endif
|
#endif
|
||||||
strs[i]=j[i].locale;
|
strs[i]=items[i].locale;
|
||||||
}
|
}
|
||||||
res = uloc_acceptLanguage(result, resultAvailable, outResult,
|
res = uloc_acceptLanguage(result, resultAvailable, outResult,
|
||||||
(const char**)strs, n, availableLocales, status);
|
strs.getAlias(), 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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -845,11 +845,18 @@ U_CDECL_END
|
|||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Chunk size.
|
// Chunk size.
|
||||||
// Must be less than 85, because of byte mapping from UChar indexes to native indexes.
|
// Must be less than 42 (256/6), because of byte mapping from UChar indexes to native indexes.
|
||||||
// Worst case is three native bytes to one UChar. (Supplemenaries are 4 native bytes
|
// Worst case there are six UTF-8 bytes per UChar.
|
||||||
// to two UChars.)
|
// obsolete 6 byte form fd + 5 trails maps to fffd
|
||||||
|
// obsolete 5 byte form fc + 4 trails maps to fffd
|
||||||
|
// non-shortest 4 byte forms maps to fffd
|
||||||
|
// normal supplementaries map to a pair of utf-16, two utf8 bytes per utf-16 unit
|
||||||
|
// mapToUChars array size must allow for the worst case, 6.
|
||||||
|
// This could be brought down to 4, by treating fd and fc as pure illegal,
|
||||||
|
// rather than obsolete lead bytes. But that is not compatible with the utf-8 access macros.
|
||||||
//
|
//
|
||||||
enum { UTF8_TEXT_CHUNK_SIZE=32 };
|
enum { UTF8_TEXT_CHUNK_SIZE=32 };
|
||||||
|
enum { SIZEOF_MAPTOUCHARS=UTF8_TEXT_CHUNK_SIZE*6+6 };
|
||||||
|
|
||||||
//
|
//
|
||||||
// UTF8Buf Two of these structs will be set up in the UText's extra allocated space.
|
// UTF8Buf Two of these structs will be set up in the UText's extra allocated space.
|
||||||
@ -887,7 +894,7 @@ struct UTF8Buf {
|
|||||||
// Requires two extra slots,
|
// Requires two extra slots,
|
||||||
// one for a supplementary starting in the last normal position,
|
// one for a supplementary starting in the last normal position,
|
||||||
// and one for an entry for the buffer limit 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
|
uint8_t mapToUChars[SIZEOF_MAPTOUCHARS]; // Map native offset from bufNativeStart to
|
||||||
// correspoding offset in filled part of buf.
|
// correspoding offset in filled part of buf.
|
||||||
int32_t align;
|
int32_t align;
|
||||||
};
|
};
|
||||||
@ -1030,6 +1037,7 @@ utf8TextAccess(UText *ut, int64_t index, UBool forward) {
|
|||||||
// Requested index is in this buffer.
|
// Requested index is in this buffer.
|
||||||
u8b = (UTF8Buf *)ut->p; // the current buffer
|
u8b = (UTF8Buf *)ut->p; // the current buffer
|
||||||
mapIndex = ix - u8b->toUCharsMapStart;
|
mapIndex = ix - u8b->toUCharsMapStart;
|
||||||
|
U_ASSERT(mapIndex < (int32_t)SIZEOF_MAPTOUCHARS);
|
||||||
ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
|
ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
@ -1296,6 +1304,10 @@ fillReverse:
|
|||||||
// Can only do this if the incoming index is somewhere in the interior of the string.
|
// 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 index is at the end, there is no character there to look at.
|
||||||
if (ix != ut->b) {
|
if (ix != ut->b) {
|
||||||
|
// Note: this function will only move the index back if it is on a trail byte
|
||||||
|
// and there is a preceding lead byte and the sequence from the lead
|
||||||
|
// through this trail could be part of a valid UTF-8 sequence
|
||||||
|
// Otherwise the index remains unchanged.
|
||||||
U8_SET_CP_START(s8, 0, ix);
|
U8_SET_CP_START(s8, 0, ix);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1309,7 +1321,10 @@ fillReverse:
|
|||||||
UChar *buf = u8b->buf;
|
UChar *buf = u8b->buf;
|
||||||
uint8_t *mapToNative = u8b->mapToNative;
|
uint8_t *mapToNative = u8b->mapToNative;
|
||||||
uint8_t *mapToUChars = u8b->mapToUChars;
|
uint8_t *mapToUChars = u8b->mapToUChars;
|
||||||
int32_t toUCharsMapStart = ix - (UTF8_TEXT_CHUNK_SIZE*3 + 1);
|
int32_t toUCharsMapStart = ix - SIZEOF_MAPTOUCHARS + 1;
|
||||||
|
// Note that toUCharsMapStart can be negative. Happens when the remaining
|
||||||
|
// text from current position to the beginning is less than the buffer size.
|
||||||
|
// + 1 because mapToUChars must have a slot at the end for the bufNativeLimit entry.
|
||||||
int32_t destIx = UTF8_TEXT_CHUNK_SIZE+2; // Start in the overflow region
|
int32_t destIx = UTF8_TEXT_CHUNK_SIZE+2; // Start in the overflow region
|
||||||
// at end of buffer to leave room
|
// at end of buffer to leave room
|
||||||
// for a surrogate pair at the
|
// for a surrogate pair at the
|
||||||
@ -1336,6 +1351,7 @@ fillReverse:
|
|||||||
if (c<0x80) {
|
if (c<0x80) {
|
||||||
// Special case ASCII range for speed.
|
// Special case ASCII range for speed.
|
||||||
buf[destIx] = (UChar)c;
|
buf[destIx] = (UChar)c;
|
||||||
|
U_ASSERT(toUCharsMapStart <= srcIx);
|
||||||
mapToUChars[srcIx - toUCharsMapStart] = (uint8_t)destIx;
|
mapToUChars[srcIx - toUCharsMapStart] = (uint8_t)destIx;
|
||||||
mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart);
|
mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart);
|
||||||
} else {
|
} else {
|
||||||
@ -1365,6 +1381,7 @@ fillReverse:
|
|||||||
do {
|
do {
|
||||||
mapToUChars[sIx-- - toUCharsMapStart] = (uint8_t)destIx;
|
mapToUChars[sIx-- - toUCharsMapStart] = (uint8_t)destIx;
|
||||||
} while (sIx >= srcIx);
|
} while (sIx >= srcIx);
|
||||||
|
U_ASSERT(toUCharsMapStart <= (srcIx+1));
|
||||||
|
|
||||||
// Set native indexing limit to be the current position.
|
// Set native indexing limit to be the current position.
|
||||||
// We are processing a non-ascii, non-native-indexing char now;
|
// We are processing a non-ascii, non-native-indexing char now;
|
||||||
@ -1539,6 +1556,7 @@ utf8TextMapIndexToUTF16(const UText *ut, int64_t index64) {
|
|||||||
U_ASSERT(index>=ut->chunkNativeStart+ut->nativeIndexingLimit);
|
U_ASSERT(index>=ut->chunkNativeStart+ut->nativeIndexingLimit);
|
||||||
U_ASSERT(index<=ut->chunkNativeLimit);
|
U_ASSERT(index<=ut->chunkNativeLimit);
|
||||||
int32_t mapIndex = index - u8b->toUCharsMapStart;
|
int32_t mapIndex = index - u8b->toUCharsMapStart;
|
||||||
|
U_ASSERT(mapIndex < (int32_t)SIZEOF_MAPTOUCHARS);
|
||||||
int32_t offset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
|
int32_t offset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
|
||||||
U_ASSERT(offset>=0 && offset<=ut->chunkLength);
|
U_ASSERT(offset>=0 && offset<=ut->chunkLength);
|
||||||
return offset;
|
return offset;
|
||||||
|
@ -29,6 +29,11 @@ int32_t ClockMath::floorDivide(int32_t numerator, int32_t denominator) {
|
|||||||
numerator / denominator : ((numerator + 1) / denominator) - 1;
|
numerator / denominator : ((numerator + 1) / denominator) - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t ClockMath::floorDivide(int64_t numerator, int64_t denominator) {
|
||||||
|
return (numerator >= 0) ?
|
||||||
|
numerator / denominator : ((numerator + 1) / denominator) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t ClockMath::floorDivide(double numerator, int32_t denominator,
|
int32_t ClockMath::floorDivide(double numerator, int32_t denominator,
|
||||||
int32_t& remainder) {
|
int32_t& remainder) {
|
||||||
double quotient;
|
double quotient;
|
||||||
|
@ -38,6 +38,17 @@ class ClockMath {
|
|||||||
*/
|
*/
|
||||||
static int32_t floorDivide(int32_t numerator, int32_t denominator);
|
static int32_t floorDivide(int32_t numerator, int32_t denominator);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 int64_t floorDivide(int64_t numerator, int64_t denominator);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Divide two numbers, returning the floor of the quotient.
|
* Divide two numbers, returning the floor of the quotient.
|
||||||
* Unlike the built-in division, this is mathematically
|
* Unlike the built-in division, this is mathematically
|
||||||
|
@ -211,7 +211,7 @@ void PersianCalendar::handleComputeFields(int32_t julianDay, UErrorCode &/*statu
|
|||||||
int32_t year, month, dayOfMonth, dayOfYear;
|
int32_t year, month, dayOfMonth, dayOfYear;
|
||||||
|
|
||||||
int32_t daysSinceEpoch = julianDay - PERSIAN_EPOCH;
|
int32_t daysSinceEpoch = julianDay - PERSIAN_EPOCH;
|
||||||
year = 1 + ClockMath::floorDivide(33 * daysSinceEpoch + 3, 12053);
|
year = 1 + (int32_t)ClockMath::floorDivide(33 * (int64_t)daysSinceEpoch + 3, (int64_t)12053);
|
||||||
|
|
||||||
int32_t farvardin1 = 365 * (year - 1) + ClockMath::floorDivide(8 * year + 21, 33);
|
int32_t farvardin1 = 365 * (year - 1) + ClockMath::floorDivide(8 * year + 21, 33);
|
||||||
dayOfYear = (daysSinceEpoch - farvardin1); // 0-based
|
dayOfYear = (daysSinceEpoch - farvardin1); // 0-based
|
||||||
|
@ -681,7 +681,6 @@ ZoneMeta::createMetazoneMappings(const UnicodeString &tzid) {
|
|||||||
mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status);
|
mzMappings = new UVector(deleteOlsonToMetaMappingEntry, NULL, status);
|
||||||
if (U_FAILURE(status)) {
|
if (U_FAILURE(status)) {
|
||||||
delete mzMappings;
|
delete mzMappings;
|
||||||
deleteOlsonToMetaMappingEntry(entry);
|
|
||||||
uprv_free(entry);
|
uprv_free(entry);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user