1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/ossrv/genericservices/httputils/internetdateutils/tinternetdateparser.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,413 @@
1.4 +// Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// This file contains the implementation of internal classes used to parse TInternetDate data
1.18 +//
1.19 +//
1.20 +
1.21 +/**
1.22 + @file tinternetdateparser.cpp
1.23 + @see tinternetdateparser.h
1.24 +*/
1.25 +
1.26 +#include "tinternetdateparser.h"
1.27 +#include "inetprottextutils.h"
1.28 +#include <e32base.h>
1.29 +
1.30 +//constants
1.31 +//
1.32 +const TInt KRfc1123DateTimeLength = 29; // Sun, 06 Nov 1994 08:49:37 GMT
1.33 +const TInt KHHMMSSFormatLength=8; // HH:MM:SS
1.34 +
1.35 +// Long form day names, 'weekday' in RFC850
1.36 +//
1.37 +static const TText8* const KInternetWeekDays[] =
1.38 + {
1.39 + _S8("Monday"),
1.40 + _S8("Tuesday"),
1.41 + _S8("Wednesday"),
1.42 + _S8("Thursday"),
1.43 + _S8("Friday"),
1.44 + _S8("Saturday"),
1.45 + _S8("Sunday")
1.46 + };
1.47 +
1.48 +// Month names, 'month' in RFC1123 & RFC850
1.49 +//
1.50 +static const TText8* const KInternetMonths[] =
1.51 + {
1.52 + _S8("Jan"),
1.53 + _S8("Feb"),
1.54 + _S8("Mar"),
1.55 + _S8("Apr"),
1.56 + _S8("May"),
1.57 + _S8("Jun"),
1.58 + _S8("Jul"),
1.59 + _S8("Aug"),
1.60 + _S8("Sep"),
1.61 + _S8("Oct"),
1.62 + _S8("Nov"),
1.63 + _S8("Dec")
1.64 + };
1.65 +
1.66 +/**
1.67 + Converts from TDateTime to Internet RFC1123 Style date strings
1.68 +
1.69 + @since 7.0
1.70 + @param aDateTime The date/time to be parsed
1.71 + @leave KErrNoMemory
1.72 + @return HBufC8* aDescriptor containing a RFC1123 style date.
1.73 +*/
1.74 +HBufC8* TInternetDateParser::ConvertToRfc1123FormL(const TDateTime& aDateTime)
1.75 + {
1.76 + const TChar KSpace = ' ';
1.77 +
1.78 + HBufC8* dateTime = HBufC8::NewLC(KRfc1123DateTimeLength);
1.79 + TPtr8 dateTimePtr = dateTime->Des();
1.80 + // Append the wkDay
1.81 + TTime time(aDateTime);
1.82 + TInt wkDay = time.DayNoInWeek();
1.83 + TPtrC8 wkDayText(KInternetWeekDays[wkDay]);
1.84 + dateTimePtr.Append(wkDayText.Left(3));
1.85 +
1.86 +
1.87 + // Append the day number
1.88 + _LIT8(KDayNumberFormat, ", %02d");
1.89 + TInt dayNumber = aDateTime.Day() + 1;
1.90 + dateTimePtr.AppendFormat(KDayNumberFormat, dayNumber);
1.91 +
1.92 + // Append month
1.93 + dateTimePtr.Append(KSpace);
1.94 + TInt month = aDateTime.Month();
1.95 + dateTimePtr.Append(TPtrC8(KInternetMonths[month]));
1.96 +
1.97 + // Append year
1.98 + _LIT8(KYearDigitFormat, " %4d");
1.99 + TInt year = aDateTime.Year();
1.100 + dateTimePtr.AppendFormat(KYearDigitFormat, year);
1.101 +
1.102 + // Append Time HH:MM:SS
1.103 +
1.104 + dateTimePtr.Append(KSpace);
1.105 + _LIT8(KHHMMSSFormat, "%02d:%02d:%02d GMT");
1.106 + dateTimePtr.AppendFormat(KHHMMSSFormat, aDateTime.Hour(),aDateTime.Minute(),aDateTime.Second());
1.107 +
1.108 + CleanupStack::Pop(dateTime);
1.109 + return dateTime;
1.110 + }
1.111 +
1.112 +
1.113 +/**
1.114 + Used to parse internet text date/time into a TDateTime
1.115 +
1.116 + @since 7.0
1.117 + @param aInternetTextDateTime The date/time in a text format
1.118 + @param aDateTime The result of parsing is placed here
1.119 + @leave KErrNoMemory, KErrCorrupt If the format of the descriptor is not valid
1.120 +*/
1.121 +void TInternetDateParser::ConvertFromInternetFormL(const TDesC8& aInternetTextDateTime, TDateTime& aDateTime)
1.122 + {
1.123 + const TChar KComma = ',';
1.124 + TInt colonLoc = aInternetTextDateTime.Locate(KComma);
1.125 + switch (colonLoc)
1.126 + {
1.127 + case -1: // ANSI C asctime() format: Sun Nov 6 08:49:37 1994
1.128 + ConvertFromAscTimeFormL(aInternetTextDateTime, aDateTime);
1.129 + break;
1.130 + case 3: // RFC 1123 Style Date: Sun, 06 Nov 1994 08:49:37 GMT
1.131 + case 6: // RFC 850 Style Date: Sunday, 06-Nov-94 08:49:37 GMT
1.132 + case 7:
1.133 + case 8:
1.134 + case 9:
1.135 + {
1.136 + TPtrC8 dateTime(aInternetTextDateTime.Right(aInternetTextDateTime.Length() -(colonLoc+1))); // Remove "<day>,"
1.137 + ConvertFromRfc1123And850FormL(dateTime, aDateTime);
1.138 + }
1.139 + break;
1.140 + default:
1.141 + User::Leave(KErrCorrupt);
1.142 + };
1.143 + }
1.144 +
1.145 +/**
1.146 + @param aRfcDateTime
1.147 + @param aDateTime The result of parsing is placed here
1.148 + */
1.149 +void TInternetDateParser::ConvertFromRfc1123And850FormL(const TDesC8& aRfcDateTime, TDateTime& aDateTime)
1.150 + {
1.151 + TPtrC8 dateTime(aRfcDateTime);
1.152 + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveBoth);
1.153 + TInt textLeft = ParseRfcDateDayMonthYearL(dateTime, aDateTime);
1.154 + if (textLeft <= 0)
1.155 + User::Leave(KErrCorrupt);
1.156 + dateTime.Set(dateTime.Right(textLeft));
1.157 + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
1.158 + ParseHHMMSSTimeL(dateTime, aDateTime);
1.159 + textLeft= dateTime.Length() - KHHMMSSFormatLength;
1.160 + if (textLeft > 1) // Must still have leading space
1.161 + {
1.162 + dateTime.Set(dateTime.Right(textLeft));
1.163 + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
1.164 + TTimeIntervalMinutes timeOffset = 0;
1.165 + ParseTimeOffsetL(dateTime, timeOffset);
1.166 +
1.167 + if (timeOffset.Int() > 0 || timeOffset.Int() < 0)
1.168 + {
1.169 + TTime time(aDateTime);
1.170 + time -= timeOffset;
1.171 + aDateTime = time.DateTime();
1.172 + }
1.173 + }
1.174 + else
1.175 + User::Leave(KErrCorrupt); // Must include a timezone or timeoffset
1.176 + }
1.177 +
1.178 +/**
1.179 + @param aTimeOffset
1.180 + @param aOffsetMinutes
1.181 + */
1.182 +void TInternetDateParser::ParseHHMMTimeOffsetL(const TDesC8& aTimeOffset, TTimeIntervalMinutes& aOffsetMinutes)
1.183 + {
1.184 + TInt offsetTextLength=aTimeOffset.Length();
1.185 + if (offsetTextLength != 5) // +0000 or -0000
1.186 + User::Leave(KErrCorrupt);
1.187 +
1.188 + TPtrC8 timeOffset(aTimeOffset.Right(offsetTextLength-1));
1.189 +
1.190 + TInt num=0;
1.191 + if (InetProtTextUtils::ConvertDescriptorToInt(timeOffset, num) !=4)
1.192 + User::Leave(KErrCorrupt); // not 0000
1.193 +
1.194 + TInt minutes = num % 100;
1.195 + TInt hours = num / 100;
1.196 + TInt offsetMinutes=0;
1.197 + if (minutes < 60 && hours < 24)
1.198 + offsetMinutes = minutes + (hours * 60);
1.199 +
1.200 + if (aTimeOffset[0] == '-')
1.201 + offsetMinutes *= -1;
1.202 +
1.203 + aOffsetMinutes = offsetMinutes;
1.204 + }
1.205 +
1.206 +/**
1.207 + @param aTimeOffset
1.208 + @param aOffsetMinutes
1.209 + */
1.210 +void TInternetDateParser::ParseTimeOffsetL(const TDesC8& aTimeOffset, TTimeIntervalMinutes& aOffsetMinutes)
1.211 + {
1.212 + TInt offsetMinutes=0;
1.213 + TInt offsetTextLength = aTimeOffset.Length();
1.214 + if (offsetTextLength > 1)
1.215 + {
1.216 + // check second letter to see if UT, GMT
1.217 + // and to differentiate between Standard and Daylight Savings
1.218 + switch (aTimeOffset[1])
1.219 + {
1.220 + case 'M' : // GMT
1.221 + case 'T' : // UT
1.222 + {
1.223 + return;
1.224 + }
1.225 + case 'S': // Standard Time (Daylight Savings Time is one hour ahead);
1.226 + offsetMinutes -= 60;
1.227 + break;
1.228 + case 'D' : // Daylight Savings Time
1.229 + break;
1.230 + default:
1.231 + // Must be either corrupt or an explicit HHMM +/- offset
1.232 + ParseHHMMTimeOffsetL(aTimeOffset, aOffsetMinutes);
1.233 + return;
1.234 + };
1.235 +
1.236 + // Check first letter to find out if its Eastern, Central, Mountain or Pacific Time
1.237 + switch (aTimeOffset[0])
1.238 + {
1.239 + case 'E' : // EST or EDT -4
1.240 + offsetMinutes -=240;
1.241 + break;
1.242 + case 'C' : // CST or CDT -5
1.243 + offsetMinutes -=300;
1.244 + break;
1.245 + case 'M' : // MST or MDT -6
1.246 + offsetMinutes -= 360;
1.247 + break;
1.248 + case 'P' : // PST or PDT -7
1.249 + offsetMinutes -=420;
1.250 + break;
1.251 + default:
1.252 + // either the format is invalid or it is a non standard 3 letter timezone
1.253 + // in either case
1.254 + return;
1.255 + };
1.256 + }
1.257 + else // This must be a military single letter format time zone
1.258 + // According to RFC2882 These Military Timezones are obsolete. Also since A can be either +1 or -1 depending on the specification
1.259 + // it should be ignored unless there is additional Out of band Information
1.260 + {
1.261 + return; // Do nothing
1.262 + }
1.263 +
1.264 + aOffsetMinutes = offsetMinutes;
1.265 + }
1.266 +
1.267 +/**
1.268 + @param aDateTimeText
1.269 + @param aDateTime
1.270 + */
1.271 +void TInternetDateParser::ParseHHMMSSTimeL(const TDesC8& aDateTimeText, TDateTime& aDateTime)
1.272 + {
1.273 + if (aDateTimeText.Length() < KHHMMSSFormatLength) // Must be at least HH:MM:SS
1.274 + User::Leave(KErrCorrupt);
1.275 + TInt num=0;
1.276 + TInt consumed = InetProtTextUtils::ConvertDescriptorToInt(aDateTimeText, num);
1.277 + if (consumed != 2 || num < 0 || num > 23)
1.278 + User::Leave(KErrCorrupt);
1.279 + TPtrC8 dateTime(aDateTimeText.Right(aDateTimeText.Length() -3)); // Remove HH:
1.280 + aDateTime.SetHour(num);
1.281 +
1.282 + consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, num);
1.283 + if (consumed != 2 || num < 0 || num > 59)
1.284 + User::Leave(KErrCorrupt);
1.285 + dateTime.Set(dateTime.Right(dateTime.Length() -3)); // Remove MM:
1.286 + aDateTime.SetMinute(num);
1.287 +
1.288 + consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, num);
1.289 + if (consumed != 2 || num < 0 || num > 59)
1.290 + User::Leave(KErrCorrupt);
1.291 + aDateTime.SetSecond(num);
1.292 + }
1.293 +
1.294 +/**
1.295 + @param aDateTimeText
1.296 + @param aDateTime
1.297 + @return
1.298 + */
1.299 +TInt TInternetDateParser::ParseRfcDateDayMonthYearL(const TDesC8& aDateTimeText, TDateTime& aDateTime)
1.300 + {
1.301 + // Parse RFC 1123 and RFC 850 style date month year parts
1.302 + // 06 Nov 1994 (RFC 1123)
1.303 + // 06-Nov-94 (RFC 850) In this case if YY < 50 then treat as 20YY otherwise 19YY
1.304 + TInt day =0;
1.305 + TInt consumed = InetProtTextUtils::ConvertDescriptorToInt(aDateTimeText,day);
1.306 + if ((consumed !=1 && consumed != 2) || aDateTimeText.Length() <= 2)
1.307 + User::Leave(KErrCorrupt);
1.308 +
1.309 + --day; // Symbian OS month days start from 0
1.310 +
1.311 + // Skip over DD and separator
1.312 + TPtrC8 dateTimeText(aDateTimeText.Right(aDateTimeText.Length()-(consumed+1)));
1.313 + TMonth month = GetMonthL(dateTimeText);
1.314 + // Skip over MMM and separator
1.315 + const TInt KConsumedMonthLength = 4;
1.316 + TInt rightLength = dateTimeText.Length() - KConsumedMonthLength ;
1.317 + if( rightLength < 0)
1.318 + {
1.319 + User::Leave(KErrCorrupt);
1.320 + }
1.321 + dateTimeText.Set(dateTimeText.Right(rightLength));
1.322 +
1.323 + // Now get year
1.324 + TInt year;
1.325 + consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTimeText, year);
1.326 + if (consumed != 4 && consumed !=2)
1.327 + User::Leave(KErrCorrupt);
1.328 +
1.329 + // check for YY and adjust
1.330 + if (consumed == 2)
1.331 + year += year > 50 ? 1900 : 2000;
1.332 +
1.333 + if (aDateTime.Set(year, month, day, 0, 0, 0, 0) != KErrNone)
1.334 + User::Leave(KErrCorrupt);
1.335 +
1.336 + return dateTimeText.Length() - (consumed +1);
1.337 + }
1.338 +
1.339 +/**
1.340 + @param aMonthText
1.341 + @return
1.342 + */
1.343 +TMonth TInternetDateParser::GetMonthL(const TDesC8& aMonthText)
1.344 + {
1.345 + if (aMonthText.Length() < 3)
1.346 + User::Leave(KErrCorrupt);
1.347 +
1.348 + switch (aMonthText[0])
1.349 + {
1.350 + case 'J': // Jan, Jun, Jul
1.351 + return (aMonthText[1] == 'a' ? EJanuary : aMonthText[2] == 'n' ? EJune : EJuly);
1.352 + case 'F': // Feb
1.353 + return EFebruary;
1.354 + case 'M': // Mar, May
1.355 + return (aMonthText[2] == 'r' ? EMarch : EMay);
1.356 + case 'A': // Apr, Aug
1.357 + return (aMonthText[1] == 'p' ? EApril : EAugust);
1.358 + case 'S': // Sep
1.359 + return ESeptember;
1.360 + case 'O': // Oct
1.361 + return EOctober;
1.362 + case 'N': // Nov
1.363 + return ENovember;
1.364 + case 'D': // Dec
1.365 + return EDecember;
1.366 + default:
1.367 + User::Leave(KErrCorrupt);
1.368 + };
1.369 + return EJanuary;
1.370 + }
1.371 +
1.372 +
1.373 +/**
1.374 + @param aAscTimeDateTime
1.375 + @param aDateTime
1.376 + */
1.377 +void TInternetDateParser::ConvertFromAscTimeFormL(const TDesC8& aAscTimeDateTime, TDateTime& aDateTime)
1.378 + {
1.379 + // Convert a date in ascTime format ( Sun Nov 6 08:49:37 1994 )
1.380 +
1.381 + const TChar KSpace = ' ';
1.382 +
1.383 + // First remove the wkDay
1.384 + TPtrC8 dateTime(aAscTimeDateTime);
1.385 + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveBoth);
1.386 + TInt endOfWkDayLoc = dateTime.Locate(KSpace);
1.387 + if (endOfWkDayLoc != 3) // Must be following a wkDay "Sun "
1.388 + User::Leave(KErrCorrupt);
1.389 + dateTime.Set(dateTime.Right(dateTime.Length() - 3));
1.390 + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
1.391 + // Now parse the month then skip over MMM
1.392 + TMonth month = GetMonthL(dateTime);
1.393 + dateTime.Set(dateTime.Right(dateTime.Length() - 3));
1.394 + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
1.395 + // Now parse the monthDay
1.396 + TInt day = 0;
1.397 + TInt consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, day);
1.398 + if (consumed < 0)
1.399 + User::Leave(KErrCorrupt);
1.400 +
1.401 + dateTime.Set(dateTime.Right(dateTime.Length() - consumed));
1.402 + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
1.403 +
1.404 + // Now get the time
1.405 + ParseHHMMSSTimeL(dateTime, aDateTime);
1.406 + dateTime.Set(dateTime.Right(dateTime.Length() - KHHMMSSFormatLength));
1.407 + // Now the year
1.408 + InetProtTextUtils::RemoveWhiteSpace(dateTime, InetProtTextUtils::ERemoveLeft);
1.409 + TInt year;
1.410 + consumed = InetProtTextUtils::ConvertDescriptorToInt(dateTime, year);
1.411 + if (consumed !=4)
1.412 + User::Leave(KErrCorrupt);
1.413 +
1.414 + if (aDateTime.Set(year, month, day-1, aDateTime.Hour(), aDateTime.Minute(), aDateTime.Second(), 0) != KErrNone)
1.415 + User::Leave(KErrCorrupt);
1.416 + }