Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Net / System / Net / _HTTPDateParse.cs / 1 / _HTTPDateParse.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- using System.Globalization; namespace System.Net { internal static class HttpDateParse { private const int BASE_DEC = 10; // base 10 // // Date indicies used to figure out what each entry is. // private const int DATE_INDEX_DAY_OF_WEEK = 0; private const int DATE_1123_INDEX_DAY = 1; private const int DATE_1123_INDEX_MONTH = 2; private const int DATE_1123_INDEX_YEAR = 3; private const int DATE_1123_INDEX_HRS = 4; private const int DATE_1123_INDEX_MINS = 5; private const int DATE_1123_INDEX_SECS = 6; private const int DATE_ANSI_INDEX_MONTH = 1; private const int DATE_ANSI_INDEX_DAY = 2; private const int DATE_ANSI_INDEX_HRS = 3; private const int DATE_ANSI_INDEX_MINS = 4; private const int DATE_ANSI_INDEX_SECS = 5; private const int DATE_ANSI_INDEX_YEAR = 6; private const int DATE_INDEX_TZ = 7; private const int DATE_INDEX_LAST = DATE_INDEX_TZ; private const int MAX_FIELD_DATE_ENTRIES = (DATE_INDEX_LAST+1); // // DATE_TOKEN's DWORD values used to determine what day/month we're on // private const int DATE_TOKEN_JANUARY = 1; private const int DATE_TOKEN_FEBRUARY = 2; private const int DATE_TOKEN_MARCH = 3; private const int DATE_TOKEN_APRIL = 4; private const int DATE_TOKEN_MAY = 5; private const int DATE_TOKEN_JUNE = 6; private const int DATE_TOKEN_JULY = 7; private const int DATE_TOKEN_AUGUST = 8; private const int DATE_TOKEN_SEPTEMBER = 9; private const int DATE_TOKEN_OCTOBER = 10; private const int DATE_TOKEN_NOVEMBER = 11; private const int DATE_TOKEN_DECEMBER = 12; private const int DATE_TOKEN_LAST_MONTH = (DATE_TOKEN_DECEMBER+1); private const int DATE_TOKEN_SUNDAY = 0; private const int DATE_TOKEN_MONDAY = 1; private const int DATE_TOKEN_TUESDAY = 2; private const int DATE_TOKEN_WEDNESDAY = 3; private const int DATE_TOKEN_THURSDAY = 4; private const int DATE_TOKEN_FRIDAY = 5; private const int DATE_TOKEN_SATURDAY = 6; private const int DATE_TOKEN_LAST_DAY = (DATE_TOKEN_SATURDAY+1); private const int DATE_TOKEN_GMT = -1000; private const int DATE_TOKEN_LAST = DATE_TOKEN_GMT; private const int DATE_TOKEN_ERROR = (DATE_TOKEN_LAST+1); // // MAKE_UPPER - takes an assumed lower character and bit manipulates into a upper. // (make sure the character is Lower case alpha char to begin, // otherwise it corrupts) // private static char MAKE_UPPER(char c) { return(Char.ToUpper(c, CultureInfo.InvariantCulture)); } /*++ Routine Description: Looks at the first three bytes of string to determine if we're looking at a Day of the Week, or Month, or "GMT" string. Is inlined so that the compiler can optimize this code into the caller FInternalParseHttpDate. Arguments: lpszDay - a string ptr to the first byte of the string in question. Return Value: DWORD Success - The Correct date token, 0-6 for day of the week, 1-14 for month, etc Failure - DATE_TOKEN_ERROR --*/ private static int MapDayMonthToDword( char [] lpszDay, int index ) { switch (MAKE_UPPER(lpszDay[index])) { // make uppercase case 'A': switch (MAKE_UPPER(lpszDay[index+1])) { case 'P': return DATE_TOKEN_APRIL; case 'U': return DATE_TOKEN_AUGUST; } return DATE_TOKEN_ERROR; case 'D': return DATE_TOKEN_DECEMBER; case 'F': switch (MAKE_UPPER(lpszDay[index+1])) { case 'R': return DATE_TOKEN_FRIDAY; case 'E': return DATE_TOKEN_FEBRUARY; } return DATE_TOKEN_ERROR; case 'G': return DATE_TOKEN_GMT; case 'M': switch (MAKE_UPPER(lpszDay[index+1])) { case 'O': return DATE_TOKEN_MONDAY; case 'A': switch (MAKE_UPPER(lpszDay[index+2])) { case 'R': return DATE_TOKEN_MARCH; case 'Y': return DATE_TOKEN_MAY; } // fall through to error break; } return DATE_TOKEN_ERROR; case 'N': return DATE_TOKEN_NOVEMBER; case 'J': switch (MAKE_UPPER(lpszDay[index+1])) { case 'A': return DATE_TOKEN_JANUARY; case 'U': switch (MAKE_UPPER(lpszDay[index+2])) { case 'N': return DATE_TOKEN_JUNE; case 'L': return DATE_TOKEN_JULY; } // fall through to error break; } return DATE_TOKEN_ERROR; case 'O': return DATE_TOKEN_OCTOBER; case 'S': switch (MAKE_UPPER(lpszDay[index+1])) { case 'A': return DATE_TOKEN_SATURDAY; case 'U': return DATE_TOKEN_SUNDAY; case 'E': return DATE_TOKEN_SEPTEMBER; } return DATE_TOKEN_ERROR; case 'T': switch (MAKE_UPPER(lpszDay[index+1])) { case 'U': return DATE_TOKEN_TUESDAY; case 'H': return DATE_TOKEN_THURSDAY; } return DATE_TOKEN_ERROR; case 'U': return DATE_TOKEN_GMT; case 'W': return DATE_TOKEN_WEDNESDAY; } return DATE_TOKEN_ERROR; } /*++ Routine Description: Parses through a ANSI, RFC850, or RFC1123 date format and covents it into a FILETIME/SYSTEMTIME time format. Important this a time-critical function and should only be changed with the intention of optimizing or a critical need work item. Arguments: lpft - Ptr to FILETIME structure. Used to store converted result. Must be NULL if not intended to be used !!! lpSysTime - Ptr to SYSTEMTIME struture. Used to return Systime if needed. lpcszDateStr - Const Date string to parse. Return Value: BOOL Success - TRUE Failure - FALSE --*/ public static bool ParseHttpDate( String DateString, out DateTime dtOut ) { int index = 0; int i = 0, iLastLettered = -1; bool fIsANSIDateFormat = false; int [] rgdwDateParseResults = new int[MAX_FIELD_DATE_ENTRIES]; bool fRet = true; char [] lpInputBuffer = DateString.ToCharArray(); dtOut = new DateTime(); // // Date Parsing v2 (1 more to go), and here is how it works... // We take a date string and churn through it once, converting // integers to integers, Month,Day, and GMT strings into integers, // and all is then placed IN order in a temp array. // // At the completetion of the parse stage, we simple look at // the data, and then map the results into the correct // places in the SYSTIME structure. Simple, No allocations, and // No dirting the data. // // The end of the function does something munging and pretting // up of the results to handle the year 2000, and TZ offsets // Note: do we need to fully handle TZs anymore? // while (index < DateString.Length && i < MAX_FIELD_DATE_ENTRIES) { if (lpInputBuffer[index] >= '0' && lpInputBuffer[index] <= '9') { // // we have a numerical entry, scan through it and convent to DWORD // rgdwDateParseResults[i] = 0; do { rgdwDateParseResults[i] *= BASE_DEC; rgdwDateParseResults[i] += (lpInputBuffer[index] - '0'); index++; } while (index < DateString.Length && lpInputBuffer[index] >= '0' && lpInputBuffer[index] <= '9'); i++; // next token } else if ((lpInputBuffer[index] >= 'A' && lpInputBuffer[index] <= 'Z') || (lpInputBuffer[index] >= 'a' && lpInputBuffer[index] <= 'z')) { // // we have a string, should be a day, month, or GMT // lets skim to the end of the string // rgdwDateParseResults[i] = MapDayMonthToDword(lpInputBuffer, index); iLastLettered = i; // We want to ignore the possibility of a time zone such as PST or EST in a non-standard // date format such as "Thu Dec 17 16:01:28 PST 1998" (Notice that the year is _after_ the time zone if ((rgdwDateParseResults[i] == DATE_TOKEN_ERROR) && !(fIsANSIDateFormat && (i==DATE_ANSI_INDEX_YEAR))) { fRet = false; goto quit; } // // At this point if we have a vaild string // at this index, we know for sure that we're // looking at a ANSI type DATE format. // if (i == DATE_ANSI_INDEX_MONTH) { fIsANSIDateFormat = true; } // // Read past the end of the current set of alpha characters, // as MapDayMonthToDword only peeks at a few characters // do { index++; } while (index < DateString.Length && ( (lpInputBuffer[index] >= 'A' && lpInputBuffer[index] <= 'Z') || (lpInputBuffer[index] >= 'a' && lpInputBuffer[index] <= 'z') )); i++; // next token } else { // // For the generic case its either a space, comma, semi-colon, etc. // the point is we really don't care, nor do we need to waste time // worring about it (the orginal code did). The point is we // care about the actual date information, So we just advance to the // next lexume. // index++; } } // // We're finished parsing the string, now take the parsed tokens // and turn them to the actual structured information we care about. // So we build lpSysTime from the Array, using a local if none is passed in. // int year; int month; int day; int hour; int minute; int second; int millisecond; millisecond = 0; if (fIsANSIDateFormat) { day = rgdwDateParseResults[DATE_ANSI_INDEX_DAY]; month = rgdwDateParseResults[DATE_ANSI_INDEX_MONTH]; hour = rgdwDateParseResults[DATE_ANSI_INDEX_HRS]; minute = rgdwDateParseResults[DATE_ANSI_INDEX_MINS]; second = rgdwDateParseResults[DATE_ANSI_INDEX_SECS]; if (iLastLettered != DATE_ANSI_INDEX_YEAR) { year = rgdwDateParseResults[DATE_ANSI_INDEX_YEAR]; } else { // This is a fix to get around toString/toGMTstring (where the timezone is // appended at the end. (See above) year = rgdwDateParseResults[DATE_INDEX_TZ]; } } else { day = rgdwDateParseResults[DATE_1123_INDEX_DAY]; month = rgdwDateParseResults[DATE_1123_INDEX_MONTH]; year = rgdwDateParseResults[DATE_1123_INDEX_YEAR]; hour = rgdwDateParseResults[DATE_1123_INDEX_HRS]; minute = rgdwDateParseResults[DATE_1123_INDEX_MINS]; second = rgdwDateParseResults[DATE_1123_INDEX_SECS]; } // // Normalize the year, 90 == 1990, handle the year 2000, 02 == 2002 // This is Year 2000 handling folks!!! We get this wrong and // we all look bad. // if (year < 100) { year += ((year < 80) ? 2000 : 1900); } // // if we got misformed time, then plug in the current time // !lpszHrs || !lpszMins || !lpszSec // if ((i < 4) || (day > 31) || (hour > 23) || (minute > 59) || (second > 59)) { fRet = false; goto quit; } // // Now do the DateTime conversion // dtOut = new DateTime (year, month, day, hour, minute, second, millisecond); // // we want the system time to be accurate. This is _suhlow_ // The time passed in is in the local time zone; we have to convert this into GMT. // if (iLastLettered==DATE_ANSI_INDEX_YEAR) { // this should be an unusual case. dtOut = dtOut.ToUniversalTime(); } // // If we have an Offset to another Time Zone // then convert to appropriate GMT time // if ((i > DATE_INDEX_TZ && rgdwDateParseResults[DATE_INDEX_TZ] != DATE_TOKEN_GMT)) { // // if we received +/-nnnn as offset (hhmm), modify the output FILETIME // double offset; offset = (double) rgdwDateParseResults[DATE_INDEX_TZ]; dtOut.AddHours(offset); } // In the end, we leave it all in LocalTime dtOut = dtOut.ToLocalTime(); quit: return fRet; } public static bool ParseCookieDate(string dateString, out DateTime dtOut) { // // The format variants // // 1) .NET HttpCookie = "dd-MMM-yyyy HH:mm:ss GMT'" // 2) Version0 = "dd-MMM-yy HH:mm:ss GMT" // 3) Some funky form = "dd MMM yyyy HH:mm:ss GMT" // // In all above cases we also accept single digit dd,hh,mm,ss // That's said what IE does. dtOut = DateTime.MinValue; char[] buffer = dateString.ToCharArray(); char ch; if (buffer.Length < 18) { //cover all before "ss" in the longest case return false; } int idx = 0; // Take the date int day=0; if (!Char.IsDigit(ch = buffer[idx++])) {return false;} else {day = ch-'0';} if (!Char.IsDigit(ch = buffer[idx++])) {--idx;} //one digit was used for a date else {day = day*10 +(ch-'0');} if (day > 31) {return false;} ++idx; //ignore delimiter and position on Month // Take the Month int month = MapDayMonthToDword(buffer, idx); if (month == DATE_TOKEN_ERROR) {return false;} idx+=4; //position after Month and ignore delimiter // Take the year int year=0; int i; for (i=0; i < 4; ++i) { if (!Char.IsDigit(ch = buffer[i+idx])) { // YY case if (i != 2) {return false;} else {break;} } year = year*10 + (ch-'0'); } //check for two digits if (i == 2) { year += ((year < 80) ? 2000 : 1900); } i += idx; //from now on 'i' is used as an index if (buffer[i++] != ' ') {return false;} //Take the hour int hour=0; if (!Char.IsDigit(ch = buffer[i++])) {return false;} else {hour = ch-'0';} if (!Char.IsDigit(ch = buffer[i++])) {--i;} //accept single digit else {hour = hour*10 +(ch-'0');} if (hour > 24 || buffer[i++] != ':') {return false;} //Take the min int min=0; if (!Char.IsDigit(ch = buffer[i++])) {return false;} else {min = ch-'0';} if (!Char.IsDigit(ch = buffer[i++])) {--i;} //accept single digit else {min = min*10 +(ch-'0');} if (min > 60 || buffer[i++] != ':') {return false;} //Check that the rest will fit the buffer size "[s]s GMT" if ((buffer.Length - i) < 5) {return false;} //Take the sec int sec=0; if (!Char.IsDigit(ch = buffer[i++])) {return false;} else {sec = ch-'0';} if (!Char.IsDigit(ch = buffer[i++])) {--i;} //accept single digit else {sec = sec*10 +(ch-'0');} if (sec > 60 || buffer[i++] != ' ') {return false;} //Test GMT if((buffer.Length - i) < 3 || buffer[i++] != 'G' || buffer[i++] != 'M' || buffer[i++] != 'T') { return false; } dtOut = new DateTime (year, month, day, hour, min, sec, 0).ToLocalTime(); return true; } } } // namespace System.Net
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- EncryptedXml.cs
- BrushProxy.cs
- RealizationContext.cs
- URLAttribute.cs
- StylusPoint.cs
- ExpressionBindingCollection.cs
- RoleManagerModule.cs
- TagMapInfo.cs
- AttributeQuery.cs
- ConfigurationManagerInternalFactory.cs
- SQLChars.cs
- XmlRawWriterWrapper.cs
- ObjectStateFormatter.cs
- Facet.cs
- WebPartUserCapability.cs
- XmlAttributeAttribute.cs
- COM2FontConverter.cs
- LinqDataSourceStatusEventArgs.cs
- StrokeCollectionDefaultValueFactory.cs
- XmlExtensionFunction.cs
- EventWaitHandleSecurity.cs
- ManagedFilter.cs
- SqlInternalConnection.cs
- XmlDeclaration.cs
- CapacityStreamGeometryContext.cs
- PartialTrustVisibleAssemblyCollection.cs
- AnnotationHighlightLayer.cs
- ObjectAnimationBase.cs
- IApplicationTrustManager.cs
- SymbolType.cs
- AuthorizationSection.cs
- ErrorHandlerModule.cs
- StorageConditionPropertyMapping.cs
- ValidationRule.cs
- DataList.cs
- EntitySetDataBindingList.cs
- BrowserDefinition.cs
- UiaCoreApi.cs
- AggregateNode.cs
- loginstatus.cs
- DocumentGridContextMenu.cs
- ElementsClipboardData.cs
- JsonGlobals.cs
- ClientProtocol.cs
- ColorEditor.cs
- MethodBuilder.cs
- StringValidatorAttribute.cs
- ProcessHostMapPath.cs
- Html32TextWriter.cs
- TextProviderWrapper.cs
- EntityDataSourceEntitySetNameItem.cs
- TagElement.cs
- ResourcePermissionBase.cs
- DataGridParentRows.cs
- SQLString.cs
- Matrix.cs
- RegexNode.cs
- SqlEnums.cs
- LayoutTable.cs
- ServiceOperationListItem.cs
- CommonRemoteMemoryBlock.cs
- IdentityHolder.cs
- TokenBasedSetEnumerator.cs
- MenuBindingsEditor.cs
- InputLanguageProfileNotifySink.cs
- DynamicDiscoSearcher.cs
- DataContractJsonSerializer.cs
- XamlPoint3DCollectionSerializer.cs
- Constant.cs
- SqlCacheDependency.cs
- DataControlFieldCell.cs
- FormViewUpdateEventArgs.cs
- linebase.cs
- HtmlImage.cs
- XmlSerializer.cs
- ViewgenGatekeeper.cs
- GlobalizationSection.cs
- Vector3DCollectionValueSerializer.cs
- ClientSettingsSection.cs
- FullTrustAssembly.cs
- SpellerStatusTable.cs
- XPathNodeInfoAtom.cs
- InputManager.cs
- LicenseManager.cs
- Vars.cs
- ExpressionPrefixAttribute.cs
- DataRelation.cs
- formatter.cs
- FtpWebRequest.cs
- FtpRequestCacheValidator.cs
- LinqDataSourceHelper.cs
- Quack.cs
- DataObjectSettingDataEventArgs.cs
- WebHttpBindingCollectionElement.cs
- SecurityState.cs
- SimpleMailWebEventProvider.cs
- IPAddress.cs
- IndentedWriter.cs
- WebPartsSection.cs
- _HelperAsyncResults.cs