os/ossrv/genericservices/httputils/internetdateutils/tinternetdateparser.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// This file contains the implementation of internal classes used to parse TInternetDate data
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
/**
sl@0
    19
 @file tinternetdateparser.cpp
sl@0
    20
 @see tinternetdateparser.h
sl@0
    21
*/
sl@0
    22
sl@0
    23
#include "tinternetdateparser.h"
sl@0
    24
#include "inetprottextutils.h"
sl@0
    25
#include <e32base.h>
sl@0
    26
sl@0
    27
//constants
sl@0
    28
//
sl@0
    29
const TInt KRfc1123DateTimeLength = 29;	// Sun, 06 Nov 1994 08:49:37 GMT
sl@0
    30
const TInt KHHMMSSFormatLength=8;		// HH:MM:SS
sl@0
    31
sl@0
    32
// Long form day names, 'weekday' in RFC850
sl@0
    33
//
sl@0
    34
static const TText8* const KInternetWeekDays[] = 
sl@0
    35
	{
sl@0
    36
	_S8("Monday"),
sl@0
    37
	_S8("Tuesday"),
sl@0
    38
	_S8("Wednesday"),
sl@0
    39
	_S8("Thursday"),
sl@0
    40
	_S8("Friday"),
sl@0
    41
	_S8("Saturday"),
sl@0
    42
	_S8("Sunday")
sl@0
    43
	};
sl@0
    44
sl@0
    45
// Month names, 'month' in RFC1123 & RFC850
sl@0
    46
//
sl@0
    47
static const TText8* const KInternetMonths[] = 
sl@0
    48
	{
sl@0
    49
	_S8("Jan"),
sl@0
    50
	_S8("Feb"),
sl@0
    51
	_S8("Mar"),
sl@0
    52
	_S8("Apr"),
sl@0
    53
	_S8("May"),
sl@0
    54
	_S8("Jun"),
sl@0
    55
	_S8("Jul"),
sl@0
    56
	_S8("Aug"),
sl@0
    57
	_S8("Sep"),
sl@0
    58
	_S8("Oct"),
sl@0
    59
	_S8("Nov"),
sl@0
    60
	_S8("Dec")
sl@0
    61
	};
sl@0
    62
sl@0
    63
/**
sl@0
    64
	Converts from TDateTime to Internet RFC1123 Style date strings
sl@0
    65
	
sl@0
    66
	@since			7.0
sl@0
    67
	@param			aDateTime The date/time to be parsed
sl@0
    68
	@leave			KErrNoMemory
sl@0
    69
	@return			HBufC8* aDescriptor containing a RFC1123 style date. 
sl@0
    70
*/
sl@0
    71
HBufC8* TInternetDateParser::ConvertToRfc1123FormL(const TDateTime& aDateTime)
sl@0
    72
	{
sl@0
    73
	const TChar KSpace = ' ';
sl@0
    74
sl@0
    75
	HBufC8* dateTime = HBufC8::NewLC(KRfc1123DateTimeLength);
sl@0
    76
	TPtr8 dateTimePtr = dateTime->Des();
sl@0
    77
	// Append the wkDay
sl@0
    78
	TTime time(aDateTime);
sl@0
    79
	TInt wkDay = time.DayNoInWeek();
sl@0
    80
	TPtrC8 wkDayText(KInternetWeekDays[wkDay]);
sl@0
    81
	dateTimePtr.Append(wkDayText.Left(3));
sl@0
    82
sl@0
    83
sl@0
    84
	// Append the day number 
sl@0
    85
	_LIT8(KDayNumberFormat, ", %02d");
sl@0
    86
	TInt dayNumber = aDateTime.Day() + 1;
sl@0
    87
	dateTimePtr.AppendFormat(KDayNumberFormat, dayNumber);
sl@0
    88
sl@0
    89
	// Append month
sl@0
    90
	dateTimePtr.Append(KSpace);
sl@0
    91
	TInt month = aDateTime.Month();
sl@0
    92
	dateTimePtr.Append(TPtrC8(KInternetMonths[month]));
sl@0
    93
sl@0
    94
	// Append year
sl@0
    95
	_LIT8(KYearDigitFormat, " %4d");
sl@0
    96
	TInt year = aDateTime.Year();
sl@0
    97
	dateTimePtr.AppendFormat(KYearDigitFormat, year);
sl@0
    98
sl@0
    99
	// Append Time HH:MM:SS
sl@0
   100
sl@0
   101
	dateTimePtr.Append(KSpace);
sl@0
   102
	_LIT8(KHHMMSSFormat, "%02d:%02d:%02d GMT");
sl@0
   103
	dateTimePtr.AppendFormat(KHHMMSSFormat, aDateTime.Hour(),aDateTime.Minute(),aDateTime.Second());
sl@0
   104
sl@0
   105
	CleanupStack::Pop(dateTime);
sl@0
   106
	return dateTime;
sl@0
   107
	}
