Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  Blob.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */


#include "Blob.hxx"
#include "Util.hxx"

#include <com/sun/star/io/BufferSizeExceededException.hpp>
#include <com/sun/star/io/NotConnectedException.hpp>
#include <com/sun/star/io/IOException.hpp>
#include <com/sun/star/lang/IllegalArgumentException.hpp>
#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
#include <com/sun/star/sdbc/SQLException.hpp>
#include <connectivity/CommonTools.hxx>
#include <connectivity/dbexception.hxx>
#include <cppuhelper/exc_hlp.hxx>
#include <comphelper/diagnose_ex.hxx>

using namespace ::connectivity::firebird;

using namespace ::cppu;
using namespace ::osl;

using namespace ::com::sun::star;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::sdbc;
using namespace ::com::sun::star::uno;

Blob::Blob(isc_db_handle* pDatabaseHandle,
           isc_tr_handle* pTransactionHandle,
           ISC_QUAD const & aBlobID):
    Blob_BASE(m_aMutex),
    m_pDatabaseHandle(pDatabaseHandle),
    m_pTransactionHandle(pTransactionHandle),
    m_blobID(aBlobID),
#if SAL_TYPES_SIZEOFPOINTER == 8
    m_blobHandle(0),
#else
    m_blobHandle(nullptr),
#endif
    m_bBlobOpened(false),
    m_nBlobLength(0),
    m_nMaxSegmentSize(0),
    m_nBlobPosition(0)
{
}

void Blob::ensureBlobIsOpened()
{
    MutexGuard aGuard(m_aMutex);

    if (m_bBlobOpened)
        return;

    ISC_STATUS aErr;
    aErr = isc_open_blob2(m_statusVector,
                          m_pDatabaseHandle,
                          m_pTransactionHandle,
                          &m_blobHandle,
                          &m_blobID,
                          0,
                          nullptr);

    if (aErr)
        evaluateStatusVector(m_statusVector, u"isc_open_blob2", *this);

    m_bBlobOpened = true;
    m_nBlobPosition = 0;

    char aBlobItems[] = {
        isc_info_blob_total_length,
        isc_info_blob_max_segment
    };

    // Assuming a data (e.g. length of blob) is maximum 64 bit.
    // That means we need 8 bytes for data + 2 for length of data + 1 for item
    // identifier for each item.
    char aResultBuffer[11 + 11];

    aErr = isc_blob_info(m_statusVector,
                  &m_blobHandle,
                  sizeof(aBlobItems),
                  aBlobItems,
                  sizeof(aResultBuffer),
                  aResultBuffer);

    if (aErr)
        evaluateStatusVector(m_statusVector, u"isc_blob_info", *this);

    char* pIt = aResultBuffer;
    while( *pIt != isc_info_end ) // info is in clusters
    {
        char item = *pIt++;
        short aResultLength = static_cast<short>(isc_vax_integer(pIt, 2));

        pIt += 2;
        switch(item)
        {
            case isc_info_blob_total_length:
                m_nBlobLength = isc_vax_integer(pIt, aResultLength);
                break;
            case isc_info_blob_max_segment:
                m_nMaxSegmentSize = isc_vax_integer(pIt, aResultLength);
                break;
            default:
                assert(false);
                break;
        }
        pIt += aResultLength;
    }
}

sal_uInt16 Blob::getMaximumSegmentSize()
{
    ensureBlobIsOpened();

    return m_nMaxSegmentSize;
}

