timerep.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:23k
源码类别:

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: timerep.cpp,v 1.11.32.3 2004/07/09 01:48:16 hubbe Exp $
  3.  * 
  4.  * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
  5.  * 
  6.  * The contents of this file, and the files included with this file,
  7.  * are subject to the current version of the RealNetworks Public
  8.  * Source License (the "RPSL") available at
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed
  10.  * the file under the current version of the RealNetworks Community
  11.  * Source License (the "RCSL") available at
  12.  * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
  13.  * will apply. You may also obtain the license terms directly from
  14.  * RealNetworks.  You may not use this file except in compliance with
  15.  * the RPSL or, if you have a valid RCSL with RealNetworks applicable
  16.  * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
  17.  * the rights, obligations and limitations governing use of the
  18.  * contents of the file.
  19.  * 
  20.  * Alternatively, the contents of this file may be used under the
  21.  * terms of the GNU General Public License Version 2 or later (the
  22.  * "GPL") in which case the provisions of the GPL are applicable
  23.  * instead of those above. If you wish to allow use of your version of
  24.  * this file only under the terms of the GPL, and not to allow others
  25.  * to use your version of this file under the terms of either the RPSL
  26.  * or RCSL, indicate your decision by deleting the provisions above
  27.  * and replace them with the notice and other provisions required by
  28.  * the GPL. If you do not delete the provisions above, a recipient may
  29.  * use your version of this file under the terms of any one of the
  30.  * RPSL, the RCSL or the GPL.
  31.  * 
  32.  * This file is part of the Helix DNA Technology. RealNetworks is the
  33.  * developer of the Original Code and owns the copyrights in the
  34.  * portions it created.
  35.  * 
  36.  * This file, and the files included with this file, is distributed
  37.  * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
  38.  * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
  39.  * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
  40.  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
  41.  * ENJOYMENT OR NON-INFRINGEMENT.
  42.  * 
  43.  * Technology Compatibility Kit Test Suite(s) Location:
  44.  *    http://www.helixcommunity.org/content/tck
  45.  * 
  46.  * Contributor(s):
  47.  * 
  48.  * ***** END LICENSE BLOCK ***** */
  49. #include "hlxclib/stdlib.h"
  50. #include "hlxclib/string.h"
  51. #include <ctype.h>
  52. #include "hxstrutl.h"
  53. #include "timerep.h"
  54. #ifdef _OPENWAVE
  55. #include "hlxclib/time.h"
  56. #endif /* _OPENWAVE */
  57. #include "hxassert.h"
  58. #include "hxheap.h"
  59. #ifdef _DEBUG
  60. #undef HX_THIS_FILE
  61. static const char HX_THIS_FILE[] = __FILE__;
  62. #endif
  63. #define SECS_PER_MIN    60
  64. #define SECS_PER_HOUR   (60*SECS_PER_MIN)
  65. #define SECS_PER_DAY    (24*SECS_PER_HOUR)
  66. #define SECS_PER_YEAR   (365*SECS_PER_DAY)
  67. #ifdef _WIN32
  68. #include <olectl.h>
  69. // Conversions between FILETIME and time_t
  70. static const UINT64 EPOCH_DIFF_DAYS = 134774;
  71. static const UINT64 EPOCH_DIFF_SECS = (EPOCH_DIFF_DAYS*SECS_PER_DAY);
  72. static const UINT64 SECS_TO_100NS   = 10000000;
  73. static void TimetToFileTime( time_t t, LPFILETIME pft )
  74. {
  75.     UINT64 u = ((UINT64)t + EPOCH_DIFF_SECS) * SECS_TO_100NS;
  76.     pft->dwLowDateTime = (DWORD)u;
  77.     pft->dwHighDateTime = (DWORD)(u>>32);
  78. }
  79. static time_t FileTimeToTimet( LPFILETIME pft )
  80. {
  81.     UINT64 u = ((UINT64)pft->dwHighDateTime << 32) |
  82.                ((UINT64)pft->dwLowDateTime);
  83.     return (time_t)( u / SECS_TO_100NS - EPOCH_DIFF_SECS );
  84. }
  85. #endif /* _WIN32 */
  86. /*
  87.  * To reproduce g_monthoffset using GNU date(2) and bash(1):
  88.  *   for N in 1 2 3 4 5 6 7 8 9 10 11 12; do
  89.  *     date -u --date="1/$N/1970" +%s
  90.  *   done
  91.  *
  92.  * To reproduce g_monthleapoffset, add SECS_PER_DAY to 2..11
  93.  */
  94. static const time_t g_monthoffset[12] =
  95.     {        0,  2678400,  5097600,  7776000, 10368000, 13046400,
  96.       15638400, 18316800, 20995200, 23587200, 26265600, 28857600 };
  97. static const int g_monthleapoffset[12] =
  98.     {        0,  2678400,  5184000, 7862400,  10454400, 13132800,
  99.       15724800, 18403200, 21081600, 23673600, 26352000, 28944000 };
  100. static const int g_monthdays[12] =
  101.     { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  102. static const int g_monthleapdays[12] =
  103.     { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  104. static const char* const g_wkday_names[7] =
  105.     { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
  106. static const char* const g_weekday_names[7] =
  107.     { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
  108. static const char* const g_mon_names[12] =
  109.     { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  110.       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
  111. static const char* const g_month_names[12] =
  112.     { "January", "February", "March",     "April",   "May",      "June",
  113.       "July",    "August",   "September", "October", "November", "December" };
  114. static inline const char* wkday_to_str(int n)
  115. {
  116.     return ( (n >= 0 && n < 7) ? g_wkday_names[n] : NULL );
  117. }
  118. static inline const char* weekday_to_str(int n)
  119. {
  120.     return ( (n >= 0 && n < 7) ? g_weekday_names[n] : NULL );
  121. }
  122. static inline const char* mon_to_str(int n)
  123. {
  124.     return ( (n >= 0 && n < 12) ? g_mon_names[n] : NULL );
  125. }
  126. static inline const char* month_to_str(int n)
  127. {
  128.     return ( (n >= 0 && n < 12) ? g_month_names[n] : NULL );
  129. }
  130. static int weekday_from_string(const char* pStr)
  131. {
  132.     int n;
  133.     for (n = 0; n < 7; n++)
  134.     {
  135.         if (strncasecmp(g_wkday_names[n], pStr, 3) == 0)
  136.         {
  137.             return n;
  138.         }
  139.     }
  140.     return -1;
  141. }
  142. static int month_from_string(const char* pStr)
  143. {
  144.     int n;
  145.     for (n = 0; n < 12; n++)
  146.     {
  147.         if (strncasecmp(g_mon_names[n], pStr, 3) == 0)
  148.         {
  149.             return n;
  150.         }
  151.     }
  152.     return -1;
  153. }
  154. /*
  155.  * We assume 32-bit signed time_t and disallow years prior to 1970 here.
  156.  * Supporting 64-bit time_t and years prior to 1970 are not trivial, as
  157.  * time_t values are commonly converted to UINT32 (eg. stat results).
  158.  *
  159.  * We also require input values to be within their legal intervals to avoid
  160.  * normalization overhead.  This is not required by mktime(3).
  161.  */
  162. time_t mktime_gmt(struct tm* ptm)
  163. {
  164.     time_t t = 0;
  165.     if (ptm == NULL)
  166.     {
  167.         HX_ASSERT(FALSE);
  168.         goto bail;
  169.     }
  170.     // Calculate seconds to beginning of year (including leap days)
  171.     // eg. one leap day for 1973..1976, two for 1977..1980, etc.
  172.     // Year 2000 was a leap year so the leap calculation is easy
  173.     if (ptm->tm_year < 70 || ptm->tm_year > 137)
  174.     {
  175.         goto bail;
  176.     }
  177.     t = SECS_PER_YEAR * (ptm->tm_year-70) +
  178.         SECS_PER_DAY * ((ptm->tm_year-69)/4);
  179.     // Add seconds to beginning of day (including leap day, if needed)
  180.     if (ptm->tm_mon < 0 || ptm->tm_mon > 11)
  181.     {
  182.         goto bail;
  183.     }
  184.     if (ptm->tm_year%4)
  185.     {
  186.         t += g_monthoffset[ptm->tm_mon];
  187.         if (ptm->tm_mday < 1 || ptm->tm_mday > g_monthdays[ptm->tm_mon])
  188.         {
  189.             goto bail;
  190.         }
  191.     }
  192.     else
  193.     {
  194.         t += g_monthleapoffset[ptm->tm_mon];
  195.         if (ptm->tm_mday < 1 || ptm->tm_mday > g_monthleapdays[ptm->tm_mon])
  196.         {
  197.             goto bail;
  198.         }
  199.     }
  200.     t += SECS_PER_DAY * (ptm->tm_mday - 1);
  201.     // Add hours, minutes, seconds
  202.     // Note: we allow up to 62 seconds per minute for "leap seconds"
  203.     if (ptm->tm_hour < 0 || ptm->tm_hour > 23 ||
  204.         ptm->tm_min  < 0 || ptm->tm_min  > 59 ||
  205.         ptm->tm_sec  < 0 || ptm->tm_sec  > 61)
  206.     {
  207.         goto bail;
  208.     }
  209.     t += ptm->tm_hour*SECS_PER_HOUR + ptm->tm_min*SECS_PER_MIN + ptm->tm_sec;
  210.     return t;
  211. bail:
  212.     return INVALID_TIME_T;
  213. }
  214. // Win16 and WinCE lack strftime() so implement it here...
  215. #if defined(_WIN16) || defined(WIN32_PLATFORM_PSPC)
  216. /*
  217.  * In all of the following make_xxx functions, the following hold true:
  218.  *   - If the destination length is too small to hold the result, the
  219.  *     buffer is not touched and pDest is not advanced.
  220.  *   - nLen is always updated using the length of the source string.
  221.  *
  222.  * Thus, we can detect overflow by checking nLen against nDestLen and the
  223.  * NULL terminator is always placed at pDest with no overflow worries.
  224.  */
  225. static void make_wkday(char*& pDest, size_t nDestLen, int n, size_t& nLen)
  226. {
  227.     const char* pStr = wkday_to_str(n);
  228.     if (pStr != NULL)
  229.     {
  230.         size_t nStrLen = strlen(pStr);
  231.         if (nLen + nStrLen < nDestLen)
  232.         {
  233.             strcpy(pDest, pStr); /* Flawfinder: ignore */
  234.             pDest += nStrLen;
  235.         }
  236.         nLen += nStrLen;
  237.     }
  238. }
  239. static void make_weekday(char*& pDest, size_t nDestLen, int n, size_t& nLen)
  240. {
  241.     const char* pStr = weekday_to_str(n);
  242.     if (pStr != NULL)
  243.     {
  244.         size_t nStrLen = strlen(pStr);
  245.         if (nLen + nStrLen < nDestLen)
  246.         {
  247.             strcpy(pDest, pStr); /* Flawfinder: ignore */
  248.             pDest += nStrLen;
  249.         }
  250.         nLen += nStrLen;
  251.     }
  252. }
  253. static void make_mon(char*& pDest, size_t nDestLen, int n, size_t& nLen)
  254. {
  255.     const char* pStr = mon_to_str(n);
  256.     if (pStr != NULL)
  257.     {
  258.         size_t nStrLen = strlen(pStr);
  259.         if (nLen + nStrLen < nDestLen)
  260.         {
  261.             strcpy(pDest, pStr); /* Flawfinder: ignore */
  262.             pDest += nStrLen;
  263.         }
  264.         nLen += nStrLen;
  265.     }
  266. }
  267. static void make_month(char*& pDest, size_t nDestLen, int n, size_t& nLen)
  268. {
  269.     const char* pStr = month_to_str(n);
  270.     if (pStr != NULL)
  271.     {
  272.         size_t nStrLen = strlen(pStr);
  273.         if (nLen + nStrLen < nDestLen)
  274.         {
  275.             strcpy(pDest, pStr); /* Flawfinder: ignore */
  276.             pDest += nStrLen;
  277.         }
  278.         nLen += nStrLen;
  279.     }
  280. }
  281. static void make_value(char*& pDest, size_t nDestLen, int n, size_t& nLen)
  282. {
  283.     char szBuffer[16]; /* Flawfinder: ignore */
  284.     _itoa(n, szBuffer, 10);
  285.     size_t nStrLen = strlen(szBuffer);
  286.     if (nLen + nStrLen < nDestLen)
  287.     {
  288.         strcpy(pDest, szBuffer); /* Flawfinder: ignore */
  289.         pDest += nStrLen;
  290.     }
  291.     nLen += nStrLen;
  292. }
  293. size_t strftime16(char* pDest, size_t nDestLen, const char* pFormat, const struct tm* ptm)
  294. {
  295.     size_t nLen = 0;
  296.     if (pDest == NULL)
  297.     {
  298.         HX_ASSERT(FALSE);
  299.         return 0;
  300.     }
  301.     pDest[0] = '';
  302.     if (pFormat == NULL)
  303.     {
  304.         return 0;
  305.     }
  306.     while (*pFormat && nLen < nDestLen)
  307.     {
  308.         if (*pFormat == '%' && *(pFormat+1) != '')
  309.         {
  310.             pFormat++;
  311.             switch (*pFormat)
  312.             {
  313.             case 'a':       // abbreviated weekday name
  314.                 make_wkday(pDest, nDestLen, ptm->tm_wday, nLen);
  315.                 break;
  316.             case 'A':       // full weekday name
  317.                 make_weekday(pDest, nDestLen, ptm->tm_wday, nLen);
  318.                 break;
  319.             case 'b':       // abbreviated month name
  320.                 make_mon(pDest, nDestLen, ptm->tm_wday, nLen);
  321.                 break;
  322.             case 'B':       // full month name
  323.                 make_month(pDest, nDestLen, ptm->tm_wday, nLen);
  324.                 break;
  325.             case 'd':       // day of month in decimal
  326.                 make_value(pDest, nDestLen, ptm->tm_mday, nLen);
  327.                 break;
  328.             case 'H':       // hour in 24-hr format
  329.                 make_value(pDest, nDestLen, ptm->tm_hour, nLen);
  330.                 break;
  331.             case 'm':       // month as decimal number
  332.                 make_value(pDest, nDestLen, ptm->tm_mon+1, nLen);
  333.                 break;
  334.             case 'M':       // minutes as decimal number
  335.                 make_value(pDest, nDestLen, ptm->tm_min, nLen);
  336.                 break;
  337.             case 'S':       // seconds as decimal number
  338.                 make_value(pDest, nDestLen, ptm->tm_sec, nLen);
  339.                 break;
  340.             case 'y':       // year without century
  341.                 make_value(pDest, nDestLen, ptm->tm_year, nLen);
  342.                 break;
  343.             case 'Y':       // year with century
  344.                 make_value(pDest, nDestLen, ptm->tm_year+1900, nLen);
  345.                 break;
  346.             default:       // add more options if needed
  347.                 break;
  348.             }
  349.         }
  350.         else
  351.         {
  352.             if (nLen+1 < nDestLen)
  353.             {
  354.                 *pDest = *pFormat;
  355.                 pDest++;
  356.             }
  357.             nLen++;
  358.         }
  359.         pFormat++;
  360.     }
  361.     *pDest = '';
  362.     return nLen;
  363. }
  364. #endif /* _WIN16 || WIN32_PLATFORM_PSPC */
  365. UTCTimeRep::UTCTimeRep(void)
  366. {
  367.     m_szTime[0] = '';
  368.     fromUTCTime(time(NULL));
  369. }
  370. UTCTimeRep::UTCTimeRep(const char* pStr)
  371. {
  372.     m_szTime[0] = '';
  373.     fromString(pStr);
  374. }
  375. UTCTimeRep::UTCTimeRep(time_t t, BOOL bUTC /* = TRUE */)
  376. {
  377.     m_szTime[0] = '';
  378.     bUTC ? fromUTCTime(t) : fromTime(t);
  379. }
  380. UTCTimeRep::~UTCTimeRep(void)
  381. {
  382.     // Empty
  383. }
  384. const char*
  385. UTCTimeRep::asRFC1123String(void)
  386. {
  387.     m_szTime[0] = '';
  388.     struct tm* ptm = NULL;
  389.     // If our time is valid, fetch a struct tm in GMT.
  390. #ifdef _USE_THREADSAFE_TIME_FUNCS
  391.     struct tm tmgmt;
  392.     if (m_tTime != INVALID_TIME_T)
  393.     {
  394.         ptm = gmtime_r(&m_tTime, &tmgmt);
  395.     }
  396. #else
  397.     if (m_tTime != INVALID_TIME_T)
  398.     {
  399.         ptm = gmtime(&m_tTime);
  400.     }
  401. #endif
  402.     // If the struct tm is good, create the string.
  403.     if (ptm != NULL)
  404.     {
  405. #if defined(_WIN16) || defined(WIN32_PLATFORM_PSPC)
  406.         if (strftime16(m_szTime, MAX_UTC_TIME_LEN, "%a, %d %b %Y %H:%M:%S GMT", ptm) == 0)
  407. #else
  408.         if (strftime(m_szTime, MAX_UTC_TIME_LEN, "%a, %d %b %Y %H:%M:%S GMT", ptm) == 0)
  409. #endif
  410.         {
  411.             // If there is an error, the string is undefined so empty it.
  412.             m_szTime[0] = '';
  413.         }
  414.     }
  415.     return m_szTime;
  416. }
  417. const char*
  418. UTCTimeRep::asRFC850String(void)
  419. {
  420.     m_szTime[0] = '';
  421.     struct tm* ptm = NULL;
  422.     // If our time is valid, fetch a struct tm in GMT.
  423. #ifdef _USE_THREADSAFE_TIME_FUNCS
  424.     struct tm tmgmt;
  425.     if (m_tTime != INVALID_TIME_T)
  426.     {
  427.         ptm = gmtime_r(&m_tTime, &tmgmt);
  428.     }
  429. #else
  430.     if (m_tTime != INVALID_TIME_T)
  431.     {
  432.         ptm = gmtime(&m_tTime);
  433.     }
  434. #endif
  435.     // If the struct tm is good, create the string.
  436.     if (ptm != NULL)
  437.     {
  438. #if defined(_WIN16) || defined(WIN32_PLATFORM_PSPC)
  439.         if (strftime16(m_szTime, MAX_UTC_TIME_LEN, "%A, %d-%b-%y %H:%M:%S GMT", ptm) == 0)
  440. #else
  441.         if (strftime(m_szTime, MAX_UTC_TIME_LEN, "%A, %d-%b-%y %H:%M:%S GMT", ptm) == 0)
  442. #endif
  443.         {
  444.             m_szTime[0] = '';
  445.         }
  446.     }
  447.     return m_szTime;
  448. }
  449. const char*
  450. UTCTimeRep::asUTCString(void)
  451. {
  452.     m_szTime[0] = '';
  453.     struct tm* ptm = NULL;
  454.     // If our time is valid, fetch a struct tm in GMT.
  455. #ifdef _USE_THREADSAFE_TIME_FUNCS
  456.     struct tm tmgmt;
  457.     if (m_tTime != INVALID_TIME_T)
  458.     {
  459.         ptm = gmtime_r(&m_tTime, &tmgmt);
  460.     }
  461. #else
  462.     if (m_tTime != INVALID_TIME_T)
  463.     {
  464.         ptm = gmtime(&m_tTime);
  465.     }
  466. #endif
  467.     // If the struct tm is good, create the string.
  468.     if (ptm != NULL)
  469.     {
  470. #if defined(_WIN16) || defined(WIN32_PLATFORM_PSPC)
  471.         if (strftime16(m_szTime, MAX_UTC_TIME_LEN, "%Y%m%dT%H%M%SZ", ptm) == 0)
  472. #else
  473.         if (strftime(m_szTime, MAX_UTC_TIME_LEN, "%Y%m%dT%H%M%SZ", ptm) == 0)
  474. #endif
  475.         {
  476.             m_szTime[0] = '';
  477.         }
  478.     }
  479.     return m_szTime;
  480. }
  481. time_t
  482. UTCTimeRep::asUTCTimeT(void)
  483. {
  484.     return m_tTime;
  485. }
  486. void UTCTimeRep::SetLocalTime(time_t t)
  487. {
  488.     fromTime(t);
  489. }
  490. void UTCTimeRep::SetUTCTime(time_t t)
  491. {
  492.     fromUTCTime(t);
  493. }
  494. void UTCTimeRep::SetTime(const char* pStr)
  495. {
  496.     fromString(pStr);
  497. }
  498. /*
  499.  * Convert time_t value from localtime to gmt.  First we call gmtime() to get
  500.  * a struct tm in localtime.  This works because gmtime() does no timezone
  501.  * conversions -- the result is in the same timezone as the input.  Then we
  502.  * call mktime() which converts a struct tm in localtime to a time_t in GMT.
  503.  *
  504.  * Win32 always assumes GMT for mktime(), so we use LocalFileTimeToFileTime()
  505.  * and a pair of conversion functions.
  506.  */
  507. int
  508. UTCTimeRep::fromTime(time_t t)
  509. {
  510. #ifdef _WIN32
  511.     FILETIME lft, ft;
  512.     TimetToFileTime(t, &lft);
  513.     LocalFileTimeToFileTime(&lft, &ft);
  514.     m_tTime = FileTimeToTimet(&ft);
  515.     return 0;
  516. #else /* ! _WIN32 */
  517. #ifdef _USE_THREADSAFE_TIME_FUNCS
  518.     struct tm tmlocal;
  519.     struct tm* ptm = gmtime_r(&t, &tmlocal);
  520. #else
  521.     struct tm* ptm = gmtime(&t);
  522. #endif
  523.     if (ptm != NULL)
  524.     {
  525.         m_tTime = mktime(ptm);
  526.         return 0;
  527.     }
  528.     m_tTime = INVALID_TIME_T;
  529.     return -1;
  530. #endif /* _WIN32 */
  531. }
  532. int
  533. UTCTimeRep::fromUTCTime(time_t t)
  534. {
  535.     m_tTime = t;
  536.     return 0;
  537. }
  538. int
  539. UTCTimeRep::fromTm(struct tm* ptm)
  540. {
  541. #ifdef _WIN32
  542.     // See note above in fromTime()
  543.     time_t t = mktime_gmt(ptm);
  544.     if (t != INVALID_TIME_T)
  545.     {
  546.         fromTime(t);
  547.         return 0;
  548.     }
  549.     return -1;
  550. #else /* ! _WIN32 */
  551.     if (ptm != NULL)
  552.     {
  553.         m_tTime = mktime(ptm);
  554.         return 0;
  555.     }
  556.     m_tTime = INVALID_TIME_T;
  557.     return -1;
  558. #endif /* _WIN32 */
  559. }
  560. int
  561. UTCTimeRep::fromUTCTm(struct tm* ptm)
  562. {
  563.     m_tTime = mktime_gmt(ptm);
  564.     return ( (m_tTime == INVALID_TIME_T) ? -1 : 0 );
  565. }
  566. // Find next alnum field in string or bail if not found
  567. #define NEXT_ALNUM_FIELD(p) 
  568.     while ( isalnum(*p)) { p++; if (*p == '') goto bail; } 
  569.     while (!isalnum(*p)) { p++; if (*p == '') goto bail; }
  570. int
  571. UTCTimeRep::fromString(const char* pStr)
  572. {
  573.     unsigned int n;
  574.     struct tm stm;
  575.     memset(&stm, 0, sizeof(stm));
  576.     if (pStr == NULL || pStr[0] == '')
  577.     {
  578.         goto bail;
  579.     }
  580.     /*
  581.      * RFC1123: wkday "," SP DD SP month SP YYYY HH:MM:SS (Wed, 02 Jun 1982)
  582.      * RFC850 : weekday "," SP DD-month-YY HH:MM:SS       (Wednesday, 02-Jun-82)
  583.      * asctime: wkday SP month SP dD HH:MM:SS YYYY        (Wed Jun  2 09:00:00 1982)
  584.      * UTC    : YYYYMMDD'T'HHMMSS'Z'
  585.      */
  586.     if (isdigit(pStr[0]))
  587.     {
  588.         // UTC
  589.         if(strlen(pStr) != 16)
  590.         {
  591.             goto bail;
  592.         }
  593.         for (n = 0; n < 8; n++)
  594.         {
  595.             if (!isdigit(pStr[n]))
  596.             {
  597.                 goto bail;
  598.             }
  599.         }
  600.         stm.tm_year = (pStr[0]-'0')*1000 + (pStr[1]-'0')*100 +
  601.                       (pStr[2]-'0')*10 + (pStr[3]-'0') - 1900;
  602.         stm.tm_mon = (pStr[4]-'0')*10 + (pStr[5]-'0');
  603.         stm.tm_mday = (pStr[6]-'0')*10 + (pStr[7]-'0');
  604.         for (n = 9; n < 15; n++)
  605.         {
  606.             if (!isdigit(pStr[n]))
  607.             {
  608.                 goto bail;
  609.             }
  610.         }
  611.         stm.tm_hour = (pStr[9]-'0')*10 + (pStr[10]-'0');
  612.         stm.tm_min = (pStr[11]-'0')*10 + (pStr[12]-'0');
  613.         stm.tm_sec = (pStr[13]-'0')*10 + (pStr[14]-'0');
  614.         // We have a struct tm in GMT
  615.         return fromUTCTm(&stm);
  616.     }
  617.     else
  618.     {
  619.         if (weekday_from_string(pStr) < 0)
  620.         {
  621.             goto bail;
  622.         }
  623.         NEXT_ALNUM_FIELD(pStr);
  624.         if (isdigit(pStr[0]))
  625.         {
  626.             // RFC1123 or RFC850
  627.             if (!isdigit(pStr[1]) || isalnum(pStr[2]))
  628.             {
  629.                 goto bail;
  630.             }
  631.             stm.tm_mday = (pStr[0]-'0')*10 + (pStr[1]-'0');
  632.             NEXT_ALNUM_FIELD(pStr);
  633.             if ((stm.tm_mon = month_from_string(pStr)) < 0)
  634.             {
  635.                 goto bail;
  636.             }
  637.             NEXT_ALNUM_FIELD(pStr);
  638.             if (!isdigit(pStr[0]) || !isdigit(pStr[1]))
  639.             {
  640.                 goto bail;
  641.             }
  642.             if (!isdigit(pStr[2]))
  643.             {
  644.                 // RFC850
  645.                 stm.tm_year = (pStr[0]-'0')*10 + (pStr[1]-'0');
  646.             }
  647.             else if (isdigit(pStr[3]) && !isdigit(pStr[4]))
  648.             {
  649.                 // RFC1123
  650.                 stm.tm_year = (pStr[0]-'0')*1000 + (pStr[1]-'0')*100 +
  651.                               (pStr[2]-'0')*10 + (pStr[3]-'0') - 1900;
  652.             }
  653.             else
  654.             {
  655.                 goto bail;
  656.             }
  657.             NEXT_ALNUM_FIELD(pStr);
  658.             for (n = 0; n < 8; n++)
  659.             {
  660.                 if (n == 2 || n == 5)
  661.                 {
  662.                     if (pStr[n] != ':')
  663.                     {
  664.                         goto bail;
  665.                     }
  666.                 }
  667.                 else if (!isdigit(pStr[n]))
  668.                 {
  669.                     goto bail;
  670.                 }
  671.             }
  672.             stm.tm_hour = (pStr[0]-'0')*10 + (pStr[1]-'0');
  673.             stm.tm_min = (pStr[3]-'0')*10 + (pStr[4]-'0');
  674.             stm.tm_sec = (pStr[6]-'0')*10 + pStr[7]-'0';
  675.             pStr += 8;
  676.             NEXT_ALNUM_FIELD(pStr);
  677.             if (strncasecmp(pStr, "GMT", 3) != 0)
  678.             {
  679.                 goto bail;
  680.             }
  681.             // We have a struct tm in GMT
  682.             return fromUTCTm(&stm);
  683.         }
  684.         else
  685.         {
  686.             // asctime
  687.             NEXT_ALNUM_FIELD(pStr);
  688.             if ((stm.tm_mon = month_from_string(pStr)) == -1)
  689.             {
  690.                 goto bail;
  691.             }
  692.             NEXT_ALNUM_FIELD(pStr);
  693.             if (isdigit(pStr[0]) && pStr[1] == ' ')
  694.             {
  695.                 stm.tm_mday = (pStr[0]-'0');
  696.             }
  697.             else if (isdigit(pStr[0]) && isdigit(pStr[1]) && pStr[2] == ' ')
  698.             {
  699.                 stm.tm_mday = (pStr[0]-'0')*10 + (pStr[1]-'0');
  700.             }
  701.             else
  702.             {
  703.                 goto bail;
  704.             }
  705.             NEXT_ALNUM_FIELD(pStr);
  706.             for (n = 0; n < 8; n++)
  707.             {
  708.                 if (n == 2 || n == 5)
  709.                 {
  710.                     if (pStr[n] != ':')
  711.                     {
  712.                         goto bail;
  713.                     }
  714.                 }
  715.                 else if (!isdigit(pStr[n]))
  716.                 {
  717.                     goto bail;
  718.                 }
  719.             }
  720.             stm.tm_hour = (pStr[0]-'0')*10 + (pStr[1]-'0');
  721.             stm.tm_min = (pStr[3]-'0')*10 + (pStr[4]-'0');
  722.             stm.tm_sec = (pStr[6]-'0')*10 + pStr[7]-'0';
  723.             pStr += 8;
  724.             NEXT_ALNUM_FIELD(pStr);
  725.             if (!isdigit(pStr[0]) || !isdigit(pStr[1]) ||
  726.                 !isdigit(pStr[2]) || !isdigit(pStr[3]) ||
  727.                 isdigit(pStr[4]))
  728.             {
  729.                 goto bail;
  730.             }
  731.             stm.tm_year = (pStr[0]-'0')*1000 + (pStr[1]-'0')*100 +
  732.                           (pStr[2]-'0')*10 + (pStr[3]-'0') - 1900;
  733.             // We have a struct tm in localtime
  734.             return fromTm(&stm);
  735.         }
  736.     }
  737.     /* NOTREACHED */
  738. bail:
  739.     m_tTime = INVALID_TIME_T;
  740.     return -1;
  741. }