sl@0
   108
sl@0
   109
sl@0
   110
/**
sl@0
   111
	Used to parse internet text date/time into a TDateTime
sl@0
   112
	
sl@0
   113
	@since			7.0
sl@0
   114
	@param			aInternetTextDateTime The date/time in a text format
sl@0
   115
	@param			aDateTime The result of parsing is placed here
sl@0
   116
	@leave			KErrNoMemory, KErrCorrupt If the format of the descriptor is not valid
sl@0
   117
*/	
sl@0
   118
void TInternetDateParser::ConvertFromInternetFormL(const TDesC8& aInternetTextDateTime, TDateTime& aDateTime)
sl@0
   119
	{
sl@0
   120
	const TChar KComma = ',';
sl@0
   121
	TInt colonLoc = aInternetTextDateTime.Locate(KComma);
sl@0
   122
	switch (colonLoc)
sl@0
   123
		{
sl@0
   124
	case -1:	// ANSI C asctime() format: Sun Nov  6 08:49:37 1994
sl@0
   125
		ConvertFromAscTimeFormL(aInternetTextDateTime, aDateTime);
sl@0
   126
		break;
sl@0
   127
	case 3:		// RFC 1123 Style Date: Sun, 06 Nov 1994 08:49:37 GMT
sl@0
   128
	case 6:		// RFC 850 Style Date: Sunday, 06-Nov-94 08:49:37 GMT
sl@0
   129
	case 7:		
sl@0
   130
	case 8:	
sl@0
   131
	case 9:		
sl@0
   132
		{
sl@0
   133
		TPtrC8 dateTime(aInternetTextDateTime.Right(aInternetTextDateTime.Length() -(colonLoc+1))); // Remove "<day>,"
sl@0
   134
		ConvertFromRfc1123And850FormL(dateTime, aDateTime);	
sl@0
   135
		}
sl@0
   136
		break;
sl@0
   137
	default:
sl@0
   138
		User::Leave(KErrCorrupt);
sl@0
   139
		};
sl@0
   140
	}
sl@0
   141
sl@0
   142
/**
sl@0
   143
	@param			aRfcDateTime 
sl@0
   144
	@param			aDateTime The result of parsing is placed here
sl@0
   145
 */	
sl@0
   146
void TInternetDateParser::ConvertFromRfc1123And850FormL(const TDesC8& aRfcDateTime, TDateTime& aDateTime)
sl@0
   147
	{
sl@0
   148
	TPtrC8 dateTime(aRfcDateTime);
sl@0
   149
	InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveBoth);
sl@0
   150
	TInt textLeft = ParseRfcDateDayMonthYearL(dateTime, aDateTime);
sl@0
   151
	if (textLeft <= 0)
sl@0
   152
		User::Leave(KErrCorrupt);
sl@0
   153
	dateTime.Set(dateTime.Right(textLeft));
sl@0
   154
	InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
sl@0
   155
	ParseHHMMSSTimeL(dateTime, aDateTime);
sl@0
   156
	textLeft= dateTime.Length() - KHHMMSSFormatLength;
sl@0
   157
	if (textLeft > 1) // Must still have leading space
sl@0
   158
		{
sl@0
   159
		dateTime.Set(dateTime.Right(textLeft));
sl@0
   160
		InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
sl@0
   161
		TTimeIntervalMinutes timeOffset = 0;
sl@0
   162
		ParseTimeOffsetL(dateTime, timeOffset);
sl@0
   163
sl@0
   164
		if (timeOffset.Int() > 0 || timeOffset.Int() < 0)
sl@0
   165
			{
sl@0
   166
			TTime time(aDateTime);
sl@0
   167
			time -= timeOffset;
sl@0
   168
			aDateTime = time.DateTime();
sl@0
   169
			}
sl@0
   170
		}
sl@0
   171
	else
sl@0
   172
		User::Leave(KErrCorrupt); // Must include a timezone or timeoffset
sl@0
   173
	}
sl@0
   174
sl@0
   175
