HttpDateParse.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx35 / System.ServiceModel.Web / System / ServiceModel / Web / HttpDateParse.cs / 1305376 / HttpDateParse.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
namespace System.ServiceModel.Web
{ 
    using System;
    using System.Globalization; 
 
    // DO NOT EDIT THIS CODE.
    // 
    // All of the code from this class was taken from build 20717.00
    // of System.Net.HttpDateParse.  If there is a bug with this code
    // it should be fixed  in the original System.Net.HttpDateParse
    // and then ported here. [[....]] 

    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_[....] = 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);
 
        // 
        // MakeUpper - 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)
        //
        static char MakeUpper(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
        static int MapDayMonthToDword(char[] lpszDay, int index) 
        { 
            switch (MakeUpper(lpszDay[index]))
            { // make uppercase 
                case 'A':
                    switch (MakeUpper(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 (MakeUpper(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 (MakeUpper(lpszDay[index + 1])) 
                    {
                        case 'O': 
                            return DATE_TOKEN_MONDAY; 
                        case 'A':
                            switch (MakeUpper(lpszDay[index + 2])) 
                            {
                                case 'R':
                                    return DATE_TOKEN_[....];
                                case 'Y': 
                                    return DATE_TOKEN_MAY;
                            } 
 
                            // fall through to error
                            break; 
                    }

                    return DATE_TOKEN_ERROR;
 
                case 'N':
                    return DATE_TOKEN_NOVEMBER; 
 
                case 'J':
 
                    switch (MakeUpper(lpszDay[index + 1]))
                    {
                        case 'A':
                            return DATE_TOKEN_JANUARY; 

                        case 'U': 
                            switch (MakeUpper(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 (MakeUpper(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 (MakeUpper(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
        internal 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; 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK