Properly escape some control chars (and generalized it)

pull/17/head
Ludovic Marcotte 2014-02-04 15:03:02 -05:00
parent 2ff3b5ef5f
commit 31969d162d
10 changed files with 70 additions and 48 deletions

View File

@ -54,16 +54,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
n = [self n]; n = [self n];
if ((o = [n flattenedValueAtIndex: 0 forKey: @""])) if ((o = [n flattenedValueAtIndex: 0 forKey: @""]))
[s appendFormat: @"<LastName xmlns=\"Contacts:\">%@</LastName>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<LastName xmlns=\"Contacts:\">%@</LastName>", [o activeSyncRepresentation]];
if ((o = [n flattenedValueAtIndex: 1 forKey: @""])) if ((o = [n flattenedValueAtIndex: 1 forKey: @""]))
[s appendFormat: @"<FirstName xmlns=\"Contacts:\">%@</FirstName>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<FirstName xmlns=\"Contacts:\">%@</FirstName>", [o activeSyncRepresentation]];
if ((o = [self workCompany])) if ((o = [self workCompany]))
[s appendFormat: @"<CompanyName xmlns=\"Contacts:\">%@</CompanyName>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<CompanyName xmlns=\"Contacts:\">%@</CompanyName>", [o activeSyncRepresentation]];
if ((o = [self title])) if ((o = [self title]))
[s appendFormat: @"<JobTitle xmlns=\"Contacts:\">%@</JobTitle>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<JobTitle xmlns=\"Contacts:\">%@</JobTitle>", [o activeSyncRepresentation]];
if ((o = [self preferredEMail])) if ((o = [self preferredEMail]))
[s appendFormat: @"<Email1Address xmlns=\"Contacts:\">%@</Email1Address>", o]; [s appendFormat: @"<Email1Address xmlns=\"Contacts:\">%@</Email1Address>", o];
@ -84,19 +84,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Telephone numbers // Telephone numbers
if ((o = [self workPhone]) && [o length]) if ((o = [self workPhone]) && [o length])
[s appendFormat: @"<BusinessPhoneNumber xmlns=\"Contacts:\">%@</BusinessPhoneNumber>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<BusinessPhoneNumber xmlns=\"Contacts:\">%@</BusinessPhoneNumber>", [o activeSyncRepresentation]];
if ((o = [self homePhone]) && [o length]) if ((o = [self homePhone]) && [o length])
[s appendFormat: @"<HomePhoneNumber xmlns=\"Contacts:\">%@</HomePhoneNumber>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<HomePhoneNumber xmlns=\"Contacts:\">%@</HomePhoneNumber>", [o activeSyncRepresentation]];
if ((o = [self fax]) && [o length]) if ((o = [self fax]) && [o length])
[s appendFormat: @"<BusinessFaxNumber xmlns=\"Contacts:\">%@</BusinessFaxNumber>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<BusinessFaxNumber xmlns=\"Contacts:\">%@</BusinessFaxNumber>", [o activeSyncRepresentation]];
if ((o = [self mobile]) && [o length]) if ((o = [self mobile]) && [o length])
[s appendFormat: @"<MobilePhoneNumber xmlns=\"Contacts:\">%@</MobilePhoneNumber>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<MobilePhoneNumber xmlns=\"Contacts:\">%@</MobilePhoneNumber>", [o activeSyncRepresentation]];
if ((o = [self pager]) && [o length]) if ((o = [self pager]) && [o length])
[s appendFormat: @"<PagerNumber xmlns=\"Contacts:\">%@</PagerNumber>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<PagerNumber xmlns=\"Contacts:\">%@</PagerNumber>", [o activeSyncRepresentation]];
// Home Address // Home Address
addresses = [self childrenWithTag: @"adr" addresses = [self childrenWithTag: @"adr"
@ -108,19 +108,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
homeAdr = [addresses objectAtIndex: 0]; homeAdr = [addresses objectAtIndex: 0];
if ((o = [homeAdr flattenedValueAtIndex: 2 forKey: @""])) if ((o = [homeAdr flattenedValueAtIndex: 2 forKey: @""]))
[s appendFormat: @"<HomeStreet xmlns=\"Contacts:\">%@</HomeStreet>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<HomeStreet xmlns=\"Contacts:\">%@</HomeStreet>", [o activeSyncRepresentation]];
if ((o = [homeAdr flattenedValueAtIndex: 3 forKey: @""])) if ((o = [homeAdr flattenedValueAtIndex: 3 forKey: @""]))
[s appendFormat: @"<HomeCity xmlns=\"Contacts:\">%@</HomeCity>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<HomeCity xmlns=\"Contacts:\">%@</HomeCity>", [o activeSyncRepresentation]];
if ((o = [homeAdr flattenedValueAtIndex: 4 forKey: @""])) if ((o = [homeAdr flattenedValueAtIndex: 4 forKey: @""]))
[s appendFormat: @"<HomeState xmlns=\"Contacts:\">%@</HomeState>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<HomeState xmlns=\"Contacts:\">%@</HomeState>", [o activeSyncRepresentation]];
if ((o = [homeAdr flattenedValueAtIndex: 5 forKey: @""])) if ((o = [homeAdr flattenedValueAtIndex: 5 forKey: @""]))
[s appendFormat: @"<HomePostalCode xmlns=\"Contacts:\">%@</HomePostalCode>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<HomePostalCode xmlns=\"Contacts:\">%@</HomePostalCode>", [o activeSyncRepresentation]];
if ((o = [homeAdr flattenedValueAtIndex: 6 forKey: @""])) if ((o = [homeAdr flattenedValueAtIndex: 6 forKey: @""]))
[s appendFormat: @"<HomeCountry xmlns=\"Contacts:\">%@</HomeCountry>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<HomeCountry xmlns=\"Contacts:\">%@</HomeCountry>", [o activeSyncRepresentation]];
} }
// Work Address // Work Address
@ -133,19 +133,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
workAdr = [addresses objectAtIndex: 0]; workAdr = [addresses objectAtIndex: 0];
if ((o = [workAdr flattenedValueAtIndex: 2 forKey: @""])) if ((o = [workAdr flattenedValueAtIndex: 2 forKey: @""]))
[s appendFormat: @"<BusinessStreet xmlns=\"Contacts:\">%@</BusinessStreet>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<BusinessStreet xmlns=\"Contacts:\">%@</BusinessStreet>", [o activeSyncRepresentation]];
if ((o = [workAdr flattenedValueAtIndex: 3 forKey: @""])) if ((o = [workAdr flattenedValueAtIndex: 3 forKey: @""]))
[s appendFormat: @"<BusinessCity xmlns=\"Contacts:\">%@</BusinessCity>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<BusinessCity xmlns=\"Contacts:\">%@</BusinessCity>", [o activeSyncRepresentation]];
if ((o = [workAdr flattenedValueAtIndex: 4 forKey: @""])) if ((o = [workAdr flattenedValueAtIndex: 4 forKey: @""]))
[s appendFormat: @"<BusinessState xmlns=\"Contacts:\">%@</BusinessState>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<BusinessState xmlns=\"Contacts:\">%@</BusinessState>", [o activeSyncRepresentation]];
if ((o = [workAdr flattenedValueAtIndex: 5 forKey: @""])) if ((o = [workAdr flattenedValueAtIndex: 5 forKey: @""]))
[s appendFormat: @"<BusinessPostalCode xmlns=\"Contacts:\">%@</BusinessPostalCode>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<BusinessPostalCode xmlns=\"Contacts:\">%@</BusinessPostalCode>", [o activeSyncRepresentation]];
if ((o = [workAdr flattenedValueAtIndex: 6 forKey: @""])) if ((o = [workAdr flattenedValueAtIndex: 6 forKey: @""]))
[s appendFormat: @"<BusinessCountry xmlns=\"Contacts:\">%@</BusinessCountry>", [o stringByEscapingHTMLString]]; [s appendFormat: @"<BusinessCountry xmlns=\"Contacts:\">%@</BusinessCountry>", [o activeSyncRepresentation]];
} }
// Other, less important fields // Other, less important fields
@ -154,7 +154,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if ((o = [self note])) if ((o = [self note]))
{ {
o = [o stringByEscapingHTMLString]; o = [o activeSyncRepresentation];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"]; [s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1]; [s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]]; [s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];

View File

@ -36,7 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <wbxml/wbxml_conv.h> #include <wbxml/wbxml_conv.h>
#include <wbxml/wbxml_errors.h> #include <wbxml/wbxml_errors.h>
#define WBXMLDEBUG 0 #define WBXMLDEBUG 1
@implementation NSData (ActiveSync) @implementation NSData (ActiveSync)

View File

@ -39,6 +39,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@interface NSString (ActiveSync) @interface NSString (ActiveSync)
- (NSString *) activeSyncRepresentation;
- (int) activeSyncFolderType; - (int) activeSyncFolderType;
- (NSString *) realCollectionIdWithFolderType: (SOGoMicrosoftActiveSyncFolderType *) folderType; - (NSString *) realCollectionIdWithFolderType: (SOGoMicrosoftActiveSyncFolderType *) folderType;
- (NSCalendarDate *) calendarDate; - (NSCalendarDate *) calendarDate;

View File

@ -34,10 +34,22 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <Foundation/NSData.h> #include <Foundation/NSData.h>
#include <Foundation/NSDate.h> #include <Foundation/NSDate.h>
#include <SOGo/NSString+Utilities.h>
#include <NGExtensions/NSString+misc.h> #include <NGExtensions/NSString+misc.h>
@implementation NSString (ActiveSync) @implementation NSString (ActiveSync)
- (NSString *) activeSyncRepresentation
{
NSString *s;
s = [self stringByEscapingHTMLString];
return [[s componentsSeparatedByCharactersInSet: [self safeCharacterSet]]
componentsJoinedByString: @""];
}
- (int) activeSyncFolderType - (int) activeSyncFolderType
{ {
if ([self isEqualToString: @"inbox"]) if ([self isEqualToString: @"inbox"])

View File

@ -508,26 +508,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[serverId stringByEscapingURL], [serverId stringByEscapingURL],
[parentId stringByEscapingURL], [parentId stringByEscapingURL],
type, type,
[name stringByEscapingHTMLString]]; [name activeSyncRepresentation]];
} }
// We add the personal calendar - events // We add the personal calendar - events
// FIXME: add all calendars // FIXME: add all calendars
currentFolder = [[context activeUser] personalCalendarFolderInContext: context]; currentFolder = [[context activeUser] personalCalendarFolderInContext: context];
name = [NSString stringWithFormat: @"vevent/%@", [currentFolder nameInContainer]]; name = [NSString stringWithFormat: @"vevent/%@", [currentFolder nameInContainer]];
[s appendFormat: @"<Add><ServerId>%@</ServerId><ParentId>%@</ParentId><Type>%d</Type><DisplayName>%@</DisplayName></Add>", name, @"0", 8, [[currentFolder displayName] stringByEscapingHTMLString]]; [s appendFormat: @"<Add><ServerId>%@</ServerId><ParentId>%@</ParentId><Type>%d</Type><DisplayName>%@</DisplayName></Add>", name, @"0", 8, [[currentFolder displayName] activeSyncRepresentation]];
// We add the personal calendar - tasks // We add the personal calendar - tasks
// FIXME: add all calendars // FIXME: add all calendars
currentFolder = [[context activeUser] personalCalendarFolderInContext: context]; currentFolder = [[context activeUser] personalCalendarFolderInContext: context];
name = [NSString stringWithFormat: @"vtodo/%@", [currentFolder nameInContainer]]; name = [NSString stringWithFormat: @"vtodo/%@", [currentFolder nameInContainer]];
[s appendFormat: @"<Add><ServerId>%@</ServerId><ParentId>%@</ParentId><Type>%d</Type><DisplayName>%@</DisplayName></Add>", name, @"0", 7, [[currentFolder displayName] stringByEscapingHTMLString]]; [s appendFormat: @"<Add><ServerId>%@</ServerId><ParentId>%@</ParentId><Type>%d</Type><DisplayName>%@</DisplayName></Add>", name, @"0", 7, [[currentFolder displayName] activeSyncRepresentation]];
// We add the personal address book // We add the personal address book
// FIXME: add all address books // FIXME: add all address books
currentFolder = [[context activeUser] personalContactsFolderInContext: context]; currentFolder = [[context activeUser] personalContactsFolderInContext: context];
name = [NSString stringWithFormat: @"vcard/%@", [currentFolder nameInContainer]]; name = [NSString stringWithFormat: @"vcard/%@", [currentFolder nameInContainer]];
[s appendFormat: @"<Add><ServerId>%@</ServerId><ParentId>%@</ParentId><Type>%d</Type><DisplayName>%@</DisplayName></Add>", name, @"0", 9, [[currentFolder displayName] stringByEscapingHTMLString]]; [s appendFormat: @"<Add><ServerId>%@</ServerId><ParentId>%@</ParentId><Type>%d</Type><DisplayName>%@</DisplayName></Add>", name, @"0", 9, [[currentFolder displayName] activeSyncRepresentation]];
} }
[s appendString: @"</Changes></FolderSync>"]; [s appendString: @"</Changes></FolderSync>"];

