diff -r 000000000000 -r bde4ae8d615e os/ossrv/genericservices/httputils/internetdateutils/tinternetdateparser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/ossrv/genericservices/httputils/internetdateutils/tinternetdateparser.cpp Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,413 @@ +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// This file contains the implementation of internal classes used to parse TInternetDate data +// +// + +/** + @file tinternetdateparser.cpp + @see tinternetdateparser.h +*/ + +#include "tinternetdateparser.h" +#include "inetprottextutils.h" +#include + +//constants +// +const TInt KRfc1123DateTimeLength = 29; // Sun, 06 Nov 1994 08:49:37 GMT +const TInt KHHMMSSFormatLength=8; // HH:MM:SS + +// Long form day names, 'weekday' in RFC850 +// +static const TText8* const KInternetWeekDays[] = + { + _S8("Monday"), + _S8("Tuesday"), + _S8("Wednesday"), + _S8("Thursday"), + _S8("Friday"), + _S8("Saturday"), + _S8("Sunday") + }; + +// Month names, 'month' in RFC1123 & RFC850 +// +static const TText8* const KInternetMonths[] = + { + _S8("Jan"), + _S8("Feb"), + _S8("Mar"), + _S8("Apr"), + _S8("May"), + _S8("Jun"), + _S8("Jul"), + _S8("Aug"), + _S8("Sep"), + _S8("Oct"), + _S8("Nov"), + _S8("Dec") + }; + +/** + Converts from TDateTime to Internet RFC1123 Style date strings + + @since 7.0 + @param aDateTime The date/time to be parsed + @leave KErrNoMemory + @return HBufC8* aDescriptor containing a RFC1123 style date. +*/ +HBufC8* TInternetDateParser::ConvertToRfc1123FormL(const TDateTime& aDateTime) + { + const TChar KSpace = ' '; + + HBufC8* dateTime = HBufC8::NewLC(KRfc1123DateTimeLength); + TPtr8 dateTimePtr = dateTime->Des(); + // Append the wkDay + TTime time(aDateTime); + TInt wkDay = time.DayNoInWeek(); + TPtrC8 wkDayText(KInternetWeekDays[wkDay]); + dateTimePtr.Append(wkDayText.Left(3)); + + + // Append the day number + _LIT8(KDayNumberFormat, ", %02d"); + TInt dayNumber = aDateTime.Day() + 1; + dateTimePtr.AppendFormat(KDayNumberFormat, dayNumber); + + // Append month + dateTimePtr.Append(KSpace); + TInt month = aDateTime.Month(); + dateTimePtr.Append(TPtrC8(KInternetMonths[month])); + + // Append year + _LIT8(KYearDigitFormat, " %4d"); + TInt year = aDateTime.Year(); + dateTimePtr.AppendFormat(KYearDigitFormat, year); + + // Append Time HH:MM:SS + + dateTimePtr.Append(KSpace); + _LIT8(KHHMMSSFormat, "%02d:%02d:%02d GMT"); + dateTimePtr.AppendFormat(KHHMMSSFormat, aDateTime.Hour(),aDateTime.Minute(),aDateTime.Second()); + + CleanupStack::Pop(dateTime); + return dateTime; + } + + +/** + Used to parse internet text date/time into a TDateTime + + @since 7.0 + @param aInternetTextDateTime The date/time in a text format + @param aDateTime The result of parsing is placed here + @leave KErrNoMemory, KErrCorrupt If the format of the descriptor is not valid +*/ +void TInternetDateParser::ConvertFromInternetFormL(const TDesC8& aInternetTextDateTime, TDateTime& aDateTime) + { + const TChar KComma = ','; + TInt colonLoc = aInternetTextDateTime.Locate(KComma); + switch (colonLoc) + { + case -1: // ANSI C asctime() format: Sun Nov 6 08:49:37 1994 + ConvertFromAscTimeFormL(aInternetTextDateTime, aDateTime); + break; + case 3: // RFC 1123 Style Date: Sun, 06 Nov 1994 08:49:37 GMT + case 6: // RFC 850 Style Date: Sunday, 06-Nov-94 08:49:37 GMT + case 7: + case 8: + case 9: + { + TPtrC8 dateTime(aInternetTextDateTime.Right(aInternetTextDateTime.Length() -(colonLoc+1))); // Remove "," + ConvertFromRfc1123And850FormL(dateTime, aDateTime); + } + break; + default: + User::Leave(KErrCorrupt); + }; + } + +/** + @param aRfcDateTime + @param aDateTime The result of parsing is placed here + */ +void TInternetDateParser::ConvertFromRfc1123And850FormL(const TDesC8& aRfcDateTime, TDateTime& aDateTime) + { + TPtrC8 dateTime(aRfcDateTime); + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveBoth); + TInt textLeft = ParseRfcDateDayMonthYearL(dateTime, aDateTime); + if (textLeft <= 0) + User::Leave(KErrCorrupt); + dateTime.Set(dateTime.Right(textLeft)); + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft); + ParseHHMMSSTimeL(dateTime, aDateTime); + textLeft= dateTime.Length() - KHHMMSSFormatLength; + if (textLeft > 1) // Must still have leading space + { + dateTime.Set(dateTime.Right(textLeft)); + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft); + TTimeIntervalMinutes timeOffset = 0; + ParseTimeOffsetL(dateTime, timeOffset); + + if (timeOffset.Int() > 0 || timeOffset.Int() < 0) + { + TTime time(aDateTime); + time -= timeOffset; + aDateTime = time.DateTime(); + } + } + else + User::Leave(KErrCorrupt); // Must include a timezone or timeoffset + } + +/** + @param aTimeOffset + @param aOffsetMinutes + */ +void TInternetDateParser::ParseHHMMTimeOffsetL(const TDesC8& aTimeOffset, TTimeIntervalMinutes& aOffsetMinutes) + { + TInt offsetTextLength=aTimeOffset.Length(); + if (offsetTextLength != 5) // +0000 or -0000 + User::Leave(KErrCorrupt); + + TPtrC8 timeOffset(aTimeOffset.Right(offsetTextLength-1)); + + TInt num=0; + if (InetProtTextUtils::ConvertDescriptorToInt(timeOffset, num) !=4) + User::Leave(KErrCorrupt); // not 0000 + + TInt minutes = num % 100; + TInt hours = num / 100; + TInt offsetMinutes=0; + if (minutes < 60 && hours < 24) + offsetMinutes = minutes + (hours * 60); + + if (aTimeOffset[0] == '-') + offsetMinutes *= -1; + + aOffsetMinutes = offsetMinutes; + } + +/** + @param aTimeOffset + @param aOffsetMinutes + */ +void TInternetDateParser::ParseTimeOffsetL(const TDesC8& aTimeOffset, TTimeIntervalMinutes& aOffsetMinutes) + { + TInt offsetMinutes=0; + TInt offsetTextLength = aTimeOffset.Length(); + if (offsetTextLength > 1) + { + // check second letter to see if UT, GMT + // and to differentiate between Standard and Daylight Savings + switch (aTimeOffset[1]) + { + case 'M' : // GMT + case 'T' : // UT + { + return; + } + case 'S': // Standard Time (Daylight Savings Time is one hour ahead); + offsetMinutes -= 60; + break; + case 'D' : // Daylight Savings Time + break; + default: + // Must be either corrupt or an explicit HHMM +/- offset + ParseHHMMTimeOffsetL(aTimeOffset, aOffsetMinutes); + return; + }; + + // Check first letter to find out if its Eastern, Central, Mountain or Pacific Time + switch (aTimeOffset[0]) + { + case 'E' : // EST or EDT -4 + offsetMinutes -=240; + break; + case 'C' : // CST or CDT -5 + offsetMinutes -=300; + break; + case 'M' : // MST or MDT -6 + offsetMinutes -= 360; + break; + case 'P' : // PST or PDT -7 + offsetMinutes -=420; + break; + default: + // either the format is invalid or it is a non standard 3 letter timezone + // in either case + return; + }; + } + else // This must be a military single letter format time zone + // According to RFC2882 These Military Timezones are obsolete. Also since A can be either +1 or -1 depending on the specification + // it should be ignored unless there is additional Out of band Information + { + return; // Do nothing + } + + aOffsetMinutes = offsetMinutes; + } + +/** + @param aDateTimeText + @param aDateTime + */ +void TInternetDateParser::ParseHHMMSSTimeL(const TDesC8& aDateTimeText, TDateTime& aDateTime) + { + if (aDateTimeText.Length() < KHHMMSSFormatLength) // Must be at least HH:MM:SS + User::Leave(KErrCorrupt); + TInt num=0; + TInt consumed = InetProtTextUtils::ConvertDescriptorToInt(aDateTimeText, num); + if (consumed != 2 || num < 0 || num > 23) + User::Leave(KErrCorrupt); + TPtrC8 dateTime(aDateTimeText.Right(aDateTimeText.Length() -3)); // Remove HH: + aDateTime.SetHour(num); + + consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, num); + if (consumed != 2 || num < 0 || num > 59) + User::Leave(KErrCorrupt); + dateTime.Set(dateTime.Right(dateTime.Length() -3)); // Remove MM: + aDateTime.SetMinute(num); + + consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, num); + if (consumed != 2 || num < 0 || num > 59) + User::Leave(KErrCorrupt); + aDateTime.SetSecond(num); + } + +/** + @param aDateTimeText + @param aDateTime + @return + */ +TInt TInternetDateParser::ParseRfcDateDayMonthYearL(const TDesC8& aDateTimeText, TDateTime& aDateTime) + { + // Parse RFC 1123 and RFC 850 style date month year parts + // 06 Nov 1994 (RFC 1123) + // 06-Nov-94 (RFC 850) In this case if YY < 50 then treat as 20YY otherwise 19YY + TInt day =0; + TInt consumed = InetProtTextUtils::ConvertDescriptorToInt(aDateTimeText,day); + if ((consumed !=1 && consumed != 2) || aDateTimeText.Length() <= 2) + User::Leave(KErrCorrupt); + + --day; // Symbian OS month days start from 0 + + // Skip over DD and separator + TPtrC8 dateTimeText(aDateTimeText.Right(aDateTimeText.Length()-(consumed+1))); + TMonth month = GetMonthL(dateTimeText); + // Skip over MMM and separator + const TInt KConsumedMonthLength = 4; + TInt rightLength = dateTimeText.Length() - KConsumedMonthLength ; + if( rightLength < 0) + { + User::Leave(KErrCorrupt); + } + dateTimeText.Set(dateTimeText.Right(rightLength)); + + // Now get year + TInt year; + consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTimeText, year); + if (consumed != 4 && consumed !=2) + User::Leave(KErrCorrupt); + + // check for YY and adjust + if (consumed == 2) + year += year > 50 ? 1900 : 2000; + + if (aDateTime.Set(year, month, day, 0, 0, 0, 0) != KErrNone) + User::Leave(KErrCorrupt); + + return dateTimeText.Length() - (consumed +1); + } + +/** + @param aMonthText + @return + */ +TMonth TInternetDateParser::GetMonthL(const TDesC8& aMonthText) + { + if (aMonthText.Length() < 3) + User::Leave(KErrCorrupt); + + switch (aMonthText[0]) + { + case 'J': // Jan, Jun, Jul + return (aMonthText[1] == 'a' ? EJanuary : aMonthText[2] == 'n' ? EJune : EJuly); + case 'F': // Feb + return EFebruary; + case 'M': // Mar, May + return (aMonthText[2] == 'r' ? EMarch : EMay); + case 'A': // Apr, Aug + return (aMonthText[1] == 'p' ? EApril : EAugust); + case 'S': // Sep + return ESeptember; + case 'O': // Oct + return EOctober; + case 'N': // Nov + return ENovember; + case 'D': // Dec + return EDecember; + default: + User::Leave(KErrCorrupt); + }; + return EJanuary; + } + + +/** + @param aAscTimeDateTime + @param aDateTime + */ +void TInternetDateParser::ConvertFromAscTimeFormL(const TDesC8& aAscTimeDateTime, TDateTime& aDateTime) + { + // Convert a date in ascTime format ( Sun Nov 6 08:49:37 1994 ) + + const TChar KSpace = ' '; + + // First remove the wkDay + TPtrC8 dateTime(aAscTimeDateTime); + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveBoth); + TInt endOfWkDayLoc = dateTime.Locate(KSpace); + if (endOfWkDayLoc != 3) // Must be following a wkDay "Sun " + User::Leave(KErrCorrupt); + dateTime.Set(dateTime.Right(dateTime.Length() - 3)); + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft); + // Now parse the month then skip over MMM + TMonth month = GetMonthL(dateTime); + dateTime.Set(dateTime.Right(dateTime.Length() - 3)); + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft); + // Now parse the monthDay + TInt day = 0; + TInt consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, day); + if (consumed < 0) + User::Leave(KErrCorrupt); + + dateTime.Set(dateTime.Right(dateTime.Length() - consumed)); + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft); + + // Now get the time + ParseHHMMSSTimeL(dateTime, aDateTime); + dateTime.Set(dateTime.Right(dateTime.Length() - KHHMMSSFormatLength)); + // Now the year + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft); + TInt year; + consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, year); + if (consumed !=4) + User::Leave(KErrCorrupt); + + if (aDateTime.Set(year, month, day-1, aDateTime.Hour(), aDateTime.Minute(), aDateTime.Second(), 0) != KErrNone) + User::Leave(KErrCorrupt); + }