bool Blob::readOneSegment(std::vector<char>& rDataOut)
{
    checkDisposed(Blob_BASE::rBHelper.bDisposed);
    ensureBlobIsOpened();

    sal_uInt16 nMaxSize = getMaximumSegmentSize();

    if(rDataOut.size() < nMaxSize)
        rDataOut.resize(nMaxSize);

    sal_uInt16 nActualSize = 0;
    ISC_STATUS aRet = isc_get_segment(m_statusVector,
            &m_blobHandle,
            &nActualSize,
            nMaxSize,
            rDataOut.data() );

    if (aRet && aRet != isc_segstr_eof && IndicatesError(m_statusVector))
    {
        OUString sError(StatusVectorToString(m_statusVector, u"isc_get_segment"));
        throw IOException(sError, *this);
    }

    if (rDataOut.size() > nActualSize)
        rDataOut.resize(nActualSize);
    m_nBlobPosition += nActualSize;
    return aRet == isc_segstr_eof;  // last segment read
}


void Blob::closeBlob()
{
    MutexGuard aGuard(m_aMutex);

    if (!m_bBlobOpened)
        return;

    ISC_STATUS aErr;
    aErr = isc_close_blob(m_statusVector,
                          &m_blobHandle);
    if (aErr)
        evaluateStatusVector(m_statusVector, u"isc_close_blob", *this);

    m_bBlobOpened = false;
#if SAL_TYPES_SIZEOFPOINTER == 8
    m_blobHandle = 0;
#else
    m_blobHandle = nullptr;
#endif
}

void SAL_CALL Blob::disposing()
{
    try
    {
         closeBlob();
    }
    catch (const SQLException &)
    {
        // we cannot throw any exceptions here...
        TOOLS_WARN_EXCEPTION("connectivity.firebird""isc_close_blob failed");
        assert(false);
    }
    Blob_BASE::disposing();
}

sal_Int64 SAL_CALL Blob::length()
{
    MutexGuard aGuard(m_aMutex);
    checkDisposed(Blob_BASE::rBHelper.bDisposed);
    ensureBlobIsOpened();

    return m_nBlobLength;
}

uno::Sequence< sal_Int8 > SAL_CALL  Blob::getBytes(sal_Int64 nPosition,
                                                   sal_Int32 nBytes)
{
    MutexGuard aGuard(m_aMutex);
    checkDisposed(Blob_BASE::rBHelper.bDisposed);
    ensureBlobIsOpened();

    if (nPosition > m_nBlobLength || nPosition < 1)
        throw lang::IllegalArgumentException(u"nPosition out of range"_ustr, *this, 0);
    // We only have to read as many bytes as are available, i.e. nPosition+nBytes
    // can legally be greater than the total length, hence we don't bother to check.

    if (nPosition -1 < m_nBlobPosition)
    {
        // Resets to the beginning (we can't seek these blobs)
        closeBlob();
        ensureBlobIsOpened();
    }

    // nPosition is indexed from 1.
    skipBytes(nPosition - m_nBlobPosition -1 );

    // Don't bother preallocating: readBytes does the appropriate calculations
    // and reallocates for us.
    uno::Sequence< sal_Int8 > aBytes;
    readBytes(aBytes, nBytes);
    return aBytes;
}

uno::Reference< XInputStream > SAL_CALL  Blob::getBinaryStream()
{
    return this;
}

sal_Int64 SAL_CALL  Blob::position(const uno::Sequence< sal_Int8 >& /*rPattern*/,
                                   sal_Int64 /*nStart*/)
{
    ::dbtools::throwFeatureNotImplementedSQLException(u"Blob::position"_ustr, *this);
}

sal_Int64 SAL_CALL  Blob::positionOfBlob(const uno::Reference< XBlob >& /*rPattern*/,
                                         sal_Int64 /*aStart*/)
{
    ::dbtools::throwFeatureNotImplementedSQLException(u"Blob::positionOfBlob"_ustr, *this);
}

// ---- XInputStream ----------------------------------------------------------

