mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-31 16:50:58 +00:00
Merge branch 'master' of github.com:gnustep/libs-base into NSSecureCoding_branch
This commit is contained in:
commit
76fac00cd2
10 changed files with 598 additions and 335 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -26,6 +26,9 @@ Tests/base/coding/ulong-8.type
|
||||||
*.orig
|
*.orig
|
||||||
*.swp
|
*.swp
|
||||||
|
|
||||||
|
# MacOS Desktop Services Store
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
# Created by https://www.gitignore.io/api/xcode
|
# Created by https://www.gitignore.io/api/xcode
|
||||||
# Edit at https://www.gitignore.io/?templates=xcode
|
# Edit at https://www.gitignore.io/?templates=xcode
|
||||||
|
|
||||||
|
|
10
ChangeLog
10
ChangeLog
|
@ -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>
|
2020-04-21 Richard Frith-Macdonald <rfm@gnu.org>
|
||||||
|
|
||||||
* Source/NSNotification.m:
|
* Source/NSNotification.m:
|
||||||
|
|
|
@ -129,7 +129,7 @@ enum
|
||||||
NSCalendarUnitWeekOfMonth = (1UL << 12),
|
NSCalendarUnitWeekOfMonth = (1UL << 12),
|
||||||
NSCalendarUnitWeekOfYear = (1UL << 13),
|
NSCalendarUnitWeekOfYear = (1UL << 13),
|
||||||
NSCalendarUnitYearForWeekOfYear = (1UL << 14),
|
NSCalendarUnitYearForWeekOfYear = (1UL << 14),
|
||||||
NSCalendarUnitNanosecond = (1 << 15), // FIXME: unimplemented
|
NSCalendarUnitNanosecond = (1 << 15),
|
||||||
NSCalendarUnitCalendar = (1 << 20), // FIXME: unimplemented
|
NSCalendarUnitCalendar = (1 << 20), // FIXME: unimplemented
|
||||||
NSCalendarUnitTimeZone = (1 << 21) // FIXME: unimplemented
|
NSCalendarUnitTimeZone = (1 << 21) // FIXME: unimplemented
|
||||||
#endif
|
#endif
|
||||||
|
@ -227,6 +227,7 @@ enum
|
||||||
* yearForWeekOfYear is 2013, since it's already week 1 in 2013.
|
* yearForWeekOfYear is 2013, since it's already week 1 in 2013.
|
||||||
*/
|
*/
|
||||||
- (NSInteger) yearForWeekOfYear;
|
- (NSInteger) yearForWeekOfYear;
|
||||||
|
- (NSInteger) nanosecond;
|
||||||
|
|
||||||
/** Sets the number of the week in this month. */
|
/** Sets the number of the week in this month. */
|
||||||
- (void) setWeekOfMonth: (NSInteger) v;
|
- (void) setWeekOfMonth: (NSInteger) v;
|
||||||
|
@ -241,8 +242,22 @@ enum
|
||||||
* See the explanation at <code>-yearForWeekOfYear</code>.
|
* See the explanation at <code>-yearForWeekOfYear</code>.
|
||||||
*/
|
*/
|
||||||
- (void) setYearForWeekOfYear: (NSInteger) v;
|
- (void) setYearForWeekOfYear: (NSInteger) v;
|
||||||
|
- (void) setNanosecond: (NSInteger) v;
|
||||||
|
|
||||||
#endif
|
#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
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,31 +46,26 @@
|
||||||
#if GS_USE_ICU == 1
|
#if GS_USE_ICU == 1
|
||||||
static UCalendarDateFields _NSCalendarUnitToDateField (NSCalendarUnit unit)
|
static UCalendarDateFields _NSCalendarUnitToDateField (NSCalendarUnit unit)
|
||||||
{
|
{
|
||||||
// I'm just going to go in the order they appear in Apple's documentation
|
if (unit & NSCalendarUnitEra)
|
||||||
if (unit & NSEraCalendarUnit)
|
|
||||||
return UCAL_ERA;
|
return UCAL_ERA;
|
||||||
if (unit & NSYearCalendarUnit)
|
if (unit & NSCalendarUnitYear)
|
||||||
return UCAL_YEAR;
|
return UCAL_YEAR;
|
||||||
if (unit & NSMonthCalendarUnit)
|
if (unit & NSCalendarUnitMonth)
|
||||||
return UCAL_MONTH;
|
return UCAL_MONTH;
|
||||||
if (unit & NSDayCalendarUnit)
|
if (unit & NSCalendarUnitDay)
|
||||||
return UCAL_DAY_OF_MONTH;
|
return UCAL_DAY_OF_MONTH;
|
||||||
if (unit & NSHourCalendarUnit)
|
if (unit & NSCalendarUnitHour)
|
||||||
return UCAL_HOUR_OF_DAY;
|
return UCAL_HOUR_OF_DAY;
|
||||||
if (unit & NSMinuteCalendarUnit)
|
if (unit & NSCalendarUnitMinute)
|
||||||
return UCAL_MINUTE;
|
return UCAL_MINUTE;
|
||||||
if (unit & NSSecondCalendarUnit)
|
if (unit & NSCalendarUnitSecond)
|
||||||
return UCAL_SECOND;
|
return UCAL_SECOND;
|
||||||
if (unit & NSWeekCalendarUnit)
|
if (unit & NSCalendarUnitWeekOfYear)
|
||||||
return UCAL_WEEK_OF_YEAR;
|
return UCAL_WEEK_OF_YEAR;
|
||||||
if (unit & NSWeekdayCalendarUnit)
|
if (unit & NSCalendarUnitWeekday)
|
||||||
return UCAL_DAY_OF_WEEK;
|
return UCAL_DAY_OF_WEEK;
|
||||||
if (unit & NSWeekdayOrdinalCalendarUnit)
|
if (unit & NSCalendarUnitWeekdayOrdinal)
|
||||||
// FIXME: Is this right???
|
|
||||||
return UCAL_DAY_OF_WEEK_IN_MONTH;
|
return UCAL_DAY_OF_WEEK_IN_MONTH;
|
||||||
// ICU doesn't include a quarter DateField...
|
|
||||||
if (unit & NSQuarterCalendarUnit)
|
|
||||||
return (UCAL_MONTH + 2) / 3;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif /* GS_USE_ICU */
|
#endif /* GS_USE_ICU */
|
||||||
|
@ -84,47 +79,76 @@ typedef struct {
|
||||||
NSInteger minimumDaysInFirstWeek;
|
NSInteger minimumDaysInFirstWeek;
|
||||||
} Calendar;
|
} Calendar;
|
||||||
#define my ((Calendar*)_NSCalendarInternal)
|
#define my ((Calendar*)_NSCalendarInternal)
|
||||||
#define aac ((Calendar*)(autoupdatingCalendar->_NSCalendarInternal))
|
|
||||||
|
|
||||||
@interface NSCalendar (PrivateMethods)
|
@interface NSCalendar (PrivateMethods)
|
||||||
|
- (void *) _openCalendarFor: (NSTimeZone *)timeZone;
|
||||||
- (void) _resetCalendar;
|
- (void) _resetCalendar;
|
||||||
- (void *) _UCalendar;
|
- (void *) _UCalendar;
|
||||||
- (NSString *) _localeIDWithLocale: (NSLocale*)locale;
|
- (NSString *) _localeIDWithLocale: (NSLocale*)locale;
|
||||||
- (NSString *) _localeIDentifier;
|
- (NSString *) _localeIdentifier;
|
||||||
- (void) _setLocaleIdentifier: (NSString*)identifier;
|
- (void) _setLocaleIdentifier: (NSString*)identifier;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
static NSCalendar *autoupdatingCalendar = nil;
|
||||||
|
static NSRecursiveLock *classLock = nil;
|
||||||
|
|
||||||
#define TZ_NAME_LENGTH 1024
|
#define TZ_NAME_LENGTH 1024
|
||||||
|
#define SECOND_TO_MILLI 1000.0
|
||||||
|
#define MILLI_TO_NANO 1000000
|
||||||
|
|
||||||
@implementation NSCalendar (PrivateMethods)
|
@implementation NSCalendar (PrivateMethods)
|
||||||
- (void) _resetCalendar
|
|
||||||
{
|
|
||||||
#if GS_USE_ICU == 1
|
#if GS_USE_ICU == 1
|
||||||
|
- (void *) _openCalendarFor: (NSTimeZone *)timeZone
|
||||||
|
{
|
||||||
NSString *tzName;
|
NSString *tzName;
|
||||||
NSUInteger tzLen;
|
NSUInteger tzLen;
|
||||||
unichar cTzId[TZ_NAME_LENGTH];
|
unichar cTzId[TZ_NAME_LENGTH];
|
||||||
const char *cLocaleId;
|
const char *cLocaleId;
|
||||||
UErrorCode err = U_ZERO_ERROR;
|
UErrorCode err = U_ZERO_ERROR;
|
||||||
|
UCalendarType type;
|
||||||
if (my->cal != NULL)
|
|
||||||
ucal_close (my->cal);
|
|
||||||
|
|
||||||
cLocaleId = [my->localeID UTF8String];
|
cLocaleId = [my->localeID UTF8String];
|
||||||
tzName = [my->tz name];
|
tzName = [timeZone name];
|
||||||
tzLen = [tzName length];
|
tzLen = [tzName length];
|
||||||
if (tzLen > TZ_NAME_LENGTH)
|
if (tzLen > TZ_NAME_LENGTH)
|
||||||
|
{
|
||||||
tzLen = TZ_NAME_LENGTH;
|
tzLen = TZ_NAME_LENGTH;
|
||||||
|
}
|
||||||
[tzName getCharacters: cTzId range: NSMakeRange(0, tzLen)];
|
[tzName getCharacters: cTzId range: NSMakeRange(0, tzLen)];
|
||||||
|
|
||||||
|
if ([NSGregorianCalendar isEqualToString: my->identifier])
|
||||||
|
{
|
||||||
|
type = UCAL_GREGORIAN;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
#ifndef UCAL_DEFAULT
|
#ifndef UCAL_DEFAULT
|
||||||
/*
|
/*
|
||||||
* Older versions of ICU used UCAL_TRADITIONAL rather than UCAL_DEFAULT
|
* Older versions of ICU used UCAL_TRADITIONAL rather than UCAL_DEFAULT
|
||||||
* so if one is not available we use the other.
|
* so if one is not available we use the other.
|
||||||
*/
|
*/
|
||||||
#define UCAL_DEFAULT UCAL_TRADITIONAL
|
type = UCAL_TRADITIONAL;
|
||||||
|
#else
|
||||||
|
type = UCAL_DEFAULT;
|
||||||
#endif
|
#endif
|
||||||
my->cal =
|
// We do not need to call uloc_setKeywordValue() here to set the calendar on the locale
|
||||||
ucal_open ((const UChar *)cTzId, tzLen, cLocaleId, UCAL_DEFAULT, &err);
|
// 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)
|
if (NSNotFound == my->firstWeekday)
|
||||||
{
|
{
|
||||||
|
@ -147,7 +171,6 @@ typedef struct {
|
||||||
ucal_setAttribute(my->cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK,
|
ucal_setAttribute(my->cal, UCAL_MINIMAL_DAYS_IN_FIRST_WEEK,
|
||||||
(int32_t)my->minimumDaysInFirstWeek);
|
(int32_t)my->minimumDaysInFirstWeek);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,16 +186,24 @@ typedef struct {
|
||||||
NSMutableDictionary *tmpDict;
|
NSMutableDictionary *tmpDict;
|
||||||
|
|
||||||
localeId = [locale localeIdentifier];
|
localeId = [locale localeIdentifier];
|
||||||
|
if (my->identifier)
|
||||||
|
{
|
||||||
tmpDict = [[NSLocale componentsFromLocaleIdentifier: localeId]
|
tmpDict = [[NSLocale componentsFromLocaleIdentifier: localeId]
|
||||||
mutableCopyWithZone: NULL];
|
mutableCopyWithZone: NULL];
|
||||||
|
[tmpDict removeObjectForKey: NSLocaleCalendar];
|
||||||
[tmpDict setObject: my->identifier forKey: NSLocaleCalendarIdentifier];
|
[tmpDict setObject: my->identifier forKey: NSLocaleCalendarIdentifier];
|
||||||
result = [NSLocale localeIdentifierFromComponents: tmpDict];
|
result = [NSLocale localeIdentifierFromComponents: tmpDict];
|
||||||
RELEASE(tmpDict);
|
RELEASE(tmpDict);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = localeId;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString*) _localeIDentifier
|
- (NSString*) _localeIdentifier
|
||||||
{
|
{
|
||||||
return my->localeID;
|
return my->localeID;
|
||||||
}
|
}
|
||||||
|
@ -180,26 +211,15 @@ typedef struct {
|
||||||
- (void) _setLocaleIdentifier: (NSString *) identifier
|
- (void) _setLocaleIdentifier: (NSString *) identifier
|
||||||
{
|
{
|
||||||
if ([identifier isEqualToString: my->localeID])
|
if ([identifier isEqualToString: my->localeID])
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
RELEASE(my->localeID);
|
ASSIGN(my->localeID, identifier);
|
||||||
my->localeID = RETAIN(identifier);
|
|
||||||
[self _resetCalendar];
|
[self _resetCalendar];
|
||||||
}
|
}
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation NSCalendar
|
- (void) _defaultsDidChange: (NSNotification*)n
|
||||||
|
|
||||||
static NSCalendar *autoupdatingCalendar = nil;
|
|
||||||
static NSRecursiveLock *classLock = nil;
|
|
||||||
|
|
||||||
+ (void) initialize
|
|
||||||
{
|
|
||||||
if (self == [NSLocale class])
|
|
||||||
classLock = [NSRecursiveLock new];
|
|
||||||
}
|
|
||||||
|
|
||||||
+ (void) defaultsDidChange: (NSNotification*)n
|
|
||||||
{
|
{
|
||||||
NSUserDefaults *defs;
|
NSUserDefaults *defs;
|
||||||
NSString *locale;
|
NSString *locale;
|
||||||
|
@ -211,105 +231,87 @@ static NSRecursiveLock *classLock = nil;
|
||||||
calendar = [defs stringForKey: @"Calendar"];
|
calendar = [defs stringForKey: @"Calendar"];
|
||||||
tz = [defs stringForKey: @"Local Time Zone"];
|
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];
|
[classLock lock];
|
||||||
RELEASE(aac->localeID);
|
if ([locale isEqual: my->localeID] == NO
|
||||||
RELEASE(aac->identifier);
|
|| [calendar isEqual: my->identifier] == NO
|
||||||
RELEASE(aac->tz);
|
|| [tz isEqual: [my->tz name]] == NO)
|
||||||
|
{
|
||||||
#if GS_USE_ICU == 1
|
#if GS_USE_ICU == 1
|
||||||
ucal_close(aac->cal);
|
ucal_close(my->cal);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
aac->localeID = RETAIN(locale);
|
ASSIGN(my->localeID, locale);
|
||||||
aac->identifier = RETAIN(calendar);
|
ASSIGN(my->identifier, calendar);
|
||||||
aac->tz = [[NSTimeZone alloc] initWithName: tz];
|
RELEASE(my->tz);
|
||||||
|
my->tz = [[NSTimeZone alloc] initWithName: tz];
|
||||||
|
|
||||||
[autoupdatingCalendar _resetCalendar];
|
[self _resetCalendar];
|
||||||
|
}
|
||||||
[classLock unlock];
|
[classLock unlock];
|
||||||
}
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation NSCalendar
|
||||||
|
|
||||||
|
+ (void) initialize
|
||||||
|
{
|
||||||
|
if (self == [NSCalendar class])
|
||||||
|
{
|
||||||
|
classLock = [NSRecursiveLock new];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id) currentCalendar
|
+ (id) currentCalendar
|
||||||
{
|
{
|
||||||
NSCalendar *result;
|
NSCalendar *result;
|
||||||
NSLocale *locale;
|
NSString *identifier;
|
||||||
NSCalendar *cal;
|
|
||||||
|
|
||||||
locale = [NSLocale currentLocale];
|
// This identifier may be nil
|
||||||
cal = [locale objectForKey: NSLocaleCalendar];
|
identifier = [[NSLocale currentLocale] objectForKey: NSLocaleCalendarIdentifier];
|
||||||
result =
|
result = [[NSCalendar alloc] initWithCalendarIdentifier: identifier];
|
||||||
[[NSCalendar alloc] initWithCalendarIdentifier: [cal calendarIdentifier]];
|
|
||||||
|
|
||||||
return AUTORELEASE(result);
|
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
|
- (id) init
|
||||||
{
|
{
|
||||||
self = [self initWithCalendarIdentifier: nil];
|
return [self initWithCalendarIdentifier: nil];
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id) calendarWithIdentifier: (NSString *) string
|
- (id) initWithCalendarIdentifier: (NSString *) identifier
|
||||||
{
|
|
||||||
return [[[self alloc] initWithCalendarIdentifier: string] autorelease];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (id) initWithCalendarIdentifier: (NSString *) string
|
|
||||||
{
|
{
|
||||||
NSAssert(0 == _NSCalendarInternal, NSInvalidArgumentException);
|
NSAssert(0 == _NSCalendarInternal, NSInvalidArgumentException);
|
||||||
_NSCalendarInternal =
|
_NSCalendarInternal = NSZoneCalloc([self zone], sizeof(Calendar), 1);
|
||||||
NSZoneCalloc([self zone], sizeof(Calendar), 1);
|
|
||||||
|
|
||||||
my->firstWeekday = NSNotFound;
|
my->firstWeekday = NSNotFound;
|
||||||
my->minimumDaysInFirstWeek = 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;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,37 +344,71 @@ static NSRecursiveLock *classLock = nil;
|
||||||
UErrorCode err = U_ZERO_ERROR;
|
UErrorCode err = U_ZERO_ERROR;
|
||||||
UDate udate;
|
UDate udate;
|
||||||
|
|
||||||
udate = (UDate)floor([date timeIntervalSince1970] * 1000.0);
|
udate = (UDate)floor([date timeIntervalSince1970] * SECOND_TO_MILLI);
|
||||||
ucal_setMillis(my->cal, udate, &err);
|
ucal_setMillis(my->cal, udate, &err);
|
||||||
if (U_FAILURE(err))
|
if (U_FAILURE(err))
|
||||||
|
{
|
||||||
return nil;
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
comps = [[NSDateComponents alloc] init];
|
comps = [[NSDateComponents alloc] init];
|
||||||
if (unitFlags & NSEraCalendarUnit)
|
if (unitFlags & NSCalendarUnitEra)
|
||||||
|
{
|
||||||
[comps setEra: ucal_get(my->cal, UCAL_ERA, &err)];
|
[comps setEra: ucal_get(my->cal, UCAL_ERA, &err)];
|
||||||
if (unitFlags & NSYearCalendarUnit)
|
}
|
||||||
|
if (unitFlags & NSCalendarUnitYear)
|
||||||
|
{
|
||||||
[comps setYear: ucal_get(my->cal, UCAL_YEAR, &err)];
|
[comps setYear: ucal_get(my->cal, UCAL_YEAR, &err)];
|
||||||
if (unitFlags & NSMonthCalendarUnit)
|
}
|
||||||
|
if (unitFlags & NSCalendarUnitMonth)
|
||||||
|
{
|
||||||
[comps setMonth: ucal_get(my->cal, UCAL_MONTH, &err) + 1];
|
[comps setMonth: ucal_get(my->cal, UCAL_MONTH, &err) + 1];
|
||||||
if (unitFlags & NSDayCalendarUnit)
|
}
|
||||||
|
if (unitFlags & NSCalendarUnitDay)
|
||||||
|
{
|
||||||
[comps setDay: ucal_get(my->cal, UCAL_DAY_OF_MONTH, &err)];
|
[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)];
|
[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)];
|
[comps setMinute: ucal_get(my->cal, UCAL_MINUTE, &err)];
|
||||||
if (unitFlags & NSSecondCalendarUnit)
|
}
|
||||||
|
if (unitFlags & NSCalendarUnitSecond)
|
||||||
|
{
|
||||||
[comps setSecond: ucal_get(my->cal, UCAL_SECOND, &err)];
|
[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)];
|
[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)];
|
[comps setWeekday: ucal_get(my->cal, UCAL_DAY_OF_WEEK, &err)];
|
||||||
if (unitFlags & NSWeekdayOrdinalCalendarUnit)
|
}
|
||||||
|
if (unitFlags & NSCalendarUnitWeekdayOrdinal)
|
||||||
|
{
|
||||||
[comps setWeekdayOrdinal:
|
[comps setWeekdayOrdinal:
|
||||||
ucal_get(my->cal, UCAL_DAY_OF_WEEK_IN_MONTH, &err)];
|
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)];
|
[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)];
|
[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);
|
return AUTORELEASE(comps);
|
||||||
#else
|
#else
|
||||||
|
@ -413,8 +449,8 @@ do \
|
||||||
|
|
||||||
NSDateComponents *comps = nil;
|
NSDateComponents *comps = nil;
|
||||||
UErrorCode err = U_ZERO_ERROR;
|
UErrorCode err = U_ZERO_ERROR;
|
||||||
UDate udateFrom = (UDate)floor([startingDate timeIntervalSince1970] * 1000.0);
|
UDate udateFrom = (UDate)floor([startingDate timeIntervalSince1970] * SECOND_TO_MILLI);
|
||||||
UDate udateTo = (UDate)floor([resultDate timeIntervalSince1970] * 1000.0);
|
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))
|
if (U_FAILURE(err))
|
||||||
|
@ -428,14 +464,14 @@ do \
|
||||||
* the largest to the smallest.
|
* the largest to the smallest.
|
||||||
*/
|
*/
|
||||||
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
||||||
NSEraCalendarUnit, setEra:, UCAL_ERA, err);
|
NSCalendarUnitEra, setEra:, UCAL_ERA, err);
|
||||||
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
||||||
NSYearCalendarUnit, setYear:, UCAL_YEAR, err);
|
NSCalendarUnitYear, setYear:, UCAL_YEAR, err);
|
||||||
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
||||||
NSMonthCalendarUnit, setMonth:, UCAL_MONTH, err);
|
NSCalendarUnitMonth, setMonth:, UCAL_MONTH, err);
|
||||||
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
||||||
NSWeekOfYearCalendarUnit, setWeek:, UCAL_WEEK_OF_YEAR, err);
|
NSCalendarUnitWeekOfYear, setWeek:, UCAL_WEEK_OF_YEAR, err);
|
||||||
if (!(unitFlags & NSWeekOfYearCalendarUnit))
|
if (!(unitFlags & NSCalendarUnitWeekOfYear))
|
||||||
{
|
{
|
||||||
/* We must avoid setting the same unit twice (it would be zero because
|
/* We must avoid setting the same unit twice (it would be zero because
|
||||||
* of the automatic advancement.
|
* of the automatic advancement.
|
||||||
|
@ -444,35 +480,33 @@ do \
|
||||||
NSWeekCalendarUnit, setWeek:, UCAL_WEEK_OF_YEAR, err);
|
NSWeekCalendarUnit, setWeek:, UCAL_WEEK_OF_YEAR, err);
|
||||||
}
|
}
|
||||||
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
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,
|
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,
|
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
||||||
NSWeekdayOrdinalCalendarUnit, setWeekdayOrdinal:,
|
NSCalendarUnitWeekdayOrdinal, setWeekdayOrdinal:,
|
||||||
UCAL_DAY_OF_WEEK_IN_MONTH, err);
|
UCAL_DAY_OF_WEEK_IN_MONTH, err);
|
||||||
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
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,
|
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,
|
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
||||||
NSMinuteCalendarUnit, setMinute:, UCAL_MINUTE, err);
|
NSCalendarUnitMinute, setMinute:, UCAL_MINUTE, err);
|
||||||
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
COMPONENT_DIFF(my->cal, unitFlags, comps, udateTo,
|
||||||
NSSecondCalendarUnit, setSecond:, UCAL_SECOND, err);
|
NSCalendarUnitSecond, setSecond:, UCAL_SECOND, err);
|
||||||
# if 0
|
|
||||||
if (unitFlags & NSCalendarUnitNanosecond)
|
if (unitFlags & NSCalendarUnitNanosecond)
|
||||||
{
|
{
|
||||||
int32_t ns;
|
int32_t ms;
|
||||||
|
|
||||||
ns = ucal_getFieldDifference(my->cal, udateTo, UCAL_MILLISECOND, &err)
|
ms = ucal_getFieldDifference(my->cal, udateTo, UCAL_MILLISECOND, &err);
|
||||||
* 1000000;
|
|
||||||
if (U_FAILURE(err))
|
if (U_FAILURE(err))
|
||||||
{
|
{
|
||||||
RELEASE(comps);
|
RELEASE(comps);
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
[comps setNanosecond: ns];
|
[comps setNanosecond: ms * MILLI_TO_NANO];
|
||||||
}
|
}
|
||||||
# endif
|
|
||||||
return AUTORELEASE(comps);
|
return AUTORELEASE(comps);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -480,6 +514,18 @@ do \
|
||||||
#endif
|
#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
|
- (NSDate *) dateByAddingComponents: (NSDateComponents *) comps
|
||||||
toDate: (NSDate *) date
|
toDate: (NSDate *) date
|
||||||
options: (NSUInteger) opts
|
options: (NSUInteger) opts
|
||||||
|
@ -490,14 +536,9 @@ do \
|
||||||
UDate udate;
|
UDate udate;
|
||||||
|
|
||||||
[self _resetCalendar];
|
[self _resetCalendar];
|
||||||
udate = (UDate)([date timeIntervalSince1970] * 1000.0);
|
udate = (UDate)([date timeIntervalSince1970] * SECOND_TO_MILLI);
|
||||||
ucal_setMillis(my->cal, udate, &err);
|
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)
|
if ((amount = [comps era]) != NSDateComponentUndefined)
|
||||||
{
|
{
|
||||||
_ADD_COMPONENT(UCAL_ERA, (int32_t)amount);
|
_ADD_COMPONENT(UCAL_ERA, (int32_t)amount);
|
||||||
|
@ -542,78 +583,107 @@ do \
|
||||||
{
|
{
|
||||||
_ADD_COMPONENT(UCAL_YEAR_WOY, (int32_t)amount);
|
_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))
|
if (U_FAILURE(err))
|
||||||
|
{
|
||||||
return nil;
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
return [NSDate dateWithTimeIntervalSince1970: (udate / 1000.0)];
|
return [NSDate dateWithTimeIntervalSince1970: (udate / SECOND_TO_MILLI)];
|
||||||
#else
|
#else
|
||||||
return nil;
|
return nil;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef _ADD_COMPONENT
|
||||||
|
|
||||||
- (NSDate *) dateFromComponents: (NSDateComponents *) comps
|
- (NSDate *) dateFromComponents: (NSDateComponents *) comps
|
||||||
{
|
{
|
||||||
#if GS_USE_ICU == 1
|
#if GS_USE_ICU == 1
|
||||||
NSInteger amount;
|
NSInteger amount;
|
||||||
UDate udate;
|
UDate udate;
|
||||||
UErrorCode err = U_ZERO_ERROR;
|
UErrorCode err = U_ZERO_ERROR;
|
||||||
|
void *cal;
|
||||||
|
NSTimeZone *timeZone;
|
||||||
|
|
||||||
[self _resetCalendar];
|
timeZone = [comps timeZone];
|
||||||
ucal_clear (my->cal);
|
if (timeZone == nil)
|
||||||
|
{
|
||||||
|
timeZone = [self timeZone];
|
||||||
|
}
|
||||||
|
cal = [self _openCalendarFor: timeZone];
|
||||||
|
if (!cal)
|
||||||
|
{
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
ucal_clear(cal);
|
||||||
|
|
||||||
if ((amount = [comps era]) != NSDateComponentUndefined)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
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))
|
if (U_FAILURE(err))
|
||||||
|
{
|
||||||
return nil;
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
return [NSDate dateWithTimeIntervalSince1970: (udate / 1000.0)];
|
return [NSDate dateWithTimeIntervalSince1970: (udate / SECOND_TO_MILLI)];
|
||||||
#else
|
#else
|
||||||
return nil;
|
return nil;
|
||||||
#endif
|
#endif
|
||||||
|
@ -626,6 +696,8 @@ do \
|
||||||
|
|
||||||
- (void) setLocale: (NSLocale *) locale
|
- (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]];
|
[self _setLocaleIdentifier: [self _localeIDWithLocale: locale]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,23 +736,25 @@ do \
|
||||||
- (void) setTimeZone: (NSTimeZone *) tz
|
- (void) setTimeZone: (NSTimeZone *) tz
|
||||||
{
|
{
|
||||||
if ([tz isEqual: my->tz])
|
if ([tz isEqual: my->tz])
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
RELEASE(my->tz);
|
ASSIGN(my->tz, tz);
|
||||||
my->tz = RETAIN(tz);
|
|
||||||
[self _resetCalendar];
|
[self _resetCalendar];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSRange) maximumRangeOfUnit: (NSCalendarUnit) unit
|
- (NSRange) maximumRangeOfUnit: (NSCalendarUnit) unit
|
||||||
{
|
{
|
||||||
|
NSRange result = NSMakeRange (0, 0);
|
||||||
#if GS_USE_ICU == 1
|
#if GS_USE_ICU == 1
|
||||||
UCalendarDateFields dateField;
|
UCalendarDateFields dateField;
|
||||||
NSRange result;
|
|
||||||
UErrorCode err = U_ZERO_ERROR;
|
UErrorCode err = U_ZERO_ERROR;
|
||||||
|
|
||||||
[self _resetCalendar];
|
[self _resetCalendar];
|
||||||
dateField = _NSCalendarUnitToDateField(unit);
|
dateField = _NSCalendarUnitToDateField(unit);
|
||||||
|
if (dateField != -1)
|
||||||
|
{
|
||||||
// We really don't care if there are any errors...
|
// We really don't care if there are any errors...
|
||||||
result.location =
|
result.location =
|
||||||
(NSUInteger)ucal_getLimit(my->cal, dateField, UCAL_MINIMUM, &err);
|
(NSUInteger)ucal_getLimit(my->cal, dateField, UCAL_MINIMUM, &err);
|
||||||
|
@ -689,23 +763,26 @@ do \
|
||||||
- result.location + 1;
|
- result.location + 1;
|
||||||
// ICU's month is 0-based, while NSCalendar is 1-based
|
// ICU's month is 0-based, while NSCalendar is 1-based
|
||||||
if (dateField == UCAL_MONTH)
|
if (dateField == UCAL_MONTH)
|
||||||
|
{
|
||||||
result.location += 1;
|
result.location += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
#else
|
|
||||||
return NSMakeRange (0, 0);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSRange) minimumRangeofUnit: (NSCalendarUnit) unit
|
- (NSRange) minimumRangeofUnit: (NSCalendarUnit) unit
|
||||||
{
|
{
|
||||||
|
NSRange result = NSMakeRange (0, 0);
|
||||||
#if GS_USE_ICU == 1
|
#if GS_USE_ICU == 1
|
||||||
UCalendarDateFields dateField;
|
UCalendarDateFields dateField;
|
||||||
NSRange result;
|
|
||||||
UErrorCode err = U_ZERO_ERROR;
|
UErrorCode err = U_ZERO_ERROR;
|
||||||
|
|
||||||
[self _resetCalendar];
|
[self _resetCalendar];
|
||||||
dateField = _NSCalendarUnitToDateField(unit);
|
dateField = _NSCalendarUnitToDateField(unit);
|
||||||
|
if (dateField != -1)
|
||||||
|
{
|
||||||
// We really don't care if there are any errors...
|
// We really don't care if there are any errors...
|
||||||
result.location =
|
result.location =
|
||||||
(NSUInteger)ucal_getLimit(my->cal, dateField, UCAL_GREATEST_MINIMUM, &err);
|
(NSUInteger)ucal_getLimit(my->cal, dateField, UCAL_GREATEST_MINIMUM, &err);
|
||||||
|
@ -714,12 +791,12 @@ do \
|
||||||
- result.location + 1;
|
- result.location + 1;
|
||||||
// ICU's month is 0-based, while NSCalendar is 1-based
|
// ICU's month is 0-based, while NSCalendar is 1-based
|
||||||
if (dateField == UCAL_MONTH)
|
if (dateField == UCAL_MONTH)
|
||||||
|
{
|
||||||
result.location += 1;
|
result.location += 1;
|
||||||
|
}
|
||||||
return result;
|
}
|
||||||
#else
|
|
||||||
return NSMakeRange (0, 0);
|
|
||||||
#endif
|
#endif
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSUInteger) ordinalityOfUnit: (NSCalendarUnit) smaller
|
- (NSUInteger) ordinalityOfUnit: (NSCalendarUnit) smaller
|
||||||
|
@ -736,27 +813,6 @@ do \
|
||||||
return NSMakeRange (0, 0);
|
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
|
- (BOOL) rangeOfUnit: (NSCalendarUnit) unit
|
||||||
startDate: (NSDate **) datep
|
startDate: (NSDate **) datep
|
||||||
interval: (NSTimeInterval *)tip
|
interval: (NSTimeInterval *)tip
|
||||||
|
@ -778,6 +834,10 @@ do \
|
||||||
return NO;
|
return NO;
|
||||||
if (![my->tz isEqual: [obj timeZone]])
|
if (![my->tz isEqual: [obj timeZone]])
|
||||||
return NO;
|
return NO;
|
||||||
|
if (my->firstWeekday != [obj firstWeekday])
|
||||||
|
return NO;
|
||||||
|
if (my->minimumDaysInFirstWeek != [obj minimumDaysInFirstWeek])
|
||||||
|
return NO;
|
||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -843,6 +903,8 @@ typedef struct {
|
||||||
NSInteger quarter;
|
NSInteger quarter;
|
||||||
NSInteger weekOfMonth;
|
NSInteger weekOfMonth;
|
||||||
NSInteger yearForWeekOfYear;
|
NSInteger yearForWeekOfYear;
|
||||||
|
BOOL leapMonth;
|
||||||
|
NSInteger nanosecond;
|
||||||
NSCalendar *cal;
|
NSCalendar *cal;
|
||||||
NSTimeZone *tz;
|
NSTimeZone *tz;
|
||||||
} DateComp;
|
} DateComp;
|
||||||
|
@ -880,6 +942,8 @@ typedef struct {
|
||||||
my->quarter = NSDateComponentUndefined;
|
my->quarter = NSDateComponentUndefined;
|
||||||
my->weekOfMonth = NSDateComponentUndefined;
|
my->weekOfMonth = NSDateComponentUndefined;
|
||||||
my->yearForWeekOfYear = NSDateComponentUndefined;
|
my->yearForWeekOfYear = NSDateComponentUndefined;
|
||||||
|
my->leapMonth = NO;
|
||||||
|
my->nanosecond = NSDateComponentUndefined;
|
||||||
my->cal = NULL;
|
my->cal = NULL;
|
||||||
my->tz = NULL;
|
my->tz = NULL;
|
||||||
}
|
}
|
||||||
|
@ -921,6 +985,11 @@ typedef struct {
|
||||||
return my->second;
|
return my->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSInteger) nanosecond
|
||||||
|
{
|
||||||
|
return my->nanosecond;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSInteger) week
|
- (NSInteger) week
|
||||||
{
|
{
|
||||||
return my->week;
|
return my->week;
|
||||||
|
@ -956,6 +1025,11 @@ typedef struct {
|
||||||
return my->yearForWeekOfYear;
|
return my->yearForWeekOfYear;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (BOOL) leapMonth
|
||||||
|
{
|
||||||
|
return my->leapMonth;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSCalendar *) calendar
|
- (NSCalendar *) calendar
|
||||||
{
|
{
|
||||||
return my->cal;
|
return my->cal;
|
||||||
|
@ -969,10 +1043,6 @@ typedef struct {
|
||||||
- (NSDate *) date
|
- (NSDate *) date
|
||||||
{
|
{
|
||||||
NSCalendar* cal = [self calendar];
|
NSCalendar* cal = [self calendar];
|
||||||
NSTimeZone* zone = [self timeZone];
|
|
||||||
|
|
||||||
if (zone != NULL)
|
|
||||||
[cal setTimeZone: zone];
|
|
||||||
|
|
||||||
return [cal dateFromComponents: self];
|
return [cal dateFromComponents: self];
|
||||||
}
|
}
|
||||||
|
@ -1013,6 +1083,11 @@ typedef struct {
|
||||||
my->second = v;
|
my->second = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) setNanosecond: (NSInteger) v
|
||||||
|
{
|
||||||
|
my->nanosecond = v;
|
||||||
|
}
|
||||||
|
|
||||||
- (void) setWeek: (NSInteger) v
|
- (void) setWeek: (NSInteger) v
|
||||||
{
|
{
|
||||||
my->week = v;
|
my->week = v;
|
||||||
|
@ -1048,6 +1123,11 @@ typedef struct {
|
||||||
my->yearForWeekOfYear = v;
|
my->yearForWeekOfYear = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) setLeapMonth: (BOOL) v
|
||||||
|
{
|
||||||
|
my->leapMonth = v;
|
||||||
|
}
|
||||||
|
|
||||||
- (void) setCalendar: (NSCalendar *) cal
|
- (void) setCalendar: (NSCalendar *) cal
|
||||||
{
|
{
|
||||||
ASSIGN(my->cal, cal);
|
ASSIGN(my->cal, cal);
|
||||||
|
@ -1058,6 +1138,98 @@ typedef struct {
|
||||||
ASSIGN(my->tz, tz);
|
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
|
- (id) copyWithZone: (NSZone*)zone
|
||||||
{
|
{
|
||||||
if (NSShouldRetainWithZone(self, zone))
|
if (NSShouldRetainWithZone(self, zone))
|
||||||
|
|
|
@ -468,10 +468,15 @@ parseNumber(ParserState *state)
|
||||||
{\
|
{\
|
||||||
bufferSize *= 2;\
|
bufferSize *= 2;\
|
||||||
if (number == numberBuffer)\
|
if (number == numberBuffer)\
|
||||||
|
{\
|
||||||
number = malloc(bufferSize);\
|
number = malloc(bufferSize);\
|
||||||
|
memcpy(number, numberBuffer, sizeof(numberBuffer));\
|
||||||
|
}\
|
||||||
else\
|
else\
|
||||||
|
{\
|
||||||
number = realloc(number, bufferSize);\
|
number = realloc(number, bufferSize);\
|
||||||
}\
|
}\
|
||||||
|
}\
|
||||||
number[parsedSize++] = (char)x; } while (0)
|
number[parsedSize++] = (char)x; } while (0)
|
||||||
// JSON numbers must start with a - or a digit
|
// JSON numbers must start with a - or a digit
|
||||||
if (!(c == '-' || isdigit(c)))
|
if (!(c == '-' || isdigit(c)))
|
||||||
|
|
|
@ -627,6 +627,11 @@ static NSRecursiveLock *classLock = nil;
|
||||||
[[dict objectForKey: NSLocaleCollationIdentifier] UTF8String];
|
[[dict objectForKey: NSLocaleCollationIdentifier] UTF8String];
|
||||||
const char *currency = [[dict objectForKey: NSLocaleCurrencyCode] UTF8String];
|
const char *currency = [[dict objectForKey: NSLocaleCurrencyCode] UTF8String];
|
||||||
|
|
||||||
|
if (!calendar)
|
||||||
|
{
|
||||||
|
calendar = [[dict objectForKey: NSLocaleCalendarIdentifier] UTF8String];
|
||||||
|
}
|
||||||
|
|
||||||
// A locale cannot be constructed without a language.
|
// A locale cannot be constructed without a language.
|
||||||
if (language == NULL)
|
if (language == NULL)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
|
@ -1901,7 +1901,8 @@ GSICUCollatorOpen(NSStringCompareOptions mask, NSLocale *locale)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *) stringByAddingPercentEncodingWithAllowedCharacters: (NSCharacterSet *)aSet
|
- (NSString *) stringByAddingPercentEncodingWithAllowedCharacters:
|
||||||
|
(NSCharacterSet *)aSet
|
||||||
{
|
{
|
||||||
NSData *data = [self dataUsingEncoding: NSUTF8StringEncoding];
|
NSData *data = [self dataUsingEncoding: NSUTF8StringEncoding];
|
||||||
NSString *s = nil;
|
NSString *s = nil;
|
||||||
|
@ -1921,7 +1922,10 @@ GSICUCollatorOpen(NSStringCompareOptions mask, NSLocale *locale)
|
||||||
unsigned int hi;
|
unsigned int hi;
|
||||||
unsigned int lo;
|
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;
|
dst[dpos++] = c;
|
||||||
}
|
}
|
||||||
|
@ -1936,7 +1940,7 @@ GSICUCollatorOpen(NSStringCompareOptions mask, NSLocale *locale)
|
||||||
}
|
}
|
||||||
s = [[NSString alloc] initWithBytes: dst
|
s = [[NSString alloc] initWithBytes: dst
|
||||||
length: dpos
|
length: dpos
|
||||||
encoding: NSUTF8StringEncoding];
|
encoding: NSASCIIStringEncoding];
|
||||||
NSZoneFree(NSDefaultMallocZone(), dst);
|
NSZoneFree(NSDefaultMallocZone(), dst);
|
||||||
IF_NO_GC([s autorelease];)
|
IF_NO_GC([s autorelease];)
|
||||||
}
|
}
|
||||||
|
@ -1963,7 +1967,7 @@ GSICUCollatorOpen(NSStringCompareOptions mask, NSLocale *locale)
|
||||||
uint8_t hi = s[index+1];
|
uint8_t hi = s[index+1];
|
||||||
uint8_t lo = s[index+2];
|
uint8_t lo = s[index+2];
|
||||||
|
|
||||||
if (isdigit(hi) && isxdigit(lo))
|
if (isxdigit(hi) && isxdigit(lo))
|
||||||
{
|
{
|
||||||
index += 2;
|
index += 2;
|
||||||
if (hi <= '9')
|
if (hi <= '9')
|
||||||
|
|
|
@ -51,6 +51,9 @@ TOP_DIR := $(shell dirname $(CURDIR))
|
||||||
all::
|
all::
|
||||||
@(echo If you want to run the gnustep-base testsuite, please type \'${MAKE} check\')
|
@(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)
|
# 'make check' runs the testsuite (Objective-C tests only)
|
||||||
#
|
#
|
||||||
|
@ -72,9 +75,9 @@ check::
|
||||||
export LD_LIBRARY_PATH;\
|
export LD_LIBRARY_PATH;\
|
||||||
export PATH;\
|
export PATH;\
|
||||||
if [ "$(debug)" = "yes" ]; then \
|
if [ "$(debug)" = "yes" ]; then \
|
||||||
gnustep-tests --debug base;\
|
gnustep-tests --debug 'base/$(testobj)';\
|
||||||
else \
|
else \
|
||||||
gnustep-tests base;\
|
gnustep-tests 'base/$(testobj)';\
|
||||||
fi; \
|
fi; \
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ int main()
|
||||||
NSCalendar *cal;
|
NSCalendar *cal;
|
||||||
NSDate *date;
|
NSDate *date;
|
||||||
NSDate *date2;
|
NSDate *date2;
|
||||||
|
NSDate *date3;
|
||||||
|
NSDate *date4;
|
||||||
|
|
||||||
START_SET("NSCalendar 10.7 features")
|
START_SET("NSCalendar 10.7 features")
|
||||||
if (!NSCALENDAR_SUPPORTED)
|
if (!NSCALENDAR_SUPPORTED)
|
||||||
|
@ -49,6 +51,12 @@ int main()
|
||||||
|
|
||||||
PASS_EQUAL(date, date2, "-[NSDateComponents date] returns the correct date");
|
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(comps);
|
||||||
RELEASE(cal);
|
RELEASE(cal);
|
||||||
|
|
||||||
|
|
|
@ -3,55 +3,93 @@
|
||||||
#import <Foundation/NSString.h>
|
#import <Foundation/NSString.h>
|
||||||
#import <Foundation/NSCharacterSet.h>
|
#import <Foundation/NSCharacterSet.h>
|
||||||
|
|
||||||
BOOL testUrlCharacterSetEncoding(
|
void testEncodeDecode(NSString* encoded, NSString* decoded, NSCharacterSet* charset, NSString* description){
|
||||||
NSString* decodedString,
|
|
||||||
NSString* encodedString,
|
NSString* encodeTest = [decoded stringByAddingPercentEncodingWithAllowedCharacters:charset];
|
||||||
NSCharacterSet* allowedCharacterSet)
|
NSString* decodeTest = [encoded stringByRemovingPercentEncoding];
|
||||||
{
|
|
||||||
NSString *testString
|
const char* encodeMsg = [[NSString stringWithFormat:@"Percent-Encode: %@", description] UTF8String];
|
||||||
= [decodedString stringByAddingPercentEncodingWithAllowedCharacters:
|
const char* decodeMsg = [[NSString stringWithFormat:@"Percent-Decode: %@", description] UTF8String];
|
||||||
allowedCharacterSet];
|
|
||||||
// NSLog(@"String by adding percent, done. test=%@ decoded=%@", testString, decodedString);
|
PASS_EQUAL(encodeTest, encoded, "%s", encodeMsg);
|
||||||
return [encodedString isEqualToString: testString];
|
PASS_EQUAL(decodeTest, decoded, "%s", decodeMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (int argc, const char * argv[])
|
int main (int argc, const char * argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
|
||||||
|
|
||||||
|
|
||||||
NSString *urlDecodedString = @"Only alphabetic characters should be allowed and not encoded. !@#$%^&*()_+-=";
|
NSString *urlDecodedString = @"Only alphabetic characters should be allowed and not encoded. !@#$%^&*()_+-=";
|
||||||
NSString *urlEncodedString =
|
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";
|
||||||
@"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],
|
||||||
NSCharacterSet *allowedCharacterSet = [NSCharacterSet alphanumericCharacterSet];
|
@"Skip alphanumericCharacterSet 01");
|
||||||
PASS(testUrlCharacterSetEncoding(urlDecodedString, urlEncodedString, allowedCharacterSet), "alphanumericCharacterSet");
|
|
||||||
|
|
||||||
urlDecodedString = @"https://www.microsoft.com/en-us/!@#$%^&*()_";
|
urlDecodedString = @"https://www.microsoft.com/en-us/!@#$%^&*()_";
|
||||||
urlEncodedString = @"https://www.microsoft.com/en-us/!@%23$%25%5E&*()_";
|
urlEncodedString = @"https://www.microsoft.com/en-us/!@%23$%25%5E&*()_";
|
||||||
allowedCharacterSet = [NSCharacterSet URLFragmentAllowedCharacterSet];
|
testEncodeDecode(urlEncodedString, urlDecodedString, [NSCharacterSet URLFragmentAllowedCharacterSet],
|
||||||
PASS(testUrlCharacterSetEncoding(urlDecodedString, urlEncodedString, allowedCharacterSet), "fragmentCharacterSet");
|
@"Skip URLFragmentAllowedCharacterSet 02");
|
||||||
|
|
||||||
|
|
||||||
urlDecodedString = @"All alphabetic characters should be encoded. Symbols should not be: !@#$%^&*()_+-=";
|
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 "
|
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: !@#$%^&*()_+-=";
|
@"%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];
|
testEncodeDecode(urlEncodedString, urlDecodedString, [[NSCharacterSet alphanumericCharacterSet] invertedSet],
|
||||||
PASS(testUrlCharacterSetEncoding(urlDecodedString, urlEncodedString, allowedCharacterSet), "inverted");
|
@"Skip not alphanumericCharacterSet 03");
|
||||||
|
|
||||||
|
|
||||||
urlDecodedString = @"Here are some Emojis: \U0001F601 \U0001F602 \U0001F638 Emojis done."; // Multibyte encoded characters
|
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.";
|
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];
|
testEncodeDecode(urlEncodedString, urlDecodedString, [NSCharacterSet URLFragmentAllowedCharacterSet],
|
||||||
PASS(testUrlCharacterSetEncoding(urlDecodedString, urlEncodedString, allowedCharacterSet), "fragmentCharacterSet emojis");
|
@"Skip URLFragmentAllowedCharacterSet 04");
|
||||||
|
|
||||||
|
|
||||||
urlDecodedString = @"\1";
|
urlDecodedString = @"\1";
|
||||||
urlEncodedString = @"%01";
|
urlEncodedString = @"%01";
|
||||||
allowedCharacterSet = [NSCharacterSet alphanumericCharacterSet];
|
testEncodeDecode(urlEncodedString, urlDecodedString, [NSCharacterSet alphanumericCharacterSet],
|
||||||
PASS(testUrlCharacterSetEncoding(urlDecodedString, urlEncodedString, allowedCharacterSet), "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];
|
[pool drain];
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue