Merge branch 'master' of github.com:gnustep/libs-base into NSSecureCoding_branch

This commit is contained in:
Gregory John Casamento 2020-05-04 05:50:58 -04:00
commit 76fac00cd2
10 changed files with 598 additions and 335 deletions

3
.gitignore vendored
View file

@ -26,6 +26,9 @@ Tests/base/coding/ulong-8.type
*.orig
*.swp
# MacOS Desktop Services Store
.DS_Store
# Created by https://www.gitignore.io/api/xcode
# Edit at https://www.gitignore.io/?templates=xcode

View file

@ -1,3 +1,13 @@
2020-04-26 Fred Kiefer <fredkiefer@gmx.de>
* Source/NSLocale.m: Respect NSLocaleCalendarIdentifier if
NSLocaleCalendar isn't set.
* Headers/Foundation/NSCalendar.h,
* Source/NSCalendar.m: Add newer features for NSDateComponents and
started to clean up NSCalendar implementation.
* Tests/base/NSCalendar/features-10-7.m: Add test for different
time zone.
2020-04-21 Richard Frith-Macdonald <rfm@gnu.org>
* Source/NSNotification.m:

View file

@ -129,7 +129,7 @@ enum
NSCalendarUnitWeekOfMonth = (1UL << 12),
NSCalendarUnitWeekOfYear = (1UL << 13),
NSCalendarUnitYearForWeekOfYear = (1UL << 14),
NSCalendarUnitNanosecond = (1 << 15), // FIXME: unimplemented
NSCalendarUnitNanosecond = (1 << 15),
NSCalendarUnitCalendar = (1 << 20), // FIXME: unimplemented
NSCalendarUnitTimeZone = (1 << 21) // FIXME: unimplemented
#endif
@ -227,6 +227,7 @@ enum
* yearForWeekOfYear is 2013, since it's already week 1 in 2013.
*/
- (NSInteger) yearForWeekOfYear;
- (NSInteger) nanosecond;
/** Sets the number of the week in this month. */
- (void) setWeekOfMonth: (NSInteger) v;
@ -241,8 +242,22 @@ enum
* See the explanation at <code>-yearForWeekOfYear</code>.
*/
- (void) setYearForWeekOfYear: (NSInteger) v;
- (void) setNanosecond: (NSInteger) v;
#endif
#if OS_API_VERSION(MAC_OS_X_VERSION_10_8, GS_API_LATEST)
- (BOOL) leapMonth;
- (void) setLeapMonth: (BOOL) v;
#endif
#if OS_API_VERSION(MAC_OS_X_VERSION_10_9, GS_API_LATEST)
- (BOOL) isValidDate;
- (BOOL) isValidDateInCalendar: (NSCalendar *) calendar;
- (NSInteger) valueForComponent: (NSCalendarUnit) unit;
- (void) setValue: (NSInteger) value
forComponent: (NSCalendarUnit) unit;
#endif
@end

View file