/**
sl@0
   176
	@param			aTimeOffset 
sl@0
   177
	@param			aOffsetMinutes 
sl@0
   178
 */
sl@0
   179
void TInternetDateParser::ParseHHMMTimeOffsetL(const TDesC8& aTimeOffset, TTimeIntervalMinutes& aOffsetMinutes)
sl@0
   180
	{
sl@0
   181
	TInt offsetTextLength=aTimeOffset.Length();
sl@0
   182
	if (offsetTextLength != 5) // +0000 or -0000
sl@0
   183
		User::Leave(KErrCorrupt);
sl@0
   184
sl@0
   185
	TPtrC8 timeOffset(aTimeOffset.Right(offsetTextLength-1));
sl@0
   186
	
sl@0
   187
	TInt num=0;
sl@0
   188
	if (InetProtTextUtils::ConvertDescriptorToInt(timeOffset, num) !=4)
sl@0
   189
		User::Leave(KErrCorrupt); // not 0000
sl@0
   190
sl@0
   191
	TInt minutes = num % 100;
sl@0
   192
	TInt hours = num / 100;
sl@0
   193
	TInt offsetMinutes=0;
sl@0
   194
	if (minutes < 60 && hours < 24)
sl@0
   195
		offsetMinutes = minutes + (hours * 60);
sl@0
   196
	
sl@0
   197
	if (aTimeOffset[0] == '-')
sl@0
   198
		offsetMinutes *= -1;
sl@0
   199
sl@0
   200
	aOffsetMinutes = offsetMinutes;
sl@0
   201
	}
sl@0
   202
sl@0
   203
/**
sl@0
   204
	@param			aTimeOffset 
sl@0
   205
	@param			aOffsetMinutes 
sl@0
   206
 */
sl@0
   207
void TInternetDateParser::ParseTimeOffsetL(const TDesC8& aTimeOffset, TTimeIntervalMinutes& aOffsetMinutes)
sl@0
   208
	{
sl@0
   209
	TInt offsetMinutes=0;
sl@0
   210
	TInt offsetTextLength = aTimeOffset.Length();
sl@0
   211
	if (offsetTextLength > 1)
sl@0
   212
		{
sl@0
   213
		// check second letter to see if UT, GMT
sl@0
   214
		// and to differentiate between Standard and Daylight Savings
sl@0
   215
		switch (aTimeOffset[1])					
sl@0
   216
			{
sl@0
   217
		case 'M' : // GMT
sl@0
   218
		case 'T' : // UT
sl@0
   219
			{
sl@0
   220
			return;
sl@0
   221
			}
sl@0
   222
		case 'S': // Standard Time (Daylight Savings Time is one hour ahead);
sl@0
   223
			offsetMinutes -= 60;
sl@0
   224
			break;
sl@0
   225
		case 'D' : // Daylight Savings Time
sl@0
   226
			break;
sl@0
   227
		default:
sl@0
   228
			// Must be either corrupt or an explicit HHMM +/- offset
sl@0
   229
			ParseHHMMTimeOffsetL(aTimeOffset, aOffsetMinutes);
sl@0
   230
			return;
sl@0
   231
			};
sl@0
   232
sl@0
   233
		// Check first letter to find out if its Eastern, Central, Mountain or Pacific Time
sl@0
   234
		switch (aTimeOffset[0])
sl@0
   235
			{
sl@0
   236
		case 'E' : // EST or EDT -4
sl@0
   237
			offsetMinutes -=240;
sl@0
   238
			break;
sl@0
   239
		case 'C' : // CST or CDT -5
sl@0
   240
			offsetMinutes -=300;
sl@0
   241
			break;
sl@0
   242
		case 'M' : // MST or MDT -6
sl@0
   243
			offsetMinutes -= 360;
sl@0
   244
			break;
sl@0
   245
		case 'P' : // PST or PDT -7
sl@0
   246
			offsetMinutes -=420;
sl@0
   247
			break;
sl@0
   248
		default:
sl@0
   249
			// either the format is invalid or it is a non standard 3 letter timezone
sl@0
   250
			// in either case 
sl@0
   251
			return;
sl@0
   252
			};
sl@0
   253
		}
sl@0
   254
	else // This must be a military single letter format time zone
sl@0
   255
		// According to RFC2882 These Military Timezones are obsolete. Also since A can be either +1 or -1 depending on the specification
sl@0
   256
		// it should be ignored unless there is additional Out of band Information
sl@0
   257
		{
sl@0
   258
		return; // Do nothing
sl@0
   259
		}
sl@0
   260
sl@0
   261
	aOffsetMinutes = offsetMinutes;
sl@0
   262
	}
