VirtualBox

Changeset 168 in vbox for trunk/src/VBox/Frontends


Ignore:
Timestamp:
Jan 18, 2007 6:53:45 PM (18 years ago)
Author:
vboxsync
Message:

FE/Qt:

  • VBoxGlobal::parseSize()/formatSize(): Don't use double when parsing sizes and formatting them to human-readable forms for better rounding control.
  • Added VBoxGlobal::decimalSep() and sizeRegexp().
Location:
trunk/src/VBox/Frontends/VirtualBox
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/include/VBoxGlobal.h

    r1 r168  
    324324                              bool aCanResize = true);
    325325
    326     static unsigned long long parseSize (QString);
    327     static QString formatSize (unsigned long long);
     326    static QChar decimalSep();
     327    static QString sizeRegexp();
     328
     329    static Q_UINT64 parseSize (const QString &);
     330    static QString formatSize (Q_UINT64, int aMode = 0);
    328331
    329332signals:
  • trunk/src/VBox/Frontends/VirtualBox/src/VBoxGlobal.cpp

    r132 r168  
    13571357}
    13581358
     1359/**
     1360 *  Returns the decimal separator for the current locale.
     1361 */
    13591362/* static */
    1360 unsigned long long VBoxGlobal::parseSize (QString aText)
    1361 {
    1362     QRegExp regexp ("^(\\d+([^\\s^\\d^B^K^M^G^T^P]\\d{1,2})?)\\s?(B|KB|MB|GB|TB|PB)?$");
     1363QChar VBoxGlobal::decimalSep()
     1364{
     1365    QString n = QLocale::system().toString (0.0, 'f', 1).stripWhiteSpace();
     1366    return n [1];
     1367}
     1368
     1369/**
     1370 *  Returns the regexp string that defines the format of the human-readable
     1371 *  size representation, <tt>####[.##] B|KB|MB|GB|TB|PB</tt>.
     1372 *
     1373 *  This regexp will capture 5 groups of text:
     1374 *  - cap(1): integer number in case when no decimal point is present
     1375 *            (if empty, it means that decimal point is present)
     1376 *  - cap(2): size suffix in case when no decimal point is present (may be empty)
     1377 *  - cap(3): integer number in case when decimal point is present (may be empty)
     1378 *  - cap(4): fraction number (hundredth) in case when decimal point is present
     1379 *  - cap(5): size suffix in case when decimal point is present (note that
     1380 *            B cannot appear there)
     1381 */
     1382/* static */
     1383QString VBoxGlobal::sizeRegexp()
     1384{
     1385    QString regexp =
     1386        QString ("^(?:(?:(\\d+)(?:\\s?([KMGTP]?B))?)|(?:(\\d*)%1(\\d{1,2})(?:\\s?([KMGTP]B))))$")
     1387                 .arg (decimalSep());
     1388    return regexp;
     1389}
     1390
     1391/**
     1392 *  Parses the given size string that should be in form of
     1393 *  <tt>####[.##] B|KB|MB|GB|TB|PB</tt> and returns the size value
     1394 *  in bytes. Zero is returned on error.
     1395 */
     1396/* static */
     1397Q_UINT64 VBoxGlobal::parseSize (const QString &aText)
     1398{
     1399    QRegExp regexp (sizeRegexp());
    13631400    int pos = regexp.search (aText);
    13641401    if (pos != -1)
    13651402    {
    1366         QString size   = regexp.cap (1);
    1367         QString suffix = regexp.cap (3);
    1368         double  result = QLocale::system().toDouble(size);
    1369         if (suffix.isEmpty() || suffix == "B")
    1370             return (unsigned long long)result;
    1371         else if (suffix == "KB")
    1372             return (unsigned long long)(result * _1K);
    1373         else if (suffix == "MB")
    1374             return (unsigned long long)(result * _1M);
    1375         else if (suffix == "GB")
    1376             return (unsigned long long)(result * _1G);
    1377         else if (suffix == "TB")
    1378             return (unsigned long long)(result * _1T);
    1379         else if (suffix == "PB")
    1380             return (unsigned long long)(result * _1P);
    1381         else
    1382             return 0;
     1403        QString intgS = regexp.cap (1);
     1404        QString hundS;
     1405        QString suff = regexp.cap (2);
     1406        if (intgS.isEmpty())
     1407        {
     1408            intgS = regexp.cap (3);
     1409            hundS = regexp.cap (4);
     1410            suff = regexp.cap (5);
     1411        }
     1412
     1413        Q_UINT64 denom = 0;
     1414        if (suff.isEmpty() || suff == "B")
     1415            denom = 1;
     1416        else if (suff == "KB")
     1417            denom = _1K;
     1418        else if (suff == "MB")
     1419            denom = _1M;
     1420        else if (suff == "GB")
     1421            denom = _1G;
     1422        else if (suff == "TB")
     1423            denom = _1T;
     1424        else if (suff == "PB")
     1425            denom = _1P;
     1426
     1427        Q_UINT64 intg = intgS.toULongLong();
     1428        if (denom == 1)
     1429            return intg;
     1430
     1431        Q_UINT64 hund = hundS.rightJustify (2, '0').toULongLong();
     1432        hund = hund * denom / 100;
     1433        intg = intg * denom + hund;
     1434        return intg;
    13831435    }
    13841436    else
     
    13861438}
    13871439
     1440/**
     1441 *  Formats the given \a size value in bytes to a human readable string
     1442 *  in form of <tt>####[.##] B|KB|MB|GB|TB|PB</tt>.
     1443 *
     1444 *  The \a mode parameter is used for resulting numbers that get a fractional
     1445 *  part after converting the \a size to KB, MB etc:
     1446 *  <ul>
     1447 *  <li>When \a mode is 0, the result is rounded to the closest number
     1448 *      containing two decimal digits.
     1449 *  </li>
     1450 *  <li>When \a mode is -1, the result is rounded to the largest two decimal
     1451 *      digit number that is not greater than the result. This guarantees that
     1452 *      converting the resulting string back to the integer value in bytes
     1453 *      will not produce a value greater that the initial \a size parameter.
     1454 *  </li>
     1455 *  <li>When \a mode is 1, the result is rounded to the smallest two decimal
     1456 *      digit number that is not less than the result. This guarantees that
     1457 *      converting the resulting string back to the integer value in bytes
     1458 *      will not produce a value less that the initial \a size parameter.
     1459 *  </li>
     1460 *  </ul>
     1461 *
     1462 *  @param  aSize   size value in bytes
     1463 *  @param  aMode   convertion mode (-1, 0 or 1)
     1464 *  @return         human-readable size string
     1465 */
    13881466/* static */
    1389 QString VBoxGlobal::formatSize (unsigned long long aSize)
    1390 {
    1391     double size;
    1392     QString suffix;
     1467QString VBoxGlobal::formatSize (Q_UINT64 aSize, int aMode /* = 0 */)
     1468{
     1469    static const char *Suffixes [] = { "B", "KB", "MB", "GB", "TB", "PB", NULL };
     1470
     1471    Q_UINT64 denom = 0;
     1472    int suffix = 0;
     1473
    13931474    if (aSize < _1K)
    13941475    {
    1395         size = aSize;
    1396         suffix = "B";
     1476        denom = 1;
     1477        suffix = 0;
    13971478    }
    13981479    else if (aSize < _1M)
    13991480    {
    1400         size = (double)aSize / _1K;
    1401         suffix = "KB";
     1481        denom = _1K;
     1482        suffix = 1;
    14021483    }
    14031484    else if (aSize < _1G)
    14041485    {
    1405         size = (double)aSize / _1M;
    1406         suffix = "MB";
     1486        denom = _1M;
     1487        suffix = 2;
    14071488    }
    14081489    else if (aSize < _1T)
    14091490    {
    1410         size = (double)aSize / _1G;
    1411         suffix = "GB";
     1491        denom = _1G;
     1492        suffix = 3;
    14121493    }
    14131494    else if (aSize < _1P)
    14141495    {
    1415         size = (double)aSize / _1T;
    1416         suffix = "TB";
     1496        denom = _1T;
     1497        suffix = 4;
    14171498    }
    14181499    else
    14191500    {
    1420         size = (double)aSize / _1P;
    1421         suffix = "PB";
    1422     }
    1423     QString number = QLocale::system().toString(size, 'f', 2);
    1424     number.remove (QRegExp ("\\s+"));
    1425     return QString ("%1 %2").arg (number).arg (suffix);
     1501        denom = _1P;
     1502        suffix = 5;
     1503    }
     1504
     1505    Q_UINT64 intg = aSize / denom;
     1506    Q_UINT64 hund = aSize % denom;
     1507
     1508    QString number;
     1509    if (denom > 1)
     1510    {
     1511        if (hund)
     1512        {
     1513            hund *= 100;
     1514            /* not greater */
     1515            if (aMode < 0) hund = hund / denom;
     1516            /* not less */
     1517            else if (aMode > 0) hund = (hund + denom - 1) / denom;
     1518            /* nearest */
     1519            else hund = (hund + denom / 2) / denom;
     1520        }
     1521        /* check for the fractional part overflow due to rounding */
     1522        if (hund == 100)
     1523        {
     1524            hund = 0;
     1525            ++ intg;
     1526            /* check if we've got 1024 XB after rounding and scale down if so */
     1527            if (intg == 1024 && Suffixes [suffix + 1] != NULL)
     1528            {
     1529                intg /= 1024;
     1530                ++ suffix;
     1531            }
     1532        }
     1533        number = QString ("%1%2%3").arg (intg).arg (decimalSep())
     1534                                   .arg (QString::number (hund).leftJustify (2, '0'));
     1535    }
     1536    else
     1537    {
     1538        number = QString::number (intg);
     1539    }
     1540   
     1541    return QString ("%1 %2").arg (number).arg (Suffixes [suffix]);
    14261542}
    14271543
Note: See TracChangeset for help on using the changeset viewer.

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