View File

@ -344,13 +344,13 @@ struct GlobalObjectId {
// From // From
value = [self _emailAddressesFrom: [[self envelope] from]]; value = [self _emailAddressesFrom: [[self envelope] from]];
if (value) if (value)
[s appendFormat: @"<From xmlns=\"Email:\">%@</From>", [value stringByEscapingHTMLString]]; [s appendFormat: @"<From xmlns=\"Email:\">%@</From>", [value activeSyncRepresentation]];
// To - "The value of this element contains one or more e-mail addresses. // To - "The value of this element contains one or more e-mail addresses.
// If there are multiple e-mail addresses, they are separated by commas." // If there are multiple e-mail addresses, they are separated by commas."
value = [self _emailAddressesFrom: [[self envelope] to]]; value = [self _emailAddressesFrom: [[self envelope] to]];
if (value) if (value)
[s appendFormat: @"<To xmlns=\"Email:\">%@</To>", [value stringByEscapingHTMLString]]; [s appendFormat: @"<To xmlns=\"Email:\">%@</To>", [value activeSyncRepresentation]];
// DisplayTo // DisplayTo
[s appendFormat: @"<DisplayTo xmlns=\"Email:\">\"%@\"</DisplayTo>", [[context activeUser] login]]; [s appendFormat: @"<DisplayTo xmlns=\"Email:\">\"%@\"</DisplayTo>", [[context activeUser] login]];
@ -358,14 +358,14 @@ struct GlobalObjectId {
// Cc - same syntax as the To field // Cc - same syntax as the To field
value = [self _emailAddressesFrom: [[self envelope] cc]]; value = [self _emailAddressesFrom: [[self envelope] cc]];
if (value) if (value)
[s appendFormat: @"<Cc xmlns=\"Email:\">%@</Cc>", [value stringByEscapingHTMLString]]; [s appendFormat: @"<Cc xmlns=\"Email:\">%@</Cc>", [value activeSyncRepresentation]];
// Subject // Subject
value = [self decodedSubject]; value = [self decodedSubject];
if (value) if (value)
{ {
[s appendFormat: @"<Subject xmlns=\"Email:\">%@</Subject>", [value stringByEscapingHTMLString]]; [s appendFormat: @"<Subject xmlns=\"Email:\">%@</Subject>", [value activeSyncRepresentation]];
[s appendFormat: @"<ThreadTopic xmlns=\"Email:\">%@</ThreadTopic>", [value stringByEscapingHTMLString]]; [s appendFormat: @"<ThreadTopic xmlns=\"Email:\">%@</ThreadTopic>", [value activeSyncRepresentation]];
} }
// DateReceived // DateReceived
@ -459,7 +459,7 @@ struct GlobalObjectId {
content = [[NSString alloc] initWithData: d encoding: NSUTF8StringEncoding]; content = [[NSString alloc] initWithData: d encoding: NSUTF8StringEncoding];
AUTORELEASE(content); AUTORELEASE(content);
content = [content stringByEscapingHTMLString]; content = [content activeSyncRepresentation];
len = [content length]; len = [content length];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"]; [s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
@ -483,7 +483,7 @@ struct GlobalObjectId {
value = [attachmentKeys objectAtIndex: i]; value = [attachmentKeys objectAtIndex: i];
[s appendString: @"<Attachment>"]; [s appendString: @"<Attachment>"];
[s appendFormat: @"<DisplayName>%@</DisplayName>", [[value objectForKey: @"filename"] stringByEscapingHTMLString]]; [s appendFormat: @"<DisplayName>%@</DisplayName>", [[value objectForKey: @"filename"] activeSyncRepresentation]];
// FileReference must be a unique identifier across the whole store. We use the following structure: // FileReference must be a unique identifier across the whole store. We use the following structure:
// mail/<foldername>/<message UID/<pathofpart> // mail/<foldername>/<message UID/<pathofpart>

View File

@ -138,11 +138,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Subject -- http://msdn.microsoft.com/en-us/library/ee157192(v=exchg.80).aspx // Subject -- http://msdn.microsoft.com/en-us/library/ee157192(v=exchg.80).aspx
if ([[self summary] length]) if ([[self summary] length])
[s appendFormat: @"<Subject xmlns=\"Calendar:\">%@</Subject>", [[self summary] stringByEscapingHTMLString]]; [s appendFormat: @"<Subject xmlns=\"Calendar:\">%@</Subject>", [[self summary] activeSyncRepresentation]];
// Location // Location
if ([[self location] length]) if ([[self location] length])
[s appendFormat: @"<Location xmlns=\"Calendar:\">%@</Location>", [[self location] stringByEscapingHTMLString]]; [s appendFormat: @"<Location xmlns=\"Calendar:\">%@</Location>", [[self location] activeSyncRepresentation]];
// Importance - NOT SUPPORTED - DO NOT ENABLE // Importance - NOT SUPPORTED - DO NOT ENABLE
//o = [self priority]; //o = [self priority];
@ -184,7 +184,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
o = [self comment]; o = [self comment];
if ([o length]) if ([o length])
{ {
o = [o stringByEscapingHTMLString]; o = [o activeSyncRepresentation];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"]; [s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1]; [s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]]; [s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];

View File

@ -97,11 +97,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Subject // Subject
o = [self summary]; o = [self summary];
if ([o length]) if ([o length])
[s appendFormat: @"<Subject xmlns=\"Tasks:\">%@</Subject>", [[self summary] stringByEscapingHTMLString]]; [s appendFormat: @"<Subject xmlns=\"Tasks:\">%@</Subject>", [[self summary] activeSyncRepresentation]];
if ((o = [self comment])) if ((o = [self comment]))
{ {
o = [o stringByEscapingHTMLString]; o = [o activeSyncRepresentation];
[s appendString: @"<Body xmlns=\"AirSyncBase:\">"]; [s appendString: @"<Body xmlns=\"AirSyncBase:\">"];
[s appendFormat: @"<Type>%d</Type>", 1]; [s appendFormat: @"<Type>%d</Type>", 1];
[s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]]; [s appendFormat: @"<EstimatedDataSize>%d</EstimatedDataSize>", [o length]];

View File

@ -1,6 +1,6 @@
/* NSString+Utilities.h - this file is part of SOGo /* NSString+Utilities.h - this file is part of SOGo
* *
* Copyright (C) 2006-2013 Inverse inc. * Copyright (C) 2006-2014 Inverse inc.
* *
* This file is free software; you can redistribute it and/or modify * This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -23,6 +23,7 @@
#import <Foundation/NSString.h> #import <Foundation/NSString.h>
@class NSCharacterSet;
@class NSDictionary; @class NSDictionary;
@class NSObject; @class NSObject;
@ -49,6 +50,7 @@
- (NSString *) asSafeSQLString; - (NSString *) asSafeSQLString;
/* JSON */ /* JSON */
- (NSCharacterSet *) safeCharacterSet;
- (NSString *) jsonRepresentation; - (NSString *) jsonRepresentation;
- (BOOL) isJSONString; - (BOOL) isJSONString;
- (id) objectFromJSONString; - (id) objectFromJSONString;

View File

@ -1,6 +1,6 @@
/* NSString+Utilities.m - this file is part of SOGo /* NSString+Utilities.m - this file is part of SOGo
* *
* Copyright (C) 2006-2013 Inverse inc. * Copyright (C) 2006-2014 Inverse inc.
* *
* This file is free software; you can redistribute it and/or modify * This file is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -46,6 +46,10 @@ static NSString **cssEscapingStrings = NULL;
static unichar *cssEscapingCharacters = NULL; static unichar *cssEscapingCharacters = NULL;
static int cssEscapingCount; static int cssEscapingCount;
static unichar thisCharCode[29];
static NSString *controlCharString = nil;
static NSCharacterSet *controlCharSet = nil;
@implementation NSString (SOGoURLExtension) @implementation NSString (SOGoURLExtension)
- (NSString *) composeURLWithAction: (NSString *) action - (NSString *) composeURLWithAction: (NSString *) action
@ -274,16 +278,12 @@ static int cssEscapingCount;
return [NSString stringWithFormat: @"\"%@\"", representation]; return [NSString stringWithFormat: @"\"%@\"", representation];
} }
- (NSString *) jsonRepresentation - (NSCharacterSet *) safeCharacterSet
{ {
static unichar thisCharCode[29];
static NSString *controlCharString = nil;
static NSCharacterSet *controlCharSet = nil;
NSString *cleanedString;
int i, j;
if (!controlCharSet) if (!controlCharSet)
{ {
int i, j;
// Create an array of chars for all control characters between 0x00 and 0x1F, // Create an array of chars for all control characters between 0x00 and 0x1F,
// apart from \t, \n, \f and \r (0x08, 0x09, 0x0A, 0x0C and 0x0D) // apart from \t, \n, \f and \r (0x08, 0x09, 0x0A, 0x0C and 0x0D)
for (i = 0, j = 0x00; j < 0x08; i++, j++) { for (i = 0, j = 0x00; j < 0x08; i++, j++) {
@ -293,7 +293,7 @@ static int cssEscapingCount;
for (j = 0x0E; j <= 0x1F; i++, j++) { for (j = 0x0E; j <= 0x1F; i++, j++) {
thisCharCode[i] = j; thisCharCode[i] = j;
} }
// Also add some unicode separators // Also add some unicode separators
thisCharCode[i++] = 0x2028; // line separator thisCharCode[i++] = 0x2028; // line separator
thisCharCode[i++] = 0x2029; // paragraph separator thisCharCode[i++] = 0x2029; // paragraph separator
@ -302,8 +302,15 @@ static int cssEscapingCount;
[controlCharSet retain]; [controlCharSet retain];
} }
return controlCharSet;
}
- (NSString *) jsonRepresentation
{
NSString *cleanedString;
// Escape double quotes and remove control characters // Escape double quotes and remove control characters
cleanedString = [[[self doubleQuotedString] componentsSeparatedByCharactersInSet: controlCharSet] cleanedString = [[[self doubleQuotedString] componentsSeparatedByCharactersInSet: [self safeCharacterSet]]
componentsJoinedByString: @""]; componentsJoinedByString: @""];
return cleanedString; return cleanedString;
} }