sl@0
   263
sl@0
   264
/**
sl@0
   265
	@param			aDateTimeText 
sl@0
   266
	@param			aDateTime 
sl@0
   267
 */
sl@0
   268
void TInternetDateParser::ParseHHMMSSTimeL(const TDesC8& aDateTimeText, TDateTime& aDateTime)
sl@0
   269
	{
sl@0
   270
	if (aDateTimeText.Length() < KHHMMSSFormatLength)  // Must be at least HH:MM:SS
sl@0
   271
		User::Leave(KErrCorrupt);
sl@0
   272
	TInt num=0;
sl@0
   273
	TInt consumed = InetProtTextUtils::ConvertDescriptorToInt(aDateTimeText, num);	
sl@0
   274
	if (consumed != 2 || num < 0 || num > 23)
sl@0
   275
		User::Leave(KErrCorrupt);
sl@0
   276
	TPtrC8 dateTime(aDateTimeText.Right(aDateTimeText.Length() -3)); // Remove HH:
sl@0
   277
	aDateTime.SetHour(num);
sl@0
   278
sl@0
   279
	consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, num);
sl@0
   280
	if (consumed != 2 || num < 0 || num > 59)
sl@0
   281
		User::Leave(KErrCorrupt);
sl@0
   282
	dateTime.Set(dateTime.Right(dateTime.Length() -3)); // Remove MM:
sl@0
   283
	aDateTime.SetMinute(num);
sl@0
   284
sl@0
   285
	consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, num);
sl@0
   286
	if (consumed != 2 || num < 0 || num > 59)
sl@0
   287
		User::Leave(KErrCorrupt);
sl@0
   288
	aDateTime.SetSecond(num);
sl@0
   289
	}
sl@0
   290
	
sl@0
   291
/**
sl@0
   292
	@param			aDateTimeText 
sl@0
   293
	@param			aDateTime 
sl@0
   294
	@return
sl@0
   295
 */
sl@0
   296
TInt TInternetDateParser::ParseRfcDateDayMonthYearL(const TDesC8& aDateTimeText, TDateTime& aDateTime)
sl@0
   297
	{
sl@0
   298
	// Parse RFC 1123 and RFC 850 style date month year parts
sl@0
   299
	// 06 Nov 1994	(RFC 1123)
sl@0
   300
	// 06-Nov-94	(RFC 850) In this case if YY < 50 then treat as 20YY otherwise 19YY
sl@0
   301
	TInt day =0;
sl@0
   302
	TInt consumed = InetProtTextUtils::ConvertDescriptorToInt(aDateTimeText,day);
sl@0
   303
	if ((consumed !=1 && consumed != 2) || aDateTimeText.Length() <= 2)
sl@0
   304
		User::Leave(KErrCorrupt);
sl@0
   305
sl@0
   306
	--day; // Symbian OS month days start from 0
sl@0
   307
sl@0
   308
	// Skip over DD and separator
sl@0
   309
	TPtrC8 dateTimeText(aDateTimeText.Right(aDateTimeText.Length()-(consumed+1)));
sl@0
   310
	TMonth month = GetMonthL(dateTimeText);
sl@0
   311
	// Skip over MMM and separator
sl@0
   312
	const TInt KConsumedMonthLength = 4;
sl@0
   313
	TInt rightLength = dateTimeText.Length() - KConsumedMonthLength ;
sl@0
   314
	if( rightLength < 0)
sl@0
   315
		{
sl@0
   316
		User::Leave(KErrCorrupt);	
sl@0
   317
		}
sl@0
   318
	dateTimeText.Set(dateTimeText.Right(rightLength)); 
sl@0
   319
sl@0
   320
	// Now get year
sl@0
   321
	TInt year;
sl@0
   322
	consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTimeText, year);
sl@0
   323
	if (consumed != 4 && consumed !=2)
sl@0
   324
		User::Leave(KErrCorrupt);
sl@0
   325
sl@0
   326
	// check for YY and adjust
sl@0
   327
	if (consumed == 2)
sl@0
   328
		year += year > 50 ? 1900 : 2000;
sl@0
   329
sl@0
   330
	if (aDateTime.Set(year, month, day, 0, 0, 0, 0) != KErrNone)
sl@0
   331
		User::Leave(KErrCorrupt);
