Changeset 74149 in vbox
- Timestamp:
- Sep 7, 2018 6:51:37 PM (7 years ago)
- svn:sync-xref-src-repo-rev:
- 124921
- Location:
- trunk
- Files:
-
- 6 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/iprt/cpp/restbase.h
r74142 r74149 31 31 #include <iprt/json.h> 32 32 #include <iprt/stdarg.h> 33 #include <iprt/time.h> 33 34 #include <iprt/cpp/ministring.h> 34 35 … … 362 363 kTypeClass_Invalid = 0, 363 364 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. */ 369 373 kTypeClass_Object, /**< Object (any kind of data model object). */ 370 374 kTypeClass_Array, /**< Array (containing any kind of object). */ 371 375 kTypeClass_StringMap, /**< String map (containing any kind of object). */ 372 kTypeClass_StringEnum, /**< String enum. */ 373 kTypeClass_BinaryString /**< Binary string. */ 376 kTypeClass_StringEnum /**< String enum. */ 374 377 } kTypeClass; 375 378 … … 642 645 static DECLCALLBACK(RTCRestObjectBase *) createInstance(void); 643 646 }; 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 */ 661 class RT_DECL_CLASS RTCRestDate : public RTCRestObjectBase 662 { 663 public: 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 745 protected: 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. */ 792 typedef RTCRestString RTCRestUuid; 644 793 645 794 -
trunk/include/iprt/err.h
r74093 r74149 3218 3218 /** Server response contains unexpected repetitive header field. */ 3219 3219 #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) 3220 3224 3221 3225 /** Internal error \#1. */ -
trunk/src/VBox/Runtime/common/rest/RTCRestAnyObject.cpp
r74117 r74149 108 108 109 109 /* Currently unused of invalid: */ 110 case kTypeClass_Date: 111 case kTypeClass_Uuid: 112 case kTypeClass_Binary: 110 113 case kTypeClass_StringEnum: 111 case kTypeClass_BinaryString:112 114 case kTypeClass_Object: 113 115 case kTypeClass_Invalid: … … 541 543 542 544 /* Currently unused of invalid: */ 545 case kTypeClass_Date: 546 case kTypeClass_Uuid: 547 case kTypeClass_Binary: 543 548 case kTypeClass_StringEnum: 544 case kTypeClass_BinaryString:545 549 case kTypeClass_Object: 546 550 case kTypeClass_Invalid: -
trunk/src/VBox/Runtime/common/rest/RTCRestClientApiBaseOci.cpp
r74125 r74149 59 59 RTTIMESPEC NowSpec; 60 60 RTTIME Now; 61 char szDate[RTTIME_R TC2822_LEN];61 char szDate[RTTIME_RFC2822_LEN]; 62 62 ssize_t cch = RTTimeToRfc2822(RTTimeExplode(&Now, RTTimeNow(&NowSpec)), szDate, sizeof(szDate), RTTIME_RFC2822_F_GMT); 63 63 AssertRCReturn((int)cch, (int)cch); -
trunk/src/VBox/Runtime/common/rest/rest-binary.cpp
r74143 r74149 222 222 RTCRestObjectBase::kTypeClass RTCRestBinary::typeClass(void) const 223 223 { 224 return kTypeClass_Binary String;224 return kTypeClass_Binary; 225 225 } 226 226 -
trunk/src/VBox/Runtime/common/rest/rest-primary-object-types.cpp
r74093 r74149 32 32 #include <iprt/cpp/restbase.h> 33 33 34 #include <iprt/ctype.h> 34 35 #include <iprt/err.h> 35 36 #include <iprt/string.h> … … 1156 1157 1157 1158 /********************************************************************************************************************************* 1159 * RTCRestDate implementation * 1160 *********************************************************************************************************************************/ 1161 1162 RTCRestDate::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 1176 RTCRestDate::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 1187 RTCRestDate::~RTCRestDate() 1188 { 1189 /* nothing to do */ 1190 } 1191 1192 1193 RTCRestDate &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 1205 int 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 1216 int 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 1228 RTCRestOutputBase &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 1238 int 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 1271 int 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 1285 int 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 1313 RTCRestObjectBase::kTypeClass RTCRestDate::typeClass(void) const 1314 { 1315 return kTypeClass_Date; 1316 } 1317 1318 1319 const 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 1330 int 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 1340 int 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 1348 int 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 1356 int 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 1364 int RTCRestDate::assignNow(kFormat a_enmFormat) 1365 { 1366 RTTIMESPEC Now; 1367 return assignValue(RTTimeNow(&Now), a_enmFormat); 1368 } 1369 1370 1371 int RTCRestDate::assignNowRfc2822() 1372 { 1373 RTTIMESPEC Now; 1374 return assignValueRfc2822(RTTimeNow(&Now)); 1375 } 1376 1377 1378 int RTCRestDate::assignNowRfc7131() 1379 { 1380 RTTIMESPEC Now; 1381 return assignValueRfc7131(RTTimeNow(&Now)); 1382 } 1383 1384 1385 int RTCRestDate::assignNowRfc3339() 1386 { 1387 RTTIMESPEC Now; 1388 return assignValueRfc3339(RTTimeNow(&Now)); 1389 } 1390 1391 1392 int 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 1423 int 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 */ 1438 int 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 */ 1486 int 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 /********************************************************************************************************************************* 1158 1591 * RTCRestStringEnumBase implementation * 1159 1592 *********************************************************************************************************************************/
Note:
See TracChangeset
for help on using the changeset viewer.