VirtualBox

Changeset 47359 in vbox for trunk/src/VBox/Runtime/common


Ignore:
Timestamp:
Jul 24, 2013 12:45:47 AM (12 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
87505
Message:

IPRT: Added compression to the gzip VFS I/O stream class (RTZipGzipCompressIoStream) and implemented compression in the RTGzip example tool (testcase\RTGzip.exe).

Location:
trunk/src/VBox/Runtime/common/zip
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/common/zip/gzipvfs.cpp

    r39083 r47359  
    5656};
    5757#endif /* RT_OS_OS2 || RT_OS_SOLARIS || RT_OS_WINDOWS */
     58
    5859
    5960/*******************************************************************************
     
    168169
    169170
     171/*******************************************************************************
     172*   Internal Functions                                                         *
     173*******************************************************************************/
     174static int rtZipGzip_FlushIt(PRTZIPGZIPSTREAM pThis, uint8_t fFlushType);
     175
     176
    170177/**
    171178 * Convert from zlib to IPRT status codes.
     
    224231    int rc;
    225232    if (pThis->fDecompress)
     233    {
    226234        rc = inflateEnd(&pThis->Zlib);
     235        if (rc != Z_OK)
     236            rc = rtZipGzipConvertErrFromZlib(pThis, rc);
     237    }
    227238    else
    228         rc = deflateEnd(&pThis->Zlib);
    229     if (rc != Z_OK)
    230         rc = rtZipGzipConvertErrFromZlib(pThis, rc);
     239    {
     240        /* Flush the compression stream before terminating it. */
     241        rc = VINF_SUCCESS;
     242        if (!pThis->fFatalError)
     243            rc = rtZipGzip_FlushIt(pThis, Z_FINISH);
     244
     245        int rc2 = deflateEnd(&pThis->Zlib);
     246        if (RT_SUCCESS(rc) && rc2 != Z_OK)
     247            rc = rtZipGzipConvertErrFromZlib(pThis, rc);
     248    }
    231249
    232250    RTVfsIoStrmRelease(pThis->hVfsIos);
     
    350368}
    351369
     370
    352371/**
    353372 * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
     
    356375{
    357376    PRTZIPGZIPSTREAM pThis = (PRTZIPGZIPSTREAM)pvThis;
    358     int              rc;
    359 
     377
     378    Assert(pSgBuf->cSegs == 1);
    360379    AssertReturn(off == -1, VERR_INVALID_PARAMETER);
    361380    if (!pThis->fDecompress)
    362381        return VERR_ACCESS_DENIED;
    363382
    364     if (pSgBuf->cSegs == 1)
    365         rc = rtZipGzip_ReadOneSeg(pThis, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, fBlocking, pcbRead);
    366     else
    367     {
    368         rc = VINF_SUCCESS;
    369         size_t  cbRead = 0;
    370         size_t  cbReadSeg;
    371         size_t *pcbReadSeg = pcbRead ? &cbReadSeg : NULL;
    372         for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
     383    return rtZipGzip_ReadOneSeg(pThis, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, fBlocking, pcbRead);
     384}
     385
     386
     387/**
     388 * Internal helper for rtZipGzip_Write, rtZipGzip_Flush and rtZipGzip_Close.
     389 *
     390 * @returns IPRT status code.
     391 * @retval  VINF_SUCCESS
     392 * @retval  VINF_TRY_AGAIN - the only informational status.
     393 * @retval  VERR_INTERRUPTED - call again.
     394 *
     395 * @param   pThis           The gzip I/O stream instance data.
     396 * @param   fBlocking       Whether to block or not.
     397 */
     398static int rtZipGzip_WriteOutputBuffer(PRTZIPGZIPSTREAM pThis, bool fBlocking)
     399{
     400    /*
     401     * Anything to write?  No, then just return immediately.
     402     */
     403    size_t cbToWrite = sizeof(pThis->abBuffer) - pThis->Zlib.avail_out;
     404    if (cbToWrite == 0)
     405    {
     406        Assert(pThis->Zlib.next_out == &pThis->abBuffer[0]);
     407        return VINF_SUCCESS;
     408    }
     409    Assert(cbToWrite <= sizeof(pThis->abBuffer));
     410
     411    /*
     412     * Loop write on VERR_INTERRUPTED.
     413     *
     414     * Note! Asserting a bit extra here to make sure the
     415     *       RTVfsIoStrmSgWrite works correctly.
     416     */
     417    int    rc;
     418    size_t cbWrittenOut;
     419    for (;;)
     420    {
     421        /* Set up the buffer. */
     422        pThis->SgSeg.cbSeg = cbToWrite;
     423        Assert(pThis->SgSeg.pvSeg == &pThis->abBuffer[0]);
     424        RTSgBufReset(&pThis->SgBuf);
     425
     426        cbWrittenOut = ~(size_t)0;
     427        rc = RTVfsIoStrmSgWrite(pThis->hVfsIos, &pThis->SgBuf, fBlocking, &cbWrittenOut);
     428        if (rc != VINF_SUCCESS)
    373429        {
    374             cbReadSeg = 0;
    375             rc = rtZipGzip_ReadOneSeg(pThis, pSgBuf->paSegs[iSeg].pvSeg, pSgBuf->paSegs[iSeg].cbSeg, fBlocking, pcbReadSeg);
    376             if (RT_FAILURE(rc))
    377                 break;
    378             if (pcbRead)
     430            AssertMsg(RT_FAILURE(rc) || rc == VINF_TRY_AGAIN, ("%Rrc\n", rc));
     431            if (rc == VERR_INTERRUPTED)
    379432            {
    380                 cbRead += cbReadSeg;
    381                 if (cbReadSeg != pSgBuf->paSegs[iSeg].cbSeg)
    382                     break;
     433                Assert(cbWrittenOut == 0);
     434                continue;
     435            }
     436            if (RT_FAILURE(rc) || rc == VINF_TRY_AGAIN || cbWrittenOut == 0)
     437            {
     438                AssertReturn(cbWrittenOut == 0, VERR_INTERNAL_ERROR_3);
     439                AssertReturn(rc != VINF_SUCCESS, VERR_IPE_UNEXPECTED_INFO_STATUS);
     440                return rc;
    383441            }
    384442        }
    385         if (pcbRead)
    386             *pcbRead = cbRead;
    387     }
    388 
    389     return rc;
     443        break;
     444    }
     445    AssertMsgReturn(cbWrittenOut > 0 && cbWrittenOut <= sizeof(pThis->abBuffer),
     446                    ("%zu %Rrc\n", cbWrittenOut, rc),
     447                    VERR_INTERNAL_ERROR_4);
     448
     449    /*
     450     * Adjust the Zlib output buffer members.
     451     */
     452    if (cbWrittenOut == pThis->SgBuf.paSegs[0].cbSeg)
     453    {
     454        pThis->Zlib.avail_out = sizeof(pThis->abBuffer);
     455        pThis->Zlib.next_out  = &pThis->abBuffer[0];
     456    }
     457    else
     458    {
     459        Assert(cbWrittenOut <= pThis->SgBuf.paSegs[0].cbSeg);
     460        size_t cbLeft = pThis->SgBuf.paSegs[0].cbSeg - cbWrittenOut;
     461        memmove(&pThis->abBuffer[0], &pThis->abBuffer[cbWrittenOut], cbLeft);
     462        pThis->Zlib.avail_out += (uInt)cbWrittenOut;
     463        pThis->Zlib.next_out  = &pThis->abBuffer[cbWrittenOut];
     464    }
     465
     466    return VINF_SUCCESS;
     467}
     468
     469
     470/**
     471 * Processes all available input.
     472 *
     473 * @returns IPRT status code.
     474 *
     475 * @param   pThis           The gzip I/O stream instance data.
     476 * @param   fBlocking       Whether to block or not.
     477 */
     478static int rtZipGzip_CompressIt(PRTZIPGZIPSTREAM pThis, bool fBlocking)
     479{
     480    /*
     481     * Processes all the intput currently lined up for us.
     482     */
     483    while (pThis->Zlib.avail_in > 0)
     484    {
     485        /* Make sure there is some space in the output buffer before calling
     486           deflate() so we don't waste time filling up the corners. */
     487        static const size_t s_cbFlushThreshold = 4096;
     488        AssertCompile(sizeof(pThis->abBuffer) >= s_cbFlushThreshold * 4);
     489        if (pThis->Zlib.avail_out < s_cbFlushThreshold)
     490        {
     491            int rc = rtZipGzip_WriteOutputBuffer(pThis, fBlocking);
     492            if (rc != VINF_SUCCESS)
     493                return rc;
     494            Assert(pThis->Zlib.avail_out >= s_cbFlushThreshold);
     495        }
     496
     497        int rcZlib = deflate(&pThis->Zlib, Z_NO_FLUSH);
     498        if (rcZlib != Z_OK)
     499            return rtZipGzipConvertErrFromZlib(pThis, rcZlib);
     500    }
     501    return VINF_SUCCESS;
    390502}
    391503
     
    397509{
    398510    PRTZIPGZIPSTREAM pThis = (PRTZIPGZIPSTREAM)pvThis;
    399     //int              rc;
    400511
    401512    AssertReturn(off == -1, VERR_INVALID_PARAMETER);
    402     NOREF(fBlocking);
     513    Assert(pSgBuf->cSegs == 1); NOREF(fBlocking);
     514
    403515    if (pThis->fDecompress)
    404516        return VERR_ACCESS_DENIED;
    405517
    406     /** @todo implement compression. */
    407     NOREF(pSgBuf); NOREF(pcbWritten);
    408     return VERR_NOT_IMPLEMENTED;
     518    /*
     519     * Write out the intput buffer. Using a loop here because of potential
     520     * integer type overflow since avail_in is uInt and cbSeg is size_t.
     521     */
     522    int             rc        = VINF_SUCCESS;
     523    size_t          cbWritten = 0;
     524    uint8_t const  *pbSrc     = (uint8_t const *)pSgBuf->paSegs[0].pvSeg;
     525    size_t          cbLeft    = pSgBuf->paSegs[0].cbSeg;
     526    if (cbLeft > 0)
     527        for (;;)
     528        {
     529            size_t cbThis = cbLeft < ~(uInt)0 ? cbLeft : ~(uInt)0 / 2;
     530            pThis->Zlib.next_in  = (Bytef * )pbSrc;
     531            pThis->Zlib.avail_in = (uInt)cbThis;
     532            rc = rtZipGzip_CompressIt(pThis, fBlocking);
     533
     534            Assert(cbThis >= pThis->Zlib.avail_in);
     535            cbThis -= pThis->Zlib.avail_in;
     536            cbWritten += cbThis;
     537            if (cbLeft == cbThis || rc != VINF_SUCCESS)
     538                break;
     539            pbSrc  += cbThis;
     540            cbLeft -= cbThis;
     541        }
     542
     543    if (pcbWritten)
     544        *pcbWritten = cbWritten;
     545    return rc;
     546}
     547
     548
     549/**
     550 * Processes all available input.
     551 *
     552 * @returns IPRT status code.
     553 *
     554 * @param   pThis           The gzip I/O stream instance data.
     555 * @param   fFlushType      The flush type to pass to deflate().
     556 */
     557static int rtZipGzip_FlushIt(PRTZIPGZIPSTREAM pThis, uint8_t fFlushType)
     558{
     559    /*
     560     * Tell Zlib to flush until it stops producing more output.
     561     */
     562    int rc;
     563    bool fMaybeMore = true;
     564    for (;;)
     565    {
     566        /* Write the entire output buffer. */
     567        do
     568        {
     569            rc = rtZipGzip_WriteOutputBuffer(pThis, true /*fBlocking*/);
     570            if (RT_FAILURE(rc))
     571                return rc;
     572            Assert(rc == VINF_SUCCESS);
     573        } while (pThis->Zlib.avail_out < sizeof(pThis->abBuffer));
     574
     575        if (!fMaybeMore)
     576            return VINF_SUCCESS;
     577
     578        /* Do the flushing. */
     579        pThis->Zlib.next_in  = NULL;
     580        pThis->Zlib.avail_in = 0;
     581        int rcZlib = deflate(&pThis->Zlib, fFlushType);
     582        if (rcZlib == Z_OK)
     583            fMaybeMore = pThis->Zlib.avail_out < 64 || fFlushType == Z_FINISH;
     584        else if (rcZlib == Z_STREAM_END)
     585            fMaybeMore = false;
     586        else
     587        {
     588            rtZipGzip_WriteOutputBuffer(pThis, true /*fBlocking*/);
     589            return rtZipGzipConvertErrFromZlib(pThis, rcZlib);
     590        }
     591    }
    409592}
    410593
     
    416599{
    417600    PRTZIPGZIPSTREAM pThis = (PRTZIPGZIPSTREAM)pvThis;
     601    if (!pThis->fDecompress)
     602    {
     603        int rc = rtZipGzip_FlushIt(pThis, Z_SYNC_FLUSH);
     604        if (RT_FAILURE(rc))
     605            return rc;
     606    }
     607
    418608    return RTVfsIoStrmFlush(pThis->hVfsIos);
    419609}
     
    481671    },
    482672    RTVFSIOSTREAMOPS_VERSION,
    483     0,
     673    RTVFSIOSTREAMOPS_FEAT_NO_SG,
    484674    rtZipGzip_Read,
    485675    rtZipGzip_Write,
     
    571761}
    572762
     763
     764RTDECL(int) RTZipGzipCompressIoStream(RTVFSIOSTREAM hVfsIosDst, uint32_t fFlags, uint8_t uLevel, PRTVFSIOSTREAM phVfsIosZip)
     765{
     766    AssertPtrReturn(hVfsIosDst, VERR_INVALID_HANDLE);
     767    AssertReturn(!fFlags, VERR_INVALID_PARAMETER);
     768    AssertPtrReturn(phVfsIosZip, VERR_INVALID_POINTER);
     769    AssertReturn(uLevel > 0 && uLevel <= 9, VERR_INVALID_PARAMETER);
     770
     771    uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosDst);
     772    AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
     773
     774    /*
     775     * Create the compression I/O stream.
     776     */
     777    RTVFSIOSTREAM    hVfsIos;
     778    PRTZIPGZIPSTREAM pThis;
     779    int rc = RTVfsNewIoStream(&g_rtZipGzipOps, sizeof(RTZIPGZIPSTREAM), RTFILE_O_WRITE, NIL_RTVFS, NIL_RTVFSLOCK,
     780                              &hVfsIos, (void **)&pThis);
     781    if (RT_SUCCESS(rc))
     782    {
     783        pThis->hVfsIos      = hVfsIosDst;
     784        pThis->offStream    = 0;
     785        pThis->fDecompress  = false;
     786        pThis->SgSeg.pvSeg  = &pThis->abBuffer[0];
     787        pThis->SgSeg.cbSeg  = sizeof(pThis->abBuffer);
     788        RTSgBufInit(&pThis->SgBuf, &pThis->SgSeg, 1);
     789
     790        RT_ZERO(pThis->Zlib);
     791        pThis->Zlib.opaque    = pThis;
     792        pThis->Zlib.next_out  = &pThis->abBuffer[0];
     793        pThis->Zlib.avail_out = sizeof(pThis->abBuffer);
     794
     795        rc = deflateInit2(&pThis->Zlib,
     796                          uLevel,
     797                          Z_DEFLATED,
     798                          15 /* Windows Size */ + 16 /* GZIP header */,
     799                          9 /* Max memory level for optimal speed */,
     800                          Z_DEFAULT_STRATEGY);
     801
     802        if (rc >= 0)
     803        {
     804            *phVfsIosZip = hVfsIos;
     805            return VINF_SUCCESS;
     806        }
     807
     808        rc = rtZipGzipConvertErrFromZlib(pThis, rc); /** @todo cleaning up in this situation is going to go wrong. */
     809        RTVfsIoStrmRelease(hVfsIos);
     810    }
     811    else
     812        RTVfsIoStrmRelease(hVfsIosDst);
     813    return rc;
     814}
     815
  • trunk/src/VBox/Runtime/common/zip/tarcmd.cpp

    r44300 r47359  
    912912}
    913913
     914
    914915RTDECL(RTEXITCODE) RTZipTarCmd(unsigned cArgs, char **papszArgs)
    915916{
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