sl@0
   332
sl@0
   333
	return dateTimeText.Length() - (consumed +1);
sl@0
   334
	}
sl@0
   335
sl@0
   336
/**
sl@0
   337
	@param			aMonthText 
sl@0
   338
	@return 
sl@0
   339
 */
sl@0
   340
TMonth TInternetDateParser::GetMonthL(const TDesC8& aMonthText)
sl@0
   341
	{
sl@0
   342
	if (aMonthText.Length() < 3)
sl@0
   343
		User::Leave(KErrCorrupt);
sl@0
   344
	
sl@0
   345
	switch (aMonthText[0])
sl@0
   346
		{
sl@0
   347
	case 'J':		// Jan, Jun, Jul
sl@0
   348
		return (aMonthText[1] == 'a' ? EJanuary : aMonthText[2] == 'n' ? EJune : EJuly);	
sl@0
   349
	case 'F':		// Feb
sl@0
   350
		return EFebruary;
sl@0
   351
	case 'M':		// Mar, May
sl@0
   352
		return (aMonthText[2] == 'r' ? EMarch : EMay);
sl@0
   353
	case 'A':		// Apr, Aug
sl@0
   354
		return (aMonthText[1] == 'p' ? EApril : EAugust);
sl@0
   355
	case 'S':		// Sep
sl@0
   356
		return ESeptember;
sl@0
   357
	case 'O':		// Oct
sl@0
   358
		return EOctober;
sl@0
   359
	case 'N':		// Nov
sl@0
   360
		return ENovember;
sl@0
   361
	case 'D':		// Dec
sl@0
   362
		return EDecember;
sl@0
   363
	default:
sl@0
   364
		User::Leave(KErrCorrupt);
sl@0
   365
		};
sl@0
   366
	return EJanuary;
sl@0
   367
	}
sl@0
   368
sl@0
   369
sl@0
   370
/**
sl@0
   371
	@param			aAscTimeDateTime 
sl@0
   372
	@param			aDateTime
sl@0
   373
 */
sl@0
   374
void TInternetDateParser::ConvertFromAscTimeFormL(const TDesC8& aAscTimeDateTime, TDateTime& aDateTime)
sl@0
   375
	{
sl@0
   376
	// Convert a date in ascTime format ( Sun Nov  6 08:49:37 1994 )
sl@0
   377
sl@0
   378
	const TChar KSpace = ' ';
sl@0
   379
sl@0
   380
	// First remove the wkDay
sl@0
   381
	TPtrC8 dateTime(aAscTimeDateTime);
sl@0
   382
	InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveBoth);
sl@0
   383
	TInt endOfWkDayLoc = dateTime.Locate(KSpace);
sl@0
   384
	if (endOfWkDayLoc != 3) // Must be following a wkDay "Sun "
sl@0
   385
		User::Leave(KErrCorrupt);
sl@0
   386
	dateTime.Set(dateTime.Right(dateTime.Length() - 3));
sl@0
   387
	InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
sl@0
   388
	// Now parse the month then skip over MMM
sl@0
   389
	TMonth month = GetMonthL(dateTime);
sl@0
   390
	dateTime.Set(dateTime.Right(dateTime.Length() - 3));
sl@0
   391
	InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
sl@0
   392
	// Now parse the monthDay
sl@0
   393
	TInt day = 0;
sl@0
   394
	TInt consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, day);
sl@0
   395
	if (consumed < 0)
sl@0
   396
		User::Leave(KErrCorrupt);
sl@0
   397
sl@0
   398
	dateTime.Set(dateTime.Right(dateTime.Length() - consumed));
sl@0
   399
	InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
sl@0
   400
sl@0
   401
	// Now get the time
sl@0
   402
	ParseHHMMSSTimeL(dateTime, aDateTime);
sl@0
   403
	dateTime.Set(dateTime.Right(dateTime.Length() - KHHMMSSFormatLength));	
sl@0
   404
	// Now the year
sl@0
   405
	InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
sl@0
   406
	TInt year;
sl@0
   407
	consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, year);
sl@0
   408
	if (consumed !=4)
sl@0
   409
		User::Leave(KErrCorrupt);
sl@0
   410
sl@0
   411
	if (aDateTime.Set(year, month, day-1, aDateTime.Hour(), aDateTime.Minute(), aDateTime.Second(), 0) != KErrNone)
sl@0
   412
		User::Leave(KErrCorrupt);
sl@0
   413
	}