@ -46,31 +46,26 @@
#if GS_USE_ICU == 1
static UCalendarDateFields _NSCalendarUnitToDateField (NSCalendarUnit unit)
{
// I'm just going to go in the order they appear in Apple's documentation
if (unit & NSEraCalendarUnit)
if (unit & NSCalendarUnitEra)
return UCAL_ERA;
if (unit & NSYearCalendarUnit)
if (unit & NSCalendarUnitYear)
return UCAL_YEAR;
if (unit & NSMonthCalendarUnit)
if (unit & NSCalendarUnitMonth)
return UCAL_MONTH;
if (unit & NSDayCalendarUnit)
if (unit & NSCalendarUnitDay)
return UCAL_DAY_OF_MONTH;
if (unit & NSHourCalendarUnit)
if (unit & NSCalendarUnitHour)
return UCAL_HOUR_OF_DAY;
if (unit & NSMinuteCalendarUnit)
if (unit & NSCalendarUnitMinute)
return UCAL_MINUTE;
if (unit & NSSecondCalendarUnit)
if (unit & NSCalendarUnitSecond)
return UCAL_SECOND;
if (unit & NSWeekCalendarUnit)
if (unit & NSCalendarUnitWeekOfYear)
return UCAL_WEEK_OF_YEAR;
if (unit & NSWeekdayCalendarUnit)
if (unit & NSCalendarUnitWeekday)
return UCAL_DAY_OF_WEEK;
if (unit & NSWeekdayOrdinalCalendarUnit)
// FIXME: Is this right???
if (unit & NSCalendarUnitWeekdayOrdinal)
return UCAL_DAY_OF_WEEK_IN_MONTH;
// ICU doesn't include a quarter DateField...
if (unit & NSQuarterCalendarUnit)
return (UCAL_MONTH + 2) / 3;
return -1;
}
#endif /* GS_USE_ICU */
@ -84,47 +79,76 @@ typedef struct {
NSInteger minimumDaysInFirstWeek;
} Calendar;
#define my ((Calendar*)_NSCalendarInternal)
#define aac ((Calendar*)(autoupdatingCalendar->_NSCalendarInternal))
@interface NSCalendar (PrivateMethods)
- (void *) _openCalendarFor: (NSTimeZone *)timeZone;
- (void) _resetCalendar;
- (void *) _UCalendar;
- (NSString *) _localeIDWithLocale: (NSLocale*)locale;
- (NSString *) _localeIDentifier;
- (NSString *) _localeIdentifier;
- (void) _setLocaleIdentifier: (NSString*)identifier;
@end
static NSCalendar *autoupdatingCalendar = nil;
static NSRecursiveLock *classLock = nil;
#define TZ_NAME_LENGTH 1024
#define SECOND_TO_MILLI 1000.0
#define MILLI_TO_NANO 1000000
@implementation NSCalendar (PrivateMethods)
- (void) _resetCalendar
{
#if GS_USE_ICU == 1
- (void *) _openCalendarFor: (NSTimeZone *)timeZone
{
NSString *tzName;
NSUInteger tzLen;
unichar cTzId[TZ_NAME_LENGTH];
const char *cLocaleId;
UErrorCode err = U_ZERO_ERROR;
if (my->cal != NULL)
ucal_close (my->cal);
UCalendarType type;
cLocaleId = [my->localeID UTF8String];
tzName = [my->tz name];
tzName = [timeZone name];
tzLen = [tzName length];
if (tzLen > TZ_NAME_LENGTH)
{
tzLen = TZ_NAME_LENGTH;
}
[tzName getCharacters: cTzId range: NSMakeRange(0, tzLen)];
if ([NSGregorianCalendar isEqualToString: my->identifier])
{
type = UCAL_GREGORIAN;
}
else
{
#ifndef UCAL_DEFAULT
/*
* Older versions of ICU used UCAL_TRADITIONAL rather than UCAL_DEFAULT
* so if one is not available we use the other.
*/
#define UCAL_DEFAULT UCAL_TRADITIONAL
type = UCAL_TRADITIONAL;
#else
type = UCAL_DEFAULT;
#endif
my->cal =
ucal_open ((const UChar *)cTzId, tzLen, cLocaleId, UCAL_DEFAULT, &err);
// We do not need to call uloc_setKeywordValue() here to set the calendar on the locale
// as the calendar is already encoded in the locale id by _localeIDWithLocale:.
}
return ucal_open((const UChar *)cTzId, tzLen, cLocaleId, type, &err);
}
#endif
- (void) _resetCalendar
{
#if GS_USE_ICU == 1
if (my->cal != NULL)
{
ucal_close(my->cal);
}
my->cal = [self _openCalendarFor: my->tz];
if (NSNotFound == my->firstWeekday)
{
@ -147,7 +171,6 @@ typedef struct {
ucal_setAttribute(my->cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK,
(int32_t)my->minimumDaysInFirstWeek);
}
#endif
}
@ -163,16 +186,24 @@ typedef struct {
NSMutableDictionary *tmpDict;
localeId = [locale localeIdentifier];
if (my->identifier)
{
tmpDict = [[NSLocale componentsFromLocaleIdentifier: localeId]
mutableCopyWithZone: NULL];
[tmpDict removeObjectForKey: NSLocaleCalendar];
[tmpDict setObject: my->identifier forKey: NSLocaleCalendarIdentifier];
result = [NSLocale localeIdentifierFromComponents: tmpDict];
RELEASE(tmpDict);
}
else
{
result = localeId;
}
return result;
}
- (NSString*) _localeIDentifier
- (NSString*) _localeIdentifier
{
return my->localeID;
}
@ -180,26 +211,15 @@ typedef struct {
- (void) _setLocaleIdentifier: (NSString *) identifier
{
if ([identifier isEqualToString: my->localeID])
{
return;
}
RELEASE(my->localeID);
my->localeID = RETAIN(identifier);
ASSIGN(my->localeID, identifier);
[self _resetCalendar];
}
@end
@implementation NSCalendar
static NSCalendar *autoupdatingCalendar = nil;
static NSRecursiveLock *classLock = nil;
+ (void) initialize
{
if (self == [NSLocale class])
classLock = [NSRecursiveLock new];
}
+ (void) defaultsDidChange: (NSNotification*)n
- (void) _defaultsDidChange: (NSNotification*)n
{
NSUserDefaults *defs;
NSString *locale;
@ -211,105 +231,87 @@ static NSRecursiveLock *classLock = nil;
calendar = [defs stringForKey: @"Calendar"];
tz = [defs stringForKey: @"Local Time Zone"];
if ([locale isEqual: aac->localeID] == NO
|| [calendar isEqual: aac->identifier] == NO
|| [tz isEqual: [(aac->tz) name]] == NO)
{
[classLock lock];
RELEASE(aac->localeID);
RELEASE(aac->identifier);
RELEASE(aac->tz);
if ([locale isEqual: my->localeID] == NO
|| [calendar isEqual: my->identifier] == NO
|| [tz isEqual: [my->tz name]] == NO)
{
#if GS_USE_ICU == 1
ucal_close(aac->cal);
ucal_close(my->cal);
#endif
aac->localeID = RETAIN(locale);
aac->identifier = RETAIN(calendar);
aac->tz = [[NSTimeZone alloc] initWithName: tz];
ASSIGN(my->localeID, locale);
ASSIGN(my->identifier, calendar);
RELEASE(my->tz);
my->tz = [[NSTimeZone alloc] initWithName: tz];
[autoupdatingCalendar _resetCalendar];
[self _resetCalendar];
}
[classLock unlock];
}
@end
@implementation NSCalendar
+ (void) initialize
{
if (self == [NSCalendar class])
{
classLock = [NSRecursiveLock new];
}
}
+ (id) currentCalendar
{
NSCalendar *result;
NSLocale *locale;
NSCalendar *cal;
NSString *identifier;
locale = [NSLocale currentLocale];
cal = [locale objectForKey: NSLocaleCalendar];
result =
[[NSCalendar alloc] initWithCalendarIdentifier: [cal calendarIdentifier]];
// This identifier may be nil
identifier = [[NSLocale currentLocale] objectForKey: NSLocaleCalendarIdentifier];
result = [[NSCalendar alloc] initWithCalendarIdentifier: identifier];
return AUTORELEASE(result);
}
+ (id) autoupdatingCurrentCalendar
{
[classLock lock];
if (nil == autoupdatingCalendar)
{
autoupdatingCalendar = [[self currentCalendar] copy];
[[NSNotificationCenter defaultCenter]
addObserver: autoupdatingCalendar
selector: @selector(_defaultsDidChange:)
name: NSUserDefaultsDidChangeNotification
object: nil];
}
[classLock unlock];
return autoupdatingCalendar;
}
+ (id) calendarWithIdentifier: (NSString *) identifier
{
return AUTORELEASE([[self alloc] initWithCalendarIdentifier: identifier]);
}
- (id) init
{
self = [self initWithCalendarIdentifier: nil];
return self;
return [self initWithCalendarIdentifier: nil];
}
+ (id) calendarWithIdentifier: (NSString *) string
{
return [[[self alloc] initWithCalendarIdentifier: string] autorelease];
}
- (id) initWithCalendarIdentifier: (NSString *) string
- (id) initWithCalendarIdentifier: (NSString *) identifier
{
NSAssert(0 == _NSCalendarInternal, NSInvalidArgumentException);
_NSCalendarInternal =
NSZoneCalloc([self zone], sizeof(Calendar), 1);
_NSCalendarInternal = NSZoneCalloc([self zone], sizeof(Calendar), 1);
my->firstWeekday = NSNotFound;
my->minimumDaysInFirstWeek = NSNotFound;
ASSIGN(my->identifier, identifier);
ASSIGN(my->tz, [NSTimeZone defaultTimeZone]);
[self setLocale: [NSLocale currentLocale]];
if ([string isEqualToString: NSGregorianCalendar])
my->identifier = NSGregorianCalendar;
else if ([string isEqualToString: NSBuddhistCalendar])
my->identifier = NSBuddhistCalendar;
else if ([string isEqualToString: NSChineseCalendar])
my->identifier = NSChineseCalendar;
else if ([string isEqualToString: NSHebrewCalendar])
my->identifier = NSHebrewCalendar;
else if ([string isEqualToString: NSIslamicCalendar])
my->identifier = NSIslamicCalendar;
else if ([string isEqualToString: NSIslamicCivilCalendar])
my->identifier = NSIslamicCivilCalendar;
else if ([string isEqualToString: NSJapaneseCalendar])
my->identifier = NSJapaneseCalendar;
else if ([string isEqualToString: NSRepublicOfChinaCalendar])
my->identifier = NSRepublicOfChinaCalendar;
else if ([string isEqualToString: NSPersianCalendar])
my->identifier = NSPersianCalendar;
else if ([string isEqualToString: NSIndianCalendar])
my->identifier = NSIndianCalendar;
else if ([string isEqualToString: NSISO8601Calendar])
my->identifier = NSISO8601Calendar;
else if ([string isEqualToString: NSCalendarIdentifierCoptic])
my->identifier = NSGregorianCalendar; // TODO: unimplemented
else if ([string isEqualToString: NSCalendarIdentifierEthiopicAmeteMihret])
my->identifier = NSGregorianCalendar; // TODO: unimplemented
else if ([string isEqualToString: NSCalendarIdentifierEthiopicAmeteAlem])
my->identifier = NSGregorianCalendar; // TODO: unimplemented
else if ([string isEqualToString: NSCalendarIdentifierIslamicTabular])
my->identifier = NSGregorianCalendar; // TODO: unimplemented
else if ([string isEqualToString: NSCalendarIdentifierIslamicUmmAlQura])
my->identifier = NSGregorianCalendar; // TODO: unimplemented
else
{
RELEASE(self);
return nil;
}
// It's much easier to keep a copy of the NSLocale's string representation
// than to have to build it everytime we have to open a UCalendar.
my->localeID = RETAIN([self _localeIDWithLocale: [NSLocale currentLocale]]);
my->tz = RETAIN([NSTimeZone defaultTimeZone]);
[self _resetCalendar];
return self;
}
@ -342,37 +344,71 @@ static NSRecursiveLock *classLock = nil;
UErrorCode err = U_ZERO_ERROR;
UDate udate;
udate = (UDate)floor([date timeIntervalSince1970] * 1000.0);
ucal_setMillis (my->cal, udate, &err);
udate = (UDate)floor([date timeIntervalSince1970] * SECOND_TO_MILLI);
ucal_setMillis(my->cal, udate, &err);
if (U_FAILURE(err))
{
return nil;
}
comps = [[NSDateComponents alloc] init];
if (unitFlags & NSEraCalendarUnit)
if (unitFlags & NSCalendarUnitEra)
{
[comps setEra: ucal_get(my->cal, UCAL_ERA, &err)];
if (unitFlags & NSYearCalendarUnit)
}
if (unitFlags & NSCalendarUnitYear)
{
[comps setYear: ucal_get(my->cal, UCAL_YEAR, &err)];
if (unitFlags & NSMonthCalendarUnit)
[comps setMonth: ucal_get(my->cal, UCAL_MONTH, &err)+1];
if (unitFlags & NSDayCalendarUnit)
}
if (unitFlags & NSCalendarUnitMonth)
{
[comps setMonth: ucal_get(my->cal, UCAL_MONTH, &err) + 1];
}
if (unitFlags & NSCalendarUnitDay)
{
[comps setDay: ucal_get(my->cal, UCAL_DAY_OF_MONTH, &err)];
if (unitFlags & NSHourCalendarUnit)
}
if (unitFlags & NSCalendarUnitHour)
{
[comps setHour: ucal_get(my->cal, UCAL_HOUR_OF_DAY, &err)];
if (unitFlags & NSMinuteCalendarUnit)
}
if (unitFlags & NSCalendarUnitMinute)
{
[comps setMinute: ucal_get(my->cal, UCAL_MINUTE, &err)];
if (unitFlags & NSSecondCalendarUnit)
}
if (unitFlags & NSCalendarUnitSecond)
{
[comps setSecond: ucal_get(my->cal, UCAL_SECOND, &err)];
if (unitFlags & (NSWeekCalendarUnit|NSWeekOfYearCalendarUnit))
}
if (unitFlags & (NSWeekCalendarUnit | NSCalendarUnitWeekOfYear))
{
[comps setWeek: ucal_get(my->cal, UCAL_WEEK_OF_YEAR, &err)];
if (unitFlags & NSWeekdayCalendarUnit)
}
if (unitFlags & NSCalendarUnitWeekday)
{
[comps setWeekday: ucal_get(my->cal, UCAL_DAY_OF_WEEK, &err)];
if (unitFlags & NSWeekdayOrdinalCalendarUnit)
}
if (unitFlags & NSCalendarUnitWeekdayOrdinal)
{
[comps setWeekdayOrdinal:
ucal_get(my->cal, UCAL_DAY_OF_WEEK_IN_MONTH, &err)];
if (unitFlags & NSWeekOfMonthCalendarUnit)
}
if (unitFlags & NSCalendarUnitQuarter)
{
[comps setQuarter: (ucal_get(my->cal, UCAL_MONTH, &err) + 3) / 3];
}
if (unitFlags & NSCalendarUnitWeekOfMonth)
{
[comps setWeekOfMonth: ucal_get(my->cal, UCAL_WEEK_OF_MONTH, &err)];
if (unitFlags & NSYearForWeekOfYearCalendarUnit)
}
if (unitFlags & NSCalendarUnitYearForWeekOfYear)
{
[comps setYearForWeekOfYear: ucal_get(my->cal, UCAL_YEAR_WOY, &err)];
}
if (unitFlags & NSCalendarUnitNanosecond)
{
[comps setNanosecond: ucal_get(my->cal, UCAL_MILLISECOND, &err) * MILLI_TO_NANO];
}
return AUTORELEASE(comps);
#else
@ -413,10 +449,10 @@ do \
NSDateComponents *comps = nil;
UErrorCode err = U_ZERO_ERROR;
UDate udateFrom = (UDate)floor([startingDate timeIntervalSince1970] * 1000.0);
UDate udateTo = (UDate)floor([resultDate timeIntervalSince1970] * 1000.0);
UDate udateFrom = (UDate)floor([startingDate timeIntervalSince1970] * SECOND_TO_MILLI);
UDate udateTo = (UDate)floor([resultDate timeIntervalSince1970] * SECOND_TO_MILLI);
ucal_setMillis (my->cal, udateFrom, &err);
ucal_setMillis(my->cal, udateFrom, &err);
if (U_FAILURE(err))
{
return nil;
@ -428,14 +464,14 @@ do \
* the largest to the smallest.
*/
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
NSEraCalendarUnit, setEra:, UCAL_ERA, err);
NSCalendarUnitEra, setEra:, UCAL_ERA, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
NSYearCalendarUnit, setYear:, UCAL_YEAR, err);
NSCalendarUnitYear, setYear:, UCAL_YEAR, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
NSMonthCalendarUnit, setMonth:, UCAL_MONTH, err);
NSCalendarUnitMonth, setMonth:, UCAL_MONTH, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
NSWeekOfYearCalendarUnit, setWeek:, UCAL_WEEK_OF_YEAR, err);
if (!(unitFlags & NSWeekOfYearCalendarUnit))
NSCalendarUnitWeekOfYear, setWeek:, UCAL_WEEK_OF_YEAR, err);
if (!(unitFlags & NSCalendarUnitWeekOfYear))
{
/* We must avoid setting the same unit twice (it would be zero because
* of the automatic advancement.
@ -444,35 +480,33 @@ do \
NSWeekCalendarUnit, setWeek:, UCAL_WEEK_OF_YEAR, err);
}
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
NSWeekOfMonthCalendarUnit, setWeekOfMonth:, UCAL_WEEK_OF_MONTH, err);
NSCalendarUnitWeekOfMonth, setWeekOfMonth:, UCAL_WEEK_OF_MONTH, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
NSDayCalendarUnit, setDay:, UCAL_DAY_OF_MONTH, err);
NSCalendarUnitDay, setDay:, UCAL_DAY_OF_MONTH, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
NSWeekdayOrdinalCalendarUnit, setWeekdayOrdinal:,
NSCalendarUnitWeekdayOrdinal, setWeekdayOrdinal:,
UCAL_DAY_OF_WEEK_IN_MONTH, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
NSWeekdayCalendarUnit, setWeekday:, UCAL_DAY_OF_WEEK, err);
NSCalendarUnitWeekday, setWeekday:, UCAL_DAY_OF_WEEK, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
NSHourCalendarUnit, setHour:, UCAL_HOUR_OF_DAY, err);
NSCalendarUnitHour, setHour:, UCAL_HOUR_OF_DAY, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
NSMinuteCalendarUnit, setMinute:, UCAL_MINUTE, err);
NSCalendarUnitMinute, setMinute:, UCAL_MINUTE, err);
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
NSSecondCalendarUnit, setSecond:, UCAL_SECOND, err);
# if 0
NSCalendarUnitSecond, setSecond:, UCAL_SECOND, err);
if (unitFlags & NSCalendarUnitNanosecond)
{
int32_t ns;
int32_t ms;
ns = ucal_getFieldDifference(my->cal, udateTo, UCAL_MILLISECOND, &err)
* 1000000;
ms = ucal_getFieldDifference(my->cal, udateTo, UCAL_MILLISECOND, &err);
if (U_FAILURE(err))
{
RELEASE(comps);
return nil;
}
[comps setNanosecond: ns];
[comps setNanosecond: ms * MILLI_TO_NANO];
}
# endif
return AUTORELEASE(comps);
#else
@ -480,6 +514,18 @@ do \
#endif
}
#undef COMPONENT_DIFF
#define _ADD_COMPONENT(c, n) \
if (opts & NSWrapCalendarComponents) \
ucal_roll(my->cal, c, n, &err); \
else \
ucal_add(my->cal, c, n, &err); \
if (U_FAILURE(err)) \
{ \
return nil; \
}
- (NSDate *) dateByAddingComponents: (NSDateComponents *) comps
toDate: (NSDate *) date
options: (NSUInteger) opts
@ -490,14 +536,9 @@ do \
UDate udate;
[self _resetCalendar];
udate = (UDate)([date timeIntervalSince1970] * 1000.0);
ucal_setMillis (my->cal, udate, &err);
udate = (UDate)([date timeIntervalSince1970] * SECOND_TO_MILLI);
ucal_setMillis(my->cal, udate, &err);
#define _ADD_COMPONENT(c, n) \
if (opts & NSWrapCalendarComponents) \
ucal_roll (my->cal, c, n, &err); \
else \
ucal_add (my->cal, c, n, &err);
if ((amount = [comps era]) != NSDateComponentUndefined)
{
_ADD_COMPONENT(UCAL_ERA, (int32_t)amount);
@ -542,78 +583,107 @@ do \
{
_ADD_COMPONENT(UCAL_YEAR_WOY, (int32_t)amount);
}
#undef _ADD_COMPONENT
if ((amount = [comps nanosecond]) != NSDateComponentUndefined)
{
_ADD_COMPONENT(UCAL_MILLISECOND, (int32_t)(amount / MILLI_TO_NANO));
}
udate = ucal_getMillis (my->cal, &err);
udate = ucal_getMillis(my->cal, &err);
if (U_FAILURE(err))
{
return nil;
}
return [NSDate dateWithTimeIntervalSince1970: (udate / 1000.0)];
return [NSDate dateWithTimeIntervalSince1970: (udate / SECOND_TO_MILLI)];
#else
return nil;
#endif
}
#undef _ADD_COMPONENT
- (NSDate *) dateFromComponents: (NSDateComponents *) comps
{
#if GS_USE_ICU == 1
NSInteger amount;
UDate udate;
UErrorCode err = U_ZERO_ERROR;
void *cal;
NSTimeZone *timeZone;
[self _resetCalendar];
ucal_clear (my->cal);
timeZone = [comps timeZone];
if (timeZone == nil)
{
timeZone = [self timeZone];
}
cal = [self _openCalendarFor: timeZone];
if (!cal)
{
return nil;
}
ucal_clear(cal);
if ((amount = [comps era]) != NSDateComponentUndefined)
{
ucal_set (my->cal, UCAL_ERA, (int32_t)amount);
ucal_set(cal, UCAL_ERA, (int32_t)amount);
}
if ((amount = [comps year]) != NSDateComponentUndefined)
{
ucal_set (my->cal, UCAL_YEAR, (int32_t)amount);
ucal_set (cal, UCAL_YEAR, (int32_t)amount);
}
if ((amount = [comps month]) != NSDateComponentUndefined)
{
ucal_set (my->cal, UCAL_MONTH, amount-1);
ucal_set (cal, UCAL_MONTH, amount - 1);
}
if ((amount = [comps day]) != NSDateComponentUndefined)
{
ucal_set (my->cal, UCAL_DAY_OF_MONTH, (int32_t)amount);
ucal_set (cal, UCAL_DAY_OF_MONTH, (int32_t)amount);
}
if ((amount = [comps hour]) != NSDateComponentUndefined)
{
ucal_set (my->cal, UCAL_HOUR_OF_DAY, (int32_t)amount);
ucal_set (cal, UCAL_HOUR_OF_DAY, (int32_t)amount);
}
if ((amount = [comps minute]) != NSDateComponentUndefined)
{
ucal_set (my->cal, UCAL_MINUTE, (int32_t)amount);
ucal_set (cal, UCAL_MINUTE, (int32_t)amount);
}
if ((amount = [comps second]) != NSDateComponentUndefined)
{
ucal_set (my->cal, UCAL_SECOND, (int32_t)amount);
ucal_set (cal, UCAL_SECOND, (int32_t)amount);
}
if ((amount = [comps week]) != NSDateComponentUndefined)
{
ucal_set (my->cal, UCAL_WEEK_OF_YEAR, (int32_t)amount);
ucal_set (cal, UCAL_WEEK_OF_YEAR, (int32_t)amount);
}
if ((amount = [comps weekday]) != NSDateComponentUndefined)
{
ucal_set (my->cal, UCAL_DAY_OF_WEEK, (int32_t)amount);
ucal_set (cal, UCAL_DAY_OF_WEEK, (int32_t)amount);
}
if ((amount = [comps weekdayOrdinal]) != NSDateComponentUndefined)
{
ucal_set (cal, UCAL_DAY_OF_WEEK_IN_MONTH, (int32_t)amount);
}
if ((amount = [comps weekOfMonth]) != NSDateComponentUndefined)
{
ucal_set (my->cal, UCAL_WEEK_OF_MONTH, (int32_t)amount);
ucal_set (cal, UCAL_WEEK_OF_MONTH, (int32_t)amount);
}
if ((amount = [comps yearForWeekOfYear]) != NSDateComponentUndefined)
{
ucal_set (my->cal, UCAL_YEAR_WOY, (int32_t)amount);
ucal_set (cal, UCAL_YEAR_WOY, (int32_t)amount);
}
if ((amount = [comps nanosecond]) != NSDateComponentUndefined)
{
ucal_set (cal, UCAL_MILLISECOND, (int32_t)(amount / MILLI_TO_NANO));
}
udate = ucal_getMillis (my->cal, &err);
udate = ucal_getMillis(cal, &err);
ucal_close(cal);
if (U_FAILURE(err))
{
return nil;
}
return [NSDate dateWithTimeIntervalSince1970: (udate / 1000.0)];
return [NSDate dateWithTimeIntervalSince1970: (udate / SECOND_TO_MILLI)];
#else
return nil;
#endif
@ -626,6 +696,8 @@ do \
- (void) setLocale: (NSLocale *) locale
{
// It's much easier to keep a copy of the NSLocale's string representation
// than to have to build it everytime we have to open a UCalendar.
[self _setLocaleIdentifier: [self _localeIDWithLocale: locale]];
}
@ -638,7 +710,7 @@ do \
{
my->firstWeekday = weekday;
#if GS_USE_ICU == 1
ucal_setAttribute (my->cal, UCAL_FIRST_DAY_OF_WEEK, my->firstWeekday);
ucal_setAttribute(my->cal, UCAL_FIRST_DAY_OF_WEEK, my->firstWeekday);
#endif
}
@ -651,7 +723,7 @@ do \
{
my->minimumDaysInFirstWeek = (int32_t)mdw;
#if GS_USE_ICU == 1
ucal_setAttribute (my->cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK,
ucal_setAttribute(my->cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK,
my->minimumDaysInFirstWeek);
#endif
}
@ -664,62 +736,67 @@ do \
- (void) setTimeZone: (NSTimeZone *) tz
{
if ([tz isEqual: my->tz])
{
return;
}
RELEASE(my->tz);
my->tz = RETAIN(tz);
ASSIGN(my->tz, tz);
[self _resetCalendar];
}
- (NSRange) maximumRangeOfUnit: (NSCalendarUnit) unit
{
NSRange result = NSMakeRange (0, 0);
#if GS_USE_ICU == 1
UCalendarDateFields dateField;
NSRange result;
UErrorCode err = U_ZERO_ERROR;
[self _resetCalendar];
dateField = _NSCalendarUnitToDateField (unit);
dateField = _NSCalendarUnitToDateField(unit);
if (dateField != -1)
{
// We really don't care if there are any errors...
result.location =
(NSUInteger)ucal_getLimit (my->cal, dateField, UCAL_MINIMUM, &err);
(NSUInteger)ucal_getLimit(my->cal, dateField, UCAL_MINIMUM, &err);
result.length =
(NSUInteger)ucal_getLimit (my->cal, dateField, UCAL_MAXIMUM, &err)
(NSUInteger)ucal_getLimit(my->cal, dateField, UCAL_MAXIMUM, &err)
- result.location + 1;
// ICU's month is 0-based, while NSCalendar is 1-based
if (dateField == UCAL_MONTH)
{
result.location += 1;
}
}
#endif
return result;
#else
return NSMakeRange (0, 0);
#endif
}
- (NSRange) minimumRangeofUnit: (NSCalendarUnit) unit
{
NSRange result = NSMakeRange (0, 0);
#if GS_USE_ICU == 1
UCalendarDateFields dateField;
NSRange result;
UErrorCode err = U_ZERO_ERROR;
[self _resetCalendar];
dateField = _NSCalendarUnitToDateField (unit);
dateField = _NSCalendarUnitToDateField(unit);
if (dateField != -1)
{
// We really don't care if there are any errors...
result.location =
(NSUInteger)ucal_getLimit (my->cal, dateField, UCAL_GREATEST_MINIMUM, &err);
(NSUInteger)ucal_getLimit(my->cal, dateField, UCAL_GREATEST_MINIMUM, &err);
result.length =
(NSUInteger)ucal_getLimit (my->cal, dateField, UCAL_LEAST_MAXIMUM, &err)
(NSUInteger)ucal_getLimit(my->cal, dateField, UCAL_LEAST_MAXIMUM, &err)
- result.location + 1;
// ICU's month is 0-based, while NSCalendar is 1-based
if (dateField == UCAL_MONTH)
{
result.location += 1;
return result;
#else
return NSMakeRange (0, 0);
}
}
#endif
return result;
}
- (NSUInteger) ordinalityOfUnit: (NSCalendarUnit) smaller
@ -736,27 +813,6 @@ do \
return NSMakeRange (0, 0);
}
+ (id) autoupdatingCurrentCalendar
{
NSCalendar *result;
[classLock lock];
if (nil == autoupdatingCalendar)
{
autoupdatingCalendar = [[self currentCalendar] copy];
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(defaultsDidChange:)
name: NSUserDefaultsDidChangeNotification
object: nil];
}
result = RETAIN(autoupdatingCalendar);
[classLock unlock];
return AUTORELEASE(result);
}
- (BOOL) rangeOfUnit: (NSCalendarUnit) unit
startDate: (NSDate **) datep
interval: (NSTimeInterval *)tip
@ -768,7 +824,7 @@ do \
- (BOOL) isEqual: (id) obj
{
#if GS_USE_ICU == 1
return (BOOL)ucal_equivalentTo (my->cal, [obj _UCalendar]);
return (BOOL)ucal_equivalentTo(my->cal, [obj _UCalendar]);
#else
if ([obj isKindOfClass: [self class]])
{
@ -778,6 +834,10 @@ do \
return NO;
if (![my->tz isEqual: [obj timeZone]])
return NO;
if (my->firstWeekday != [obj firstWeekday])
return NO;
if (my->minimumDaysInFirstWeek != [obj minimumDaysInFirstWeek])
return NO;
return YES;
}
@ -843,6 +903,8 @@ typedef struct {
NSInteger quarter;
NSInteger weekOfMonth;
NSInteger yearForWeekOfYear;
BOOL leapMonth;
NSInteger nanosecond;
NSCalendar *cal;
NSTimeZone *tz;
} DateComp;
@ -880,6 +942,8 @@ typedef struct {
my->quarter = NSDateComponentUndefined;
my->weekOfMonth = NSDateComponentUndefined;
my->yearForWeekOfYear = NSDateComponentUndefined;
my->leapMonth = NO;
my->nanosecond = NSDateComponentUndefined;
my->cal = NULL;
my->tz = NULL;
}
@ -921,6 +985,11 @@ typedef struct {
return my->second;
}
- (NSInteger) nanosecond
{
return my->nanosecond;
}
- (NSInteger) week
{
return my->week;
@ -956,6 +1025,11 @@ typedef struct {
return my->yearForWeekOfYear;
}
- (BOOL) leapMonth
{
return my->leapMonth;
}
- (NSCalendar *) calendar
{
return my->cal;
@ -969,10 +1043,6 @@ typedef struct {
- (NSDate *) date
{
NSCalendar* cal = [self calendar];
NSTimeZone* zone = [self timeZone];
if (zone != NULL)
[cal setTimeZone: zone];
return [cal dateFromComponents: self];
}
@ -1013,6 +1083,11 @@ typedef struct {
my->second = v;
}
- (void) setNanosecond: (NSInteger) v
{
my->nanosecond = v;
}
- (void) setWeek: (NSInteger) v
{
my->week = v;
@ -1048,6 +1123,11 @@ typedef struct {
my->yearForWeekOfYear = v;
}
- (void) setLeapMonth: (BOOL) v
{
my->leapMonth = v;
}
- (void) setCalendar: (NSCalendar *) cal
{
ASSIGN(my->cal, cal);
@ -1058,6 +1138,98 @@ typedef struct {
ASSIGN(my->tz, tz);
}
- (BOOL) isValidDate
{
if (my->cal == nil)
{
return NO;
}
return [self isValidDateInCalendar: my->cal];
}
- (BOOL) isValidDateInCalendar: (NSCalendar *) calendar
{
return [calendar dateFromComponents: self] != nil;
}
- (NSInteger) valueForComponent: (NSCalendarUnit) unit
{
switch (unit)
{
case NSCalendarUnitEra: return my->era;
case NSCalendarUnitYear: return my->year;
case NSCalendarUnitMonth: return my->month;
case NSCalendarUnitDay: return my->day;
case NSCalendarUnitHour: return my->hour;
case NSCalendarUnitMinute: return my->minute;
case NSCalendarUnitSecond: return my->second;
case NSCalendarUnitWeekday: return my->weekday;
case NSCalendarUnitWeekdayOrdinal: return my->weekdayOrdinal;
case NSCalendarUnitQuarter: return my->quarter;
case NSCalendarUnitWeekOfMonth: return my->weekOfMonth;
case NSCalendarUnitWeekOfYear: return my->week;
case NSWeekCalendarUnit: return my->week;
case NSCalendarUnitYearForWeekOfYear: return my->yearForWeekOfYear;
case NSCalendarUnitNanosecond: return my->nanosecond;
default: return 0;
}
}
- (void) setValue: (NSInteger) value
forComponent: (NSCalendarUnit) unit
{
switch (unit)
{
case NSCalendarUnitEra:
my->era = value;
break;
case NSCalendarUnitYear:
my->year = value;
break;
case NSCalendarUnitMonth:
my->month = value;
break;
case NSCalendarUnitDay:
my->day = value;
break;
case NSCalendarUnitHour:
my->hour = value;
break;
case NSCalendarUnitMinute:
my->minute = value;
break;
case NSCalendarUnitSecond:
my->second = value;
break;
case NSCalendarUnitWeekday:
my->weekday = value;
break;
case NSCalendarUnitWeekdayOrdinal:
my->weekdayOrdinal = value;
break;
case NSCalendarUnitQuarter:
my->quarter = value;
break;
case NSCalendarUnitWeekOfMonth:
my->weekOfMonth = value;
break;
case NSCalendarUnitWeekOfYear:
my->week = value;
break;
case NSWeekCalendarUnit:
my->week = value;
break;
case NSCalendarUnitYearForWeekOfYear:
my->yearForWeekOfYear = value;
break;
case NSCalendarUnitNanosecond:
my->nanosecond = value;
break;
default:
break;
}
}
- (id) copyWithZone: (NSZone*)zone
{
if (NSShouldRetainWithZone(self, zone))

View file

@ -468,10 +468,15 @@ parseNumber(ParserState *state)
{\
bufferSize *= 2;\
if (number == numberBuffer)\
{\
number = malloc(bufferSize);\
memcpy(number, numberBuffer, sizeof(numberBuffer));\
}\
else\
{\
number = realloc(number, bufferSize);\
}\
}\
number[parsedSize++] = (char)x; } while (0)
// JSON numbers must start with a - or a digit
if (!(c == '-' || isdigit(c)))

View file

@ -627,6 +627,11 @@ static NSRecursiveLock *classLock = nil;
[[dict objectForKey: NSLocaleCollationIdentifier] UTF8String];
const char *currency = [[dict objectForKey: NSLocaleCurrencyCode] UTF8String];
if (!calendar)
{
calendar = [[dict objectForKey: NSLocaleCalendarIdentifier] UTF8String];
}
// A locale cannot be constructed without a language.
if (language == NULL)
return nil;

View file

@ -1901,7 +1901,8 @@ GSICUCollatorOpen(NSStringCompareOptions mask, NSLocale *locale)
}
}
- (NSString *) stringByAddingPercentEncodingWithAllowedCharacters: (NSCharacterSet *)aSet
- (NSString *) stringByAddingPercentEncodingWithAllowedCharacters:
(NSCharacterSet *)aSet
{
NSData *data = [self dataUsingEncoding: NSUTF8StringEncoding];
NSString *s = nil;
@ -1921,7 +1922,10 @@ GSICUCollatorOpen(NSStringCompareOptions mask, NSLocale *locale)
unsigned int hi;
unsigned int lo;
if([aSet characterIsMember: c]) // if the character is in the allowed set, put it in
/* If the character is in the allowed set *and* is in the
* 7-bit ASCII range, it can be added unchanged.
*/
if (c < 128 && [aSet characterIsMember: c])
{
dst[dpos++] = c;
}
@ -1936,7 +1940,7 @@ GSICUCollatorOpen(NSStringCompareOptions mask, NSLocale *locale)
}
s = [[NSString alloc] initWithBytes: dst
length: dpos
encoding: NSUTF8StringEncoding];
encoding: NSASCIIStringEncoding];
NSZoneFree(NSDefaultMallocZone(), dst);
IF_NO_GC([s autorelease];)
}
@ -1963,7 +1967,7 @@ GSICUCollatorOpen(NSStringCompareOptions mask, NSLocale *locale)
uint8_t hi = s[index+1];
uint8_t lo = s[index+2];
if (isdigit(hi) && isxdigit(lo))
if (isxdigit(hi) && isxdigit(lo))
{
index += 2;
if (hi <= '9')

View file

@ -51,6 +51,9 @@ TOP_DIR := $(shell dirname $(CURDIR))
all::
@(echo If you want to run the gnustep-base testsuite, please type \'${MAKE} check\')
# To run tests for a separate group please, use 'make check testobj=NSString'
# or 'make check testobj=NSDate/general.m' to run an individual test file
#
#
# 'make check' runs the testsuite (Objective-C tests only)
#
@ -72,9 +75,9 @@ check::
export LD_LIBRARY_PATH;\
export PATH;\
if [ "$(debug)" = "yes" ]; then \
gnustep-tests --debug base;\
gnustep-tests --debug 'base/$(testobj)';\
else \
gnustep-tests base;\
gnustep-tests 'base/$(testobj)';\
fi; \
)

View file

@ -17,6 +17,8 @@ int main()
NSCalendar *cal;
NSDate *date;
NSDate *date2;
NSDate *date3;
NSDate *date4;
START_SET("NSCalendar 10.7 features")
if (!NSCALENDAR_SUPPORTED)
@ -49,6 +51,12 @@ int main()
PASS_EQUAL(date, date2, "-[NSDateComponents date] returns the correct date");
date3 = [NSDate dateWithString: @"2012-12-31 13:57:00 +0200"];
[comps setTimeZone: [NSTimeZone timeZoneForSecondsFromGMT: 7200]];
date4 = [cal dateFromComponents: comps];
PASS_EQUAL(date3, date4, "-[NSCalendar dateFromComponents:] respects the time zone");
RELEASE(comps);
RELEASE(cal);

View file

@ -3,55 +3,93 @@
#import <Foundation/NSString.h>
#import <Foundation/NSCharacterSet.h>
BOOL testUrlCharacterSetEncoding(
NSString* decodedString,
NSString* encodedString,
NSCharacterSet* allowedCharacterSet)
{
NSString *testString
= [decodedString stringByAddingPercentEncodingWithAllowedCharacters:
allowedCharacterSet];
// NSLog(@"String by adding percent, done. test=%@ decoded=%@", testString, decodedString);
return [encodedString isEqualToString: testString];
void testEncodeDecode(NSString* encoded, NSString* decoded, NSCharacterSet* charset, NSString* description){
NSString* encodeTest = [decoded stringByAddingPercentEncodingWithAllowedCharacters:charset];
NSString* decodeTest = [encoded stringByRemovingPercentEncoding];
const char* encodeMsg = [[NSString stringWithFormat:@"Percent-Encode: %@", description] UTF8String];
const char* decodeMsg = [[NSString stringWithFormat:@"Percent-Decode: %@", description] UTF8String];
PASS_EQUAL(encodeTest, encoded, "%s", encodeMsg);
PASS_EQUAL(decodeTest, decoded, "%s", decodeMsg);
}
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSString *urlDecodedString = @"Only alphabetic characters should be allowed and not encoded. !@#$%^&*()_+-=";
NSString *urlEncodedString =
@"Only%20alphabetic%20characters%20should%20be%20allowed%20and%20not%20encoded%2E%20%21%40%23%24%25%5E%26%2A%28%29%5F%2B%2D%3D";
NSCharacterSet *allowedCharacterSet = [NSCharacterSet alphanumericCharacterSet];
PASS(testUrlCharacterSetEncoding(urlDecodedString, urlEncodedString, allowedCharacterSet), "alphanumericCharacterSet");
NSString *urlEncodedString = @"Only%20alphabetic%20characters%20should%20be%20allowed%20and%20not%20encoded%2E%20%21%40%23%24%25%5E%26%2A%28%29%5F%2B%2D%3D";
testEncodeDecode(urlEncodedString, urlDecodedString, [NSCharacterSet alphanumericCharacterSet],
@"Skip alphanumericCharacterSet 01");
urlDecodedString = @"https://www.microsoft.com/en-us/!@#$%^&*()_";
urlEncodedString = @"https://www.microsoft.com/en-us/!@%23$%25%5E&*()_";
allowedCharacterSet = [NSCharacterSet URLFragmentAllowedCharacterSet];
PASS(testUrlCharacterSetEncoding(urlDecodedString, urlEncodedString, allowedCharacterSet), "fragmentCharacterSet");
testEncodeDecode(urlEncodedString, urlDecodedString, [NSCharacterSet URLFragmentAllowedCharacterSet],
@"Skip URLFragmentAllowedCharacterSet 02");
urlDecodedString = @"All alphabetic characters should be encoded. Symbols should not be: !@#$%^&*()_+-=";
urlEncodedString = @"%41%6C%6C %61%6C%70%68%61%62%65%74%69%63 %63%68%61%72%61%63%74%65%72%73 %73%68%6F%75%6C%64 %62%65 "
@"%65%6E%63%6F%64%65%64. %53%79%6D%62%6F%6C%73 %73%68%6F%75%6C%64 %6E%6F%74 %62%65: !@#$%^&*()_+-=";
allowedCharacterSet = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
PASS(testUrlCharacterSetEncoding(urlDecodedString, urlEncodedString, allowedCharacterSet), "inverted");
testEncodeDecode(urlEncodedString, urlDecodedString, [[NSCharacterSet alphanumericCharacterSet] invertedSet],
@"Skip not alphanumericCharacterSet 03");
urlDecodedString = @"Here are some Emojis: \U0001F601 \U0001F602 \U0001F638 Emojis done."; // Multibyte encoded characters
urlEncodedString = @"Here%20are%20some%20Emojis:%20%F0%9F%98%81%20%F0%9F%98%82%20%F0%9F%98%B8%20Emojis%20done.";
allowedCharacterSet = [NSCharacterSet URLFragmentAllowedCharacterSet];
PASS(testUrlCharacterSetEncoding(urlDecodedString, urlEncodedString, allowedCharacterSet), "fragmentCharacterSet emojis");
testEncodeDecode(urlEncodedString, urlDecodedString, [NSCharacterSet URLFragmentAllowedCharacterSet],
@"Skip URLFragmentAllowedCharacterSet 04");
urlDecodedString = @"\1";
urlEncodedString = @"%01";
allowedCharacterSet = [NSCharacterSet alphanumericCharacterSet];
PASS(testUrlCharacterSetEncoding(urlDecodedString, urlEncodedString, allowedCharacterSet), "alphanumericCharacterSet");
testEncodeDecode(urlEncodedString, urlDecodedString, [NSCharacterSet alphanumericCharacterSet],
@"Skip URLFragmentAllowedCharacterSet 05");
urlDecodedString = @"£";
urlEncodedString = @"%C2%A3";
testEncodeDecode(urlEncodedString, urlDecodedString, [NSCharacterSet alphanumericCharacterSet],
@"Two-byte character 06");
urlDecodedString = @"€";
urlEncodedString = @"%E2%82%AC";
testEncodeDecode(urlEncodedString, urlDecodedString, [NSCharacterSet alphanumericCharacterSet],
@"Three-byte character 07");
urlDecodedString = @"𐍈";
urlEncodedString = @"%F0%90%8D%88";
testEncodeDecode(urlEncodedString, urlDecodedString, [NSCharacterSet alphanumericCharacterSet],
@"Four-byte character 08");
//check full string encoding and decoding
urlDecodedString = @"0123456789 AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz _-~`!#$%&'()*+,/:;=?@[]™…©®£ƒ‰¥§";
urlEncodedString = @"%30%31%32%33%34%35%36%37%38%39%20%41%61%42%62%43%63%44%64%45%65%46%66%47%67%48%68%49%69%4A%6A%4B%6B%4C%6C%4D%6D%4E%6E%4F%6F%50%70%51%71%52%72%53%73%54%74%55%75%56%76%57%77%58%78%59%79%5A%7A%20%5F%2D%7E%60%21%23%24%25%26%27%28%29%2A%2B%2C%2F%3A%3B%3D%3F%40%5B%5D%E2%84%A2%E2%80%A6%C2%A9%C2%AE%C2%A3%C6%92%E2%80%B0%C2%A5%C2%A7";
testEncodeDecode(urlEncodedString, urlDecodedString, [[NSCharacterSet characterSetWithCharactersInString:urlDecodedString] invertedSet],
@"All characters in string 09");
//check decoding of string with an unencoded part at the beginning
NSString* asIsString = @"0123456789 AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz _-~`!#$&'()*+,/:;=?@[]™…©®£ƒ‰¥§";
urlDecodedString = [asIsString stringByAppendingString:urlDecodedString];
urlEncodedString = [asIsString stringByAppendingString:urlEncodedString];
PASS_EQUAL([urlEncodedString stringByRemovingPercentEncoding], urlDecodedString, "Percent-encoded string decoding 10");
//check decoding of string with the encoded part in the middle
urlDecodedString = [urlDecodedString stringByAppendingString:asIsString];
urlEncodedString = [urlEncodedString stringByAppendingString:asIsString];
PASS_EQUAL([urlEncodedString stringByRemovingPercentEncoding], urlDecodedString, "Percent-encoded string decoding 11");
urlDecodedString = @"All alphabetic characters should be encoded. Symbols should not be: !@#$%^&*()_+-=";
urlEncodedString = @"%41%6C%6C %61%6C%70%68%61%62%65%74%69%63 %63%68%61%72%61%63%74%65%72%73 %73%68%6F%75%6C%64 %62%65 "
@"%65%6E%63%6F%64%65%64. %53%79%6D%62%6F%6C%73 %73%68%6F%75%6C%64 %6E%6F%74 %62%65: !@#$%^&*()_+-=";
NSString *result = [urlEncodedString stringByRemovingPercentEncoding];
PASS([urlDecodedString isEqualToString: result], "stringByRemovingPercentEncoding");
// NSLog(@"Result = \"%@\",\ndecodedString = \"%@\",\nencodedString = \"%@\"", result, urlDecodedString, urlEncodedString);
[pool drain];
return 0;
}