sal_Int32 SAL_CALL Blob::readBytes(uno::Sequence< sal_Int8 >& rDataOut,
                                   sal_Int32 nBytes)
{
    MutexGuard aGuard(m_aMutex);

    try
    {
        checkDisposed(Blob_BASE::rBHelper.bDisposed);
        ensureBlobIsOpened();
    }
    catch (const NotConnectedException&)
    {
        throw;
    }
    catch (const BufferSizeExceededException&)
    {
        throw;
    }
    catch (const IOException&)
    {
        throw;
    }
    catch (const RuntimeException&)
    {
        throw;
    }
    catch (const Exception& e)
    {
        css::uno::Any a(cppu::getCaughtException());
        throw css::lang::WrappedTargetRuntimeException(
            "wrapped Exception " + e.Message,
            css::uno::Reference<css::uno::XInterface>(), a);
    }

    // Ensure we have enough space for the amount of data we can actually read.
    const sal_Int64 nBytesAvailable = m_nBlobLength - m_nBlobPosition;
    const sal_Int32 nBytesToRead = std::min<sal_Int64>(nBytes, nBytesAvailable);

    if (rDataOut.getLength() < nBytesToRead)
        rDataOut.realloc(nBytesToRead);

    sal_Int32 nTotalBytesRead = 0;
    ISC_STATUS aErr;
    while (nTotalBytesRead < nBytesToRead)
    {
        sal_uInt16 nBytesRead = 0;
        sal_uInt64 nDataRemaining = nBytesToRead - nTotalBytesRead;
        sal_uInt16 nReadSize = std::min<sal_uInt64>(nDataRemaining, SAL_MAX_UINT16);
        aErr = isc_get_segment(m_statusVector,
                               &m_blobHandle,
                               &nBytesRead,
                               nReadSize,
                               reinterpret_cast<char*>(rDataOut.getArray()) + nTotalBytesRead);
        if (aErr && IndicatesError(m_statusVector))
        {
            OUString sError(StatusVectorToString(m_statusVector, u"isc_get_segment"));
            throw IOException(sError, *this);
        }
        nTotalBytesRead += nBytesRead;
        m_nBlobPosition += nBytesRead;
    }

    return nTotalBytesRead;
}

sal_Int32 SAL_CALL Blob::readSomeBytes(uno::Sequence< sal_Int8 >& rDataOut,
                                sal_Int32 nMaximumBytes)
{
    // We don't have any way of verifying how many bytes are immediately available,
    // hence we just pass through direct to readBytes
    // (Spec: "reads the available number of bytes, at maximum nMaxBytesToRead.")
    return readBytes(rDataOut, nMaximumBytes);
}

void SAL_CALL Blob::skipBytes(sal_Int32 nBytesToSkip)
{
    // There is no way of directly skipping, hence we have to pretend to skip
    // by reading & discarding the data.
    uno::Sequence< sal_Int8 > aBytes;
    readBytes(aBytes, nBytesToSkip);
}

sal_Int32 SAL_CALL Blob::available()
{
    MutexGuard aGuard(m_aMutex);

    try
    {
        checkDisposed(Blob_BASE::rBHelper.bDisposed);
        ensureBlobIsOpened();
    }
    catch (const NotConnectedException&)
    {
        throw;
    }
    catch (const IOException&)
    {
        throw;
    }
    catch (const RuntimeException&)
    {
        throw;
    }
    catch (const Exception& e)
    {
        css::uno::Any a(cppu::getCaughtException());
        throw css::lang::WrappedTargetRuntimeException(
            "wrapped Exception " + e.Message,
            css::uno::Reference<css::uno::XInterface>(), a);
    }

    return m_nBlobLength - m_nBlobPosition;
}

void SAL_CALL Blob::closeInput()
{
    try
    {
        closeBlob();
    }
    catch (const NotConnectedException&)
    {
        throw;
    }
    catch (const IOException&)
    {
        throw;
    }
    catch (const RuntimeException&)
    {
        throw;
    }
    catch (const Exception& e)
    {
        css::uno::Any a(cppu::getCaughtException());
        throw css::lang::WrappedTargetRuntimeException(
            "wrapped Exception " + e.Message,
            css::uno::Reference<css::uno::XInterface>(), a);
    }
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

Messung V0.5
C=96 H=100 G=97

¤ Dauer der Verarbeitung: 0.12 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge