VirtualBox

Changeset 74149 in vbox


Ignore:
Timestamp:
Sep 7, 2018 6:51:37 PM (7 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
124921
Message:

IPRT/rest: Adding RTCRestDate (untested). bugref:9167

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/cpp/restbase.h

    r74142 r74149  
    3131#include <iprt/json.h>
    3232#include <iprt/stdarg.h>
     33#include <iprt/time.h>
    3334#include <iprt/cpp/ministring.h>
    3435
     
    362363        kTypeClass_Invalid = 0,
    363364        kTypeClass_Bool,                /**< Primitive: bool. */
    364         kTypeClass_Int64,               /**< Primitive: bool. */
    365         kTypeClass_Int32,               /**< Primitive: bool. */
    366         kTypeClass_Int16,               /**< Primitive: bool. */
    367         kTypeClass_Double,              /**< Primitive: bool. */
    368         kTypeClass_String,              /**< Primitive: bool. */
     365        kTypeClass_Int64,               /**< Primitive: int64_t. */
     366        kTypeClass_Int32,               /**< Primitive: int32_t. */
     367        kTypeClass_Int16,               /**< Primitive: int16_t. */
     368        kTypeClass_Double,              /**< Primitive: double. */
     369        kTypeClass_String,              /**< Primitive: string. */
     370        kTypeClass_Date,                /**< Date. */
     371        kTypeClass_Uuid,                /**< UUID. */
     372        kTypeClass_Binary,              /**< Binary blob. */
    369373        kTypeClass_Object,              /**< Object (any kind of data model object). */
    370374        kTypeClass_Array,               /**< Array (containing any kind of object). */
    371375        kTypeClass_StringMap,           /**< String map (containing any kind of object). */
    372         kTypeClass_StringEnum,          /**< String enum. */
    373         kTypeClass_BinaryString         /**< Binary string. */
     376        kTypeClass_StringEnum           /**< String enum. */
    374377    } kTypeClass;
    375378
     
    642645    static DECLCALLBACK(RTCRestObjectBase *) createInstance(void);
    643646};
     647
     648
     649/**
     650 * Date class.
     651 *
     652 * There are numerous ways of formatting a timestamp and the specifications
     653 * we're currently working with doesn't have a way of telling it seems.
     654 * Thus, decoding need to have fail safes built in so the user can give hints.
     655 * The formatting likewise needs to be told which format to use by the user.
     656 *
     657 * Two side-effects of the format stuff is that the default constructor creates
     658 * an object that is null, and resetToDefault will do the same bug leave the
     659 * format as a hint.
     660 */
     661class RT_DECL_CLASS RTCRestDate : public RTCRestObjectBase
     662{
     663public:
     664    /** Default constructor.
     665     * @note The result is a null-object.   */
     666    RTCRestDate();
     667    /** Copy constructor. */
     668    RTCRestDate(RTCRestDate const &a_rThat);
     669    /** Destructor. */
     670    virtual ~RTCRestDate();
     671    /** Copy assignment operator. */
     672    RTCRestDate &operator=(RTCRestDate const &a_rThat);
     673    /** Safe copy assignment method. */
     674    int assignCopy(RTCRestDate const &a_rThat);
     675
     676    /* Overridden methods: */
     677    virtual int resetToDefault() RT_OVERRIDE;
     678    virtual RTCRestOutputBase &serializeAsJson(RTCRestOutputBase &a_rDst) const RT_OVERRIDE;
     679    virtual int deserializeFromJson(RTCRestJsonCursor const &a_rCursor) RT_OVERRIDE;
     680    virtual int toString(RTCString *a_pDst, uint32_t a_fFlags = 0) const RT_OVERRIDE;
     681    virtual int fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo = NULL,
     682                           uint32_t a_fFlags = kCollectionFormat_Unspecified) RT_OVERRIDE;
     683    virtual kTypeClass typeClass(void) const RT_OVERRIDE;
     684    virtual const char *typeName(void) const RT_OVERRIDE;
     685
     686    /** Factory method. */
     687    static DECLCALLBACK(RTCRestObjectBase *) createInstance(void);
     688
     689    /** Date formats. */
     690    typedef enum
     691    {
     692        kFormat_Invalid = 0,
     693        kFormat_Rfc2822,            /**< Format it according to RFC-2822. */
     694        kFormat_Rfc7131,            /**< Format it according to RFC-7131 (HTTP). */
     695        kFormat_Rfc3339,            /**< Format it according to RFC-3339 (ISO-8601) (no fraction). */
     696        kFormat_Rfc3339_Fraction_2, /**< Format it according to RFC-3339 (ISO-8601) with two digit fraction (hundreths). */
     697        kFormat_Rfc3339_Fraction_3, /**< Format it according to RFC-3339 (ISO-8601) with three digit fraction (milliseconds). */
     698        kFormat_Rfc3339_Fraction_6, /**< Format it according to RFC-3339 (ISO-8601) with six digit fraction (microseconds). */
     699        kFormat_Rfc3339_Fraction_9, /**< Format it according to RFC-3339 (ISO-8601) with nine digit fraction (nanoseconds). */
     700        kFormat_End
     701    } kFormat;
     702
     703    /**
     704     * Assigns the value, formats it as a string and clears the null indicator.
     705     *
     706     * @returns VINF_SUCCESS, VERR_NO_STR_MEMORY or VERR_INVALID_PARAMETER.
     707     * @param   a_pTimeSpec     The time spec to set.
     708     * @param   a_enmFormat     The date format to use when formatting it.
     709     */
     710    int assignValue(PCRTTIMESPEC a_pTimeSpec, kFormat a_enmFormat);
     711    int assignValueRfc2822(PCRTTIMESPEC a_pTimeSpec); /**< Convenience method. */
     712    int assignValueRfc7131(PCRTTIMESPEC a_pTimeSpec); /**< Convenience method. */
     713    int assignValueRfc3339(PCRTTIMESPEC a_pTimeSpec); /**< Convenience method. */
     714
     715    /**
     716     * Assigns the current UTC time and clears the null indicator .
     717     *
     718     * @returns VINF_SUCCESS, VERR_NO_STR_MEMORY or VERR_INVALID_PARAMETER.
     719     * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY.
     720     * @param   a_enmFormat     The date format to use when formatting it.
     721     */
     722    int assignNow(kFormat a_enmFormat);
     723    int assignNowRfc2822(); /**< Convenience method. */
     724    int assignNowRfc7131(); /**< Convenience method. */
     725    int assignNowRfc3339(); /**< Convenience method. */
     726
     727    /**
     728     * Sets the format to help deal with decoding issues.
     729     *
     730     * This can also be used to change the date format for an okay timespec.
     731     * @returns IPRT status code.
     732     * @param   a_enmFormat     The date format to try/set.
     733     */
     734    int setFormat(kFormat a_enmFormat);
     735
     736    /** Check if the value is okay (m_TimeSpec & m_Exploded). */
     737    bool              isOkay() const        { return m_fTimeSpecOkay; }
     738    /** Get the timespec value. */
     739    RTTIMESPEC const &getTimeSpec() const   { return m_TimeSpec; }
     740    /** Get the exploded time. */
     741    RTTIME const     &getExploded() const   { return m_Exploded; }
     742    /** Get the formatted/raw string value. */
     743    RTCString const  &getString() const     { return m_strFormatted; }
     744
     745protected:
     746    /** The value. */
     747    RTTIMESPEC  m_TimeSpec;
     748    /** The exploded time value. */
     749    RTTIME      m_Exploded;
     750    /** Set if m_TimeSpec is okay, consult m_strFormatted if not. */
     751    bool        m_fTimeSpecOkay;
     752    /** The format / format hint. */
     753    kFormat     m_enmFormat;
     754    /** The formatted date string.
     755     * This will be the raw input string for a deserialized value, where as for
     756     * a value set by the user it will be the formatted value. */
     757    RTCString   m_strFormatted;
     758
     759    /**
     760     * Explodes and formats the m_TimeSpec value.
     761     *
     762     * Sets m_Exploded, m_strFormatted, m_fTimeSpecOkay, and m_enmFormat, clears m_fNullIndicator.
     763     *
     764     * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY.
     765     * @param   a_enmFormat The format to use.
     766     */
     767    int explodeAndFormat(kFormat a_enmFormat);
     768
     769    /**
     770     * Formats the m_Exploded value.
     771     *
     772     * Sets m_strFormatted, m_fTimeSpecOkay, and m_enmFormat, clears m_fNullIndicator.
     773     *
     774     * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY.
     775     * @param   a_enmFormat The format to use.
     776     */
     777    int format(kFormat a_enmFormat);
     778
     779    /**
     780     * Internal worker that attempts to decode m_strFormatted.
     781     *
     782     * Sets m_fTimeSpecOkay.
     783     *
     784     * @returns IPRT status code.
     785     * @param   enmFormat   Specific format to try, kFormat_Invalid (default) to try guess it.
     786     */
     787    int decodeFormattedString(kFormat enmFormat = kFormat_Invalid);
     788};
     789
     790
     791/** We should provide a proper UUID class eventually.  Currently it is not used. */
     792typedef RTCRestString RTCRestUuid;
    644793
    645794
  • trunk/include/iprt/err.h

    r74093 r74149  
    32183218/** Server response contains unexpected repetitive header field. */
    32193219#define VERR_REST_RESPONSE_REPEAT_HEADER_FIELD          (-25703)
     3220/** Unable to decode date value. */
     3221#define VWRN_REST_UNABLE_TO_DECODE_DATE                 (25704)
     3222/** Unable to decode date value. */
     3223#define VERR_REST_UNABLE_TO_DECODE_DATE                 (-25704)
    32203224
    32213225/** Internal error \#1. */
  • trunk/src/VBox/Runtime/common/rest/RTCRestAnyObject.cpp

    r74117 r74149  
    108108
    109109            /* Currently unused of invalid: */
     110            case kTypeClass_Date:
     111            case kTypeClass_Uuid:
     112            case kTypeClass_Binary:
    110113            case kTypeClass_StringEnum:
    111             case kTypeClass_BinaryString:
    112114            case kTypeClass_Object:
    113115            case kTypeClass_Invalid:
     
    541543
    542544            /* Currently unused of invalid: */
     545            case kTypeClass_Date:
     546            case kTypeClass_Uuid:
     547            case kTypeClass_Binary:
    543548            case kTypeClass_StringEnum:
    544             case kTypeClass_BinaryString:
    545549            case kTypeClass_Object:
    546550            case kTypeClass_Invalid:
  • trunk/src/VBox/Runtime/common/rest/RTCRestClientApiBaseOci.cpp

    r74125 r74149  
    5959    RTTIMESPEC NowSpec;
    6060    RTTIME     Now;
    61     char       szDate[RTTIME_RTC2822_LEN];
     61    char       szDate[RTTIME_RFC2822_LEN];
    6262    ssize_t cch = RTTimeToRfc2822(RTTimeExplode(&Now, RTTimeNow(&NowSpec)), szDate, sizeof(szDate), RTTIME_RFC2822_F_GMT);
    6363    AssertRCReturn((int)cch, (int)cch);
  • trunk/src/VBox/Runtime/common/rest/rest-binary.cpp

    r74143 r74149  
    222222RTCRestObjectBase::kTypeClass RTCRestBinary::typeClass(void) const
    223223{
    224     return kTypeClass_BinaryString;
     224    return kTypeClass_Binary;
    225225}
    226226
  • trunk/src/VBox/Runtime/common/rest/rest-primary-object-types.cpp

    r74093 r74149  
    3232#include <iprt/cpp/restbase.h>
    3333
     34#include <iprt/ctype.h>
    3435#include <iprt/err.h>
    3536#include <iprt/string.h>
     
    11561157
    11571158/*********************************************************************************************************************************
     1159*   RTCRestDate implementation                                                                                                   *
     1160*********************************************************************************************************************************/
     1161
     1162RTCRestDate::RTCRestDate()
     1163    : RTCRestObjectBase()
     1164    , m_fTimeSpecOkay(false)
     1165    , m_enmFormat(kFormat_Invalid)
     1166    , m_strFormatted()
     1167{
     1168    RTTimeSpecSetNano(&m_TimeSpec, 0);
     1169    RT_ZERO(m_Exploded);
     1170
     1171    /* Since we need to know the format, all date-time values default to 'null'. */
     1172    m_fNullIndicator = true;
     1173}
     1174
     1175
     1176RTCRestDate::RTCRestDate(RTCRestDate const &a_rThat)
     1177    : RTCRestObjectBase(a_rThat)
     1178    , m_fTimeSpecOkay(a_rThat.m_fTimeSpecOkay)
     1179    , m_enmFormat(a_rThat.m_enmFormat)
     1180    , m_strFormatted(a_rThat.m_strFormatted)
     1181{
     1182    m_TimeSpec = a_rThat.m_TimeSpec;
     1183    m_Exploded = a_rThat.m_Exploded;
     1184}
     1185
     1186
     1187RTCRestDate::~RTCRestDate()
     1188{
     1189    /* nothing to do */
     1190}
     1191
     1192
     1193RTCRestDate &RTCRestDate::operator=(RTCRestDate const &a_rThat)
     1194{
     1195    RTCRestObjectBase::operator=(a_rThat);
     1196    m_TimeSpec      = a_rThat.m_TimeSpec;
     1197    m_Exploded      = a_rThat.m_Exploded;
     1198    m_fTimeSpecOkay = a_rThat.m_fTimeSpecOkay;
     1199    m_enmFormat     = a_rThat.m_enmFormat;
     1200    m_strFormatted  = a_rThat.m_strFormatted;
     1201    return *this;
     1202}
     1203
     1204
     1205int RTCRestDate::assignCopy(RTCRestDate const &a_rThat)
     1206{
     1207    m_fNullIndicator = a_rThat.m_fNullIndicator;
     1208    m_TimeSpec       = a_rThat.m_TimeSpec;
     1209    m_Exploded       = a_rThat.m_Exploded;
     1210    m_fTimeSpecOkay  = a_rThat.m_fTimeSpecOkay;
     1211    m_enmFormat      = a_rThat.m_enmFormat;
     1212    return m_strFormatted.assignNoThrow(a_rThat.m_strFormatted);
     1213}
     1214
     1215
     1216int RTCRestDate::resetToDefault()
     1217{
     1218    m_fNullIndicator = true;
     1219    RTTimeSpecSetNano(&m_TimeSpec, 0);
     1220    RT_ZERO(m_Exploded);
     1221    m_fTimeSpecOkay = false;
     1222    m_strFormatted.setNull();
     1223    /*m_enmFormat - leave as hint. */
     1224    return VINF_SUCCESS;
     1225}
     1226
     1227
     1228RTCRestOutputBase &RTCRestDate::serializeAsJson(RTCRestOutputBase &a_rDst) const
     1229{
     1230    if (m_fNullIndicator)
     1231        a_rDst.printf("null");
     1232    else
     1233        a_rDst.printf("%RMjs", m_strFormatted.c_str());
     1234    return a_rDst;
     1235}
     1236
     1237
     1238int RTCRestDate::deserializeFromJson(RTCRestJsonCursor const &a_rCursor)
     1239{
     1240    RTJSONVALTYPE enmType = RTJsonValueGetType(a_rCursor.m_hValue);
     1241    if (enmType == RTJSONVALTYPE_STRING)
     1242    {
     1243        int rc = m_strFormatted.assignNoThrow(RTJsonValueGetString(a_rCursor.m_hValue));
     1244        AssertRCReturn(rc, rc);
     1245
     1246        m_fNullIndicator = false;
     1247        rc = decodeFormattedString(m_enmFormat);
     1248        if (RT_SUCCESS(rc))
     1249            return rc;
     1250        if (m_enmFormat != kFormat_Invalid)
     1251        {
     1252            rc = decodeFormattedString();
     1253            if (RT_SUCCESS(rc))
     1254                return rc;
     1255        }
     1256        return a_rCursor.m_pPrimary->addError(a_rCursor, VWRN_REST_UNABLE_TO_DECODE_DATE,
     1257                                              "Unable to decode date value: %s", m_strFormatted.c_str());
     1258    }
     1259
     1260    if (enmType == RTJSONVALTYPE_NULL)
     1261    {
     1262        setNull();
     1263        return VINF_SUCCESS;
     1264    }
     1265
     1266    return a_rCursor.m_pPrimary->addError(a_rCursor, VERR_WRONG_TYPE, "wrong JSON type for date: %s",
     1267                                          RTJsonValueTypeName(RTJsonValueGetType(a_rCursor.m_hValue)));
     1268}
     1269
     1270
     1271int RTCRestDate::toString(RTCString *a_pDst, uint32_t a_fFlags /*= 0*/) const
     1272{
     1273    if (m_fNullIndicator)
     1274    {
     1275        if (a_fFlags & kToString_Append)
     1276            return a_pDst->appendNoThrow(RT_STR_TUPLE("null"));
     1277        return a_pDst->assignNoThrow(RT_STR_TUPLE("null"));
     1278    }
     1279    if (a_fFlags & kToString_Append)
     1280        return a_pDst->appendNoThrow(m_strFormatted);
     1281    return a_pDst->assignNoThrow(m_strFormatted);
     1282}
     1283
     1284
     1285int RTCRestDate::fromString(RTCString const &a_rValue, const char *a_pszName, PRTERRINFO a_pErrInfo /*= NULL*/,
     1286                            uint32_t a_fFlags /*= kCollectionFormat_Unspecified*/)
     1287{
     1288    if (a_rValue.startsWithWord("null", RTCString::CaseInsensitive))
     1289    {
     1290        setNull();
     1291        return VINF_SUCCESS;
     1292    }
     1293
     1294    int rc = m_strFormatted.assignNoThrow(a_rValue);
     1295    AssertRCReturn(rc, rc);
     1296
     1297    m_fNullIndicator = false;
     1298    rc = decodeFormattedString(m_enmFormat);
     1299    if (RT_SUCCESS(rc))
     1300        return rc;
     1301    if (m_enmFormat != kFormat_Invalid)
     1302    {
     1303        rc = decodeFormattedString();
     1304        if (RT_SUCCESS(rc))
     1305            return rc;
     1306    }
     1307    RT_NOREF(a_fFlags);
     1308    return RTErrInfoSetF(a_pErrInfo, VERR_REST_UNABLE_TO_DECODE_DATE,
     1309                         "Unable to decode date value (%s): %s", a_pszName, m_strFormatted.c_str());
     1310}
     1311
     1312
     1313RTCRestObjectBase::kTypeClass RTCRestDate::typeClass(void) const
     1314{
     1315    return kTypeClass_Date;
     1316}
     1317
     1318
     1319const char *RTCRestDate::typeName(void) const
     1320{
     1321    return "RTCRestDate";
     1322}
     1323
     1324
     1325/*static*/ DECLCALLBACK(RTCRestObjectBase *) RTCRestDate::createInstance(void)
     1326{
     1327    return new (std::nothrow) RTCRestDate();
     1328}
     1329
     1330int RTCRestDate::assignValue(PCRTTIMESPEC a_pTimeSpec, kFormat a_enmFormat)
     1331{
     1332    AssertPtrReturn(a_pTimeSpec, VERR_INVALID_PARAMETER);
     1333    AssertReturn(a_enmFormat > kFormat_Invalid && a_enmFormat < kFormat_End, VERR_INVALID_PARAMETER);
     1334
     1335    m_TimeSpec = *a_pTimeSpec;
     1336    return explodeAndFormat(a_enmFormat);
     1337}
     1338
     1339
     1340int RTCRestDate::assignValueRfc2822(PCRTTIMESPEC a_pTimeSpec)
     1341{
     1342    AssertPtrReturn(a_pTimeSpec, VERR_INVALID_PARAMETER);
     1343    m_TimeSpec = *a_pTimeSpec;
     1344    return explodeAndFormat(kFormat_Rfc2822);
     1345}
     1346
     1347
     1348int RTCRestDate::assignValueRfc7131(PCRTTIMESPEC a_pTimeSpec)
     1349{
     1350    AssertPtrReturn(a_pTimeSpec, VERR_INVALID_PARAMETER);
     1351    m_TimeSpec = *a_pTimeSpec;
     1352    return explodeAndFormat(kFormat_Rfc7131);
     1353}
     1354
     1355
     1356int RTCRestDate::assignValueRfc3339(PCRTTIMESPEC a_pTimeSpec)
     1357{
     1358    AssertPtrReturn(a_pTimeSpec, VERR_INVALID_PARAMETER);
     1359    m_TimeSpec = *a_pTimeSpec;
     1360    return explodeAndFormat(kFormat_Rfc3339);
     1361}
     1362
     1363
     1364int RTCRestDate::assignNow(kFormat a_enmFormat)
     1365{
     1366    RTTIMESPEC Now;
     1367    return assignValue(RTTimeNow(&Now), a_enmFormat);
     1368}
     1369
     1370
     1371int RTCRestDate::assignNowRfc2822()
     1372{
     1373    RTTIMESPEC Now;
     1374    return assignValueRfc2822(RTTimeNow(&Now));
     1375}
     1376
     1377
     1378int RTCRestDate::assignNowRfc7131()
     1379{
     1380    RTTIMESPEC Now;
     1381    return assignValueRfc7131(RTTimeNow(&Now));
     1382}
     1383
     1384
     1385int RTCRestDate::assignNowRfc3339()
     1386{
     1387    RTTIMESPEC Now;
     1388    return assignValueRfc3339(RTTimeNow(&Now));
     1389}
     1390
     1391
     1392int RTCRestDate::setFormat(kFormat a_enmFormat)
     1393{
     1394    /*
     1395     * If this is a null object, just set the format as a hint for upcoming deserialization.
     1396     */
     1397    if (m_fNullIndicator)
     1398    {
     1399        AssertReturn(a_enmFormat >= kFormat_Invalid && a_enmFormat < kFormat_End, VERR_INVALID_PARAMETER);
     1400        m_enmFormat = a_enmFormat;
     1401        return VINF_SUCCESS;
     1402    }
     1403
     1404    /*
     1405     * If the tiem spec is okay, just reformat the string value accordingly.
     1406     */
     1407    if (m_fTimeSpecOkay)
     1408    {
     1409        AssertReturn(a_enmFormat > kFormat_Invalid && a_enmFormat < kFormat_End, VERR_INVALID_PARAMETER);
     1410        if (a_enmFormat ==  m_enmFormat)
     1411            return VINF_SUCCESS;
     1412        return format(a_enmFormat);
     1413    }
     1414
     1415    /*
     1416     * Try decode
     1417     */
     1418    AssertReturn(a_enmFormat > kFormat_Invalid && a_enmFormat < kFormat_End, VERR_INVALID_PARAMETER);
     1419    return decodeFormattedString(a_enmFormat);
     1420}
     1421
     1422
     1423int RTCRestDate::explodeAndFormat(kFormat a_enmFormat)
     1424{
     1425    RTTimeExplode(&m_Exploded, &m_TimeSpec);
     1426    return format(a_enmFormat);
     1427}
     1428
     1429
     1430/**
     1431 * Formats the m_Exploded value.
     1432 *
     1433 * Sets m_strFormatted, m_fTimeSpecOkay, and m_enmFormat, clears m_fNullIndicator.
     1434 *
     1435 * @returns VINF_SUCCESS or VERR_NO_STR_MEMORY.
     1436 * @param   a_enmFormat The format to use.
     1437 */
     1438int RTCRestDate::format(kFormat a_enmFormat)
     1439{
     1440    m_fNullIndicator = true;
     1441    m_enmFormat = a_enmFormat;
     1442    int rc;
     1443    switch (a_enmFormat)
     1444    {
     1445        case kFormat_Rfc2822:
     1446        case kFormat_Rfc7131:
     1447            rc = m_strFormatted.reserveNoThrow(RTTIME_RFC2822_LEN);
     1448            AssertRCReturn(rc, rc);
     1449            RTTimeToRfc2822(&m_Exploded, m_strFormatted.mutableRaw(), m_strFormatted.capacity(),
     1450                            a_enmFormat == kFormat_Rfc7131 ? RTTIME_RFC2822_F_GMT : 0);
     1451            m_strFormatted.jolt();
     1452            return VINF_SUCCESS;
     1453
     1454        case kFormat_Rfc3339:
     1455        case kFormat_Rfc3339_Fraction_2:
     1456        case kFormat_Rfc3339_Fraction_3:
     1457        case kFormat_Rfc3339_Fraction_6:
     1458        case kFormat_Rfc3339_Fraction_9:
     1459            rc = m_strFormatted.reserveNoThrow(RTTIME_STR_LEN);
     1460            AssertRCReturn(rc, rc);
     1461            RTTimeToStringEx(&m_Exploded, m_strFormatted.mutableRaw(), m_strFormatted.capacity(),
     1462                             a_enmFormat == kFormat_Rfc3339 ? 0
     1463                             : a_enmFormat == kFormat_Rfc3339_Fraction_2 ? 2
     1464                             : a_enmFormat == kFormat_Rfc3339_Fraction_3 ? 3
     1465                             : a_enmFormat == kFormat_Rfc3339_Fraction_6 ? 6 : 9);
     1466            m_strFormatted.jolt();
     1467            return VINF_SUCCESS;
     1468
     1469        /* no default */
     1470        case kFormat_Invalid:
     1471        case kFormat_End:
     1472            break;
     1473    }
     1474    AssertFailedReturn(VERR_REST_INTERNAL_ERROR_7);
     1475}
     1476
     1477
     1478/**
     1479 * Internal worker that attempts to decode m_strFormatted.
     1480 *
     1481 * Sets m_fTimeSpecOkay.
     1482 *
     1483 * @returns IPRT status code.
     1484 * @param   enmFormat   Specific format to try, kFormat_Invalid (default) to try guess it.
     1485 */
     1486int RTCRestDate::decodeFormattedString(kFormat enmFormat /*= kFormat_Invalid*/)
     1487{
     1488    /*
     1489     * Take empty string to mean null.
     1490     */
     1491    const char *pszTmp = RTStrStripL(m_strFormatted.c_str());
     1492    if (*pszTmp == '\0')
     1493    {
     1494        setNull();
     1495        return VINF_SUCCESS;
     1496    }
     1497
     1498    switch (enmFormat)
     1499    {
     1500        case kFormat_Invalid:
     1501        {
     1502            size_t cch = strlen(pszTmp);
     1503            if (cch >= 6)
     1504            {
     1505                if (   !RT_C_IS_DIGIT(pszTmp[0])
     1506                    || RT_C_IS_SPACE(pszTmp[5])
     1507                    || RT_C_IS_SPACE(pszTmp[2])
     1508                    || RT_C_IS_SPACE(pszTmp[1])
     1509                    || RT_C_IS_SPACE(pszTmp[3])
     1510                    || RT_C_IS_SPACE(pszTmp[4]))
     1511                    return decodeFormattedString(kFormat_Rfc2822);
     1512                return decodeFormattedString(kFormat_Rfc3339);
     1513            }
     1514            return VERR_REST_UNABLE_TO_DECODE_DATE;
     1515        }
     1516
     1517        /*
     1518         * Examples:
     1519         *      Fri, 31 Aug 2018 00:00:00 +0200
     1520         *      Mon, 3 Sep 2018 00:00:00 GMT
     1521         *      Mon, 3 Sep 2018 00:00:00 -0000
     1522         *      3 Sep 2018 00:00:00 -0000 (?)
     1523         *      3 Sep 2018 00:00:00 GMT   (?)
     1524         */
     1525        case kFormat_Rfc2822:
     1526        case kFormat_Rfc7131:
     1527            if (RTTimeFromRfc2822(&m_Exploded, pszTmp))
     1528            {
     1529                RTTimeImplode(&m_TimeSpec, &m_Exploded);
     1530
     1531                pszTmp = strchr(pszTmp, '\0');
     1532                if (pszTmp[-1] == 'T' || pszTmp[-1] == 't')
     1533                    m_enmFormat = kFormat_Rfc7131;
     1534                else
     1535                    m_enmFormat = kFormat_Rfc2822;
     1536                m_fTimeSpecOkay = true;
     1537                return VINF_SUCCESS;
     1538            }
     1539            return VERR_REST_UNABLE_TO_DECODE_DATE;
     1540
     1541        /*
     1542         * Examples:
     1543         *      2018-08-31T00:00:00+0200
     1544         *      2018-09-03T00:00:00Z
     1545         *      2018-09-03T00:00:00+0000
     1546         *      2018-09-03T00:00:00.123456789Z
     1547         */
     1548        case kFormat_Rfc3339:
     1549        case kFormat_Rfc3339_Fraction_2:
     1550        case kFormat_Rfc3339_Fraction_3:
     1551        case kFormat_Rfc3339_Fraction_6:
     1552        case kFormat_Rfc3339_Fraction_9:
     1553            if (RTTimeFromString(&m_Exploded, pszTmp))
     1554            {
     1555                RTTimeImplode(&m_TimeSpec, &m_Exploded);
     1556
     1557                pszTmp = strchr(pszTmp, '.');
     1558                if (!pszTmp)
     1559                    m_enmFormat = kFormat_Rfc3339;
     1560                else
     1561                {
     1562                    size_t cchFraction = 0;
     1563                    pszTmp++;
     1564                    while (RT_C_IS_DIGIT(pszTmp[cchFraction]))
     1565                        cchFraction++;
     1566                    if (cchFraction == 0)
     1567                        m_enmFormat = kFormat_Rfc3339;
     1568                    else if (cchFraction <= 2)
     1569                        m_enmFormat = kFormat_Rfc3339_Fraction_2;
     1570                    else if (cchFraction <= 3)
     1571                        m_enmFormat = kFormat_Rfc3339_Fraction_3;
     1572                    else if (cchFraction <= 6)
     1573                        m_enmFormat = kFormat_Rfc3339_Fraction_6;
     1574                    else
     1575                        m_enmFormat = kFormat_Rfc3339_Fraction_9;
     1576                }
     1577                m_fTimeSpecOkay = true;
     1578                return VINF_SUCCESS;
     1579            }
     1580            return VERR_REST_UNABLE_TO_DECODE_DATE;
     1581
     1582        /* no default */
     1583        case kFormat_End:
     1584            break;
     1585    }
     1586    AssertFailedReturn(VERR_INVALID_PARAMETER);
     1587}
     1588
     1589
     1590/*********************************************************************************************************************************
    11581591*   RTCRestStringEnumBase implementation                                                                                         *
    11591592*********************************************************************************************************************************/
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette