bump product version to 7.2.5.1
[LibreOffice.git] / connectivity / source / drivers / firebird / Blob.cxx
blobedcc0d233989b5124782481aa45cd8483e3a41c4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
10 #include "Blob.hxx"
11 #include "Util.hxx"
13 #include <com/sun/star/io/BufferSizeExceededException.hpp>
14 #include <com/sun/star/io/NotConnectedException.hpp>
15 #include <com/sun/star/io/IOException.hpp>
16 #include <com/sun/star/lang/IllegalArgumentException.hpp>
17 #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
18 #include <com/sun/star/sdbc/SQLException.hpp>
19 #include <connectivity/CommonTools.hxx>
20 #include <connectivity/dbexception.hxx>
21 #include <cppuhelper/exc_hlp.hxx>
22 #include <tools/diagnose_ex.h>
24 using namespace ::connectivity::firebird;
26 using namespace ::cppu;
27 using namespace ::osl;
29 using namespace ::com::sun::star;
30 using namespace ::com::sun::star::io;
31 using namespace ::com::sun::star::sdbc;
32 using namespace ::com::sun::star::uno;
34 Blob::Blob(isc_db_handle* pDatabaseHandle,
35 isc_tr_handle* pTransactionHandle,
36 ISC_QUAD const & aBlobID):
37 Blob_BASE(m_aMutex),
38 m_pDatabaseHandle(pDatabaseHandle),
39 m_pTransactionHandle(pTransactionHandle),
40 m_blobID(aBlobID),
41 #if SAL_TYPES_SIZEOFPOINTER == 8
42 m_blobHandle(0),
43 #else
44 m_blobHandle(nullptr),
45 #endif
46 m_bBlobOpened(false),
47 m_nBlobLength(0),
48 m_nMaxSegmentSize(0),
49 m_nBlobPosition(0)
53 void Blob::ensureBlobIsOpened()
55 MutexGuard aGuard(m_aMutex);
57 if (m_bBlobOpened)
58 return;
60 ISC_STATUS aErr;
61 aErr = isc_open_blob2(m_statusVector,
62 m_pDatabaseHandle,
63 m_pTransactionHandle,
64 &m_blobHandle,
65 &m_blobID,
67 nullptr);
69 if (aErr)
70 evaluateStatusVector(m_statusVector, u"isc_open_blob2", *this);
72 m_bBlobOpened = true;
73 m_nBlobPosition = 0;
75 char aBlobItems[] = {
76 isc_info_blob_total_length,
77 isc_info_blob_max_segment
80 // Assuming a data (e.g. length of blob) is maximum 64 bit.
81 // That means we need 8 bytes for data + 2 for length of data + 1 for item
82 // identifier for each item.
83 char aResultBuffer[11 + 11];
85 aErr = isc_blob_info(m_statusVector,
86 &m_blobHandle,
87 sizeof(aBlobItems),
88 aBlobItems,
89 sizeof(aResultBuffer),
90 aResultBuffer);
92 if (aErr)
93 evaluateStatusVector(m_statusVector, u"isc_blob_info", *this);
95 char* pIt = aResultBuffer;
96 while( *pIt != isc_info_end ) // info is in clusters
98 char item = *pIt++;
99 short aResultLength = static_cast<short>(isc_vax_integer(pIt, 2));
101 pIt += 2;
102 switch(item)
104 case isc_info_blob_total_length:
105 m_nBlobLength = isc_vax_integer(pIt, aResultLength);
106 break;
107 case isc_info_blob_max_segment:
108 m_nMaxSegmentSize = isc_vax_integer(pIt, aResultLength);
109 break;
110 default:
111 assert(false);
112 break;
114 pIt += aResultLength;
118 sal_uInt16 Blob::getMaximumSegmentSize()
120 ensureBlobIsOpened();
122 return m_nMaxSegmentSize;
125 bool Blob::readOneSegment(uno::Sequence< sal_Int8 >& rDataOut)
127 checkDisposed(Blob_BASE::rBHelper.bDisposed);
128 ensureBlobIsOpened();
130 sal_uInt16 nMaxSize = getMaximumSegmentSize();
132 if(rDataOut.getLength() < nMaxSize)
133 rDataOut.realloc(nMaxSize);
135 sal_uInt16 nActualSize = 0;
136 ISC_STATUS aRet = isc_get_segment(m_statusVector,
137 &m_blobHandle,
138 &nActualSize,
139 nMaxSize,
140 reinterpret_cast<char*>(rDataOut.getArray()) );
142 if (aRet && aRet != isc_segstr_eof && IndicatesError(m_statusVector))
144 OUString sError(StatusVectorToString(m_statusVector, u"isc_get_segment"));
145 throw IOException(sError, *this);
148 if (rDataOut.getLength() > nActualSize)
149 rDataOut.realloc(nActualSize);
150 m_nBlobPosition += nActualSize;
151 return aRet == isc_segstr_eof; // last segment read
155 void Blob::closeBlob()
157 MutexGuard aGuard(m_aMutex);
159 if (!m_bBlobOpened)
160 return;
162 ISC_STATUS aErr;
163 aErr = isc_close_blob(m_statusVector,
164 &m_blobHandle);
165 if (aErr)
166 evaluateStatusVector(m_statusVector, u"isc_close_blob", *this);
168 m_bBlobOpened = false;
169 #if SAL_TYPES_SIZEOFPOINTER == 8
170 m_blobHandle = 0;
171 #else
172 m_blobHandle = nullptr;
173 #endif
176 void SAL_CALL Blob::disposing()
180 closeBlob();
182 catch (const SQLException &)
184 // we cannot throw any exceptions here...
185 TOOLS_WARN_EXCEPTION("connectivity.firebird", "isc_close_blob failed");
186 assert(false);
188 Blob_BASE::disposing();
191 sal_Int64 SAL_CALL Blob::length()
193 MutexGuard aGuard(m_aMutex);
194 checkDisposed(Blob_BASE::rBHelper.bDisposed);
195 ensureBlobIsOpened();
197 return m_nBlobLength;
200 uno::Sequence< sal_Int8 > SAL_CALL Blob::getBytes(sal_Int64 nPosition,
201 sal_Int32 nBytes)
203 MutexGuard aGuard(m_aMutex);
204 checkDisposed(Blob_BASE::rBHelper.bDisposed);
205 ensureBlobIsOpened();
207 if (nPosition > m_nBlobLength || nPosition < 1)
208 throw lang::IllegalArgumentException("nPosition out of range", *this, 0);
209 // We only have to read as many bytes as are available, i.e. nPosition+nBytes
210 // can legally be greater than the total length, hence we don't bother to check.
212 if (nPosition -1 < m_nBlobPosition)
214 // Resets to the beginning (we can't seek these blobs)
215 closeBlob();
216 ensureBlobIsOpened();
219 // nPosition is indexed from 1.
220 skipBytes(nPosition - m_nBlobPosition -1 );
222 // Don't bother preallocating: readBytes does the appropriate calculations
223 // and reallocates for us.
224 uno::Sequence< sal_Int8 > aBytes;
225 readBytes(aBytes, nBytes);
226 return aBytes;
229 uno::Reference< XInputStream > SAL_CALL Blob::getBinaryStream()
231 return this;
234 sal_Int64 SAL_CALL Blob::position(const uno::Sequence< sal_Int8 >& /*rPattern*/,
235 sal_Int64 /*nStart*/)
237 ::dbtools::throwFeatureNotImplementedSQLException("Blob::position", *this);
238 return 0;
241 sal_Int64 SAL_CALL Blob::positionOfBlob(const uno::Reference< XBlob >& /*rPattern*/,
242 sal_Int64 /*aStart*/)
244 ::dbtools::throwFeatureNotImplementedSQLException("Blob::positionOfBlob", *this);
245 return 0;
248 // ---- XInputStream ----------------------------------------------------------
250 sal_Int32 SAL_CALL Blob::readBytes(uno::Sequence< sal_Int8 >& rDataOut,
251 sal_Int32 nBytes)
253 MutexGuard aGuard(m_aMutex);
257 checkDisposed(Blob_BASE::rBHelper.bDisposed);
258 ensureBlobIsOpened();
260 catch (const NotConnectedException&)
262 throw;
264 catch (const BufferSizeExceededException&)
266 throw;
268 catch (const IOException&)
270 throw;
272 catch (const RuntimeException&)
274 throw;
276 catch (const Exception& e)
278 css::uno::Any a(cppu::getCaughtException());
279 throw css::lang::WrappedTargetRuntimeException(
280 "wrapped Exception " + e.Message,
281 css::uno::Reference<css::uno::XInterface>(), a);
284 // Ensure we have enough space for the amount of data we can actually read.
285 const sal_Int64 nBytesAvailable = m_nBlobLength - m_nBlobPosition;
286 const sal_Int32 nBytesToRead = std::min<sal_Int64>(nBytes, nBytesAvailable);
288 if (rDataOut.getLength() < nBytesToRead)
289 rDataOut.realloc(nBytesToRead);
291 sal_Int32 nTotalBytesRead = 0;
292 ISC_STATUS aErr;
293 while (nTotalBytesRead < nBytesToRead)
295 sal_uInt16 nBytesRead = 0;
296 sal_uInt64 nDataRemaining = nBytesToRead - nTotalBytesRead;
297 sal_uInt16 nReadSize = std::min<sal_uInt64>(nDataRemaining, SAL_MAX_UINT16);
298 aErr = isc_get_segment(m_statusVector,
299 &m_blobHandle,
300 &nBytesRead,
301 nReadSize,
302 reinterpret_cast<char*>(rDataOut.getArray()) + nTotalBytesRead);
303 if (aErr && IndicatesError(m_statusVector))
305 OUString sError(StatusVectorToString(m_statusVector, u"isc_get_segment"));
306 throw IOException(sError, *this);
308 nTotalBytesRead += nBytesRead;
309 m_nBlobPosition += nBytesRead;
312 return nTotalBytesRead;
315 sal_Int32 SAL_CALL Blob::readSomeBytes(uno::Sequence< sal_Int8 >& rDataOut,
316 sal_Int32 nMaximumBytes)
318 // We don't have any way of verifying how many bytes are immediately available,
319 // hence we just pass through direct to readBytes
320 // (Spec: "reads the available number of bytes, at maximum nMaxBytesToRead.")
321 return readBytes(rDataOut, nMaximumBytes);
324 void SAL_CALL Blob::skipBytes(sal_Int32 nBytesToSkip)
326 // There is no way of directly skipping, hence we have to pretend to skip
327 // by reading & discarding the data.
328 uno::Sequence< sal_Int8 > aBytes;
329 readBytes(aBytes, nBytesToSkip);
332 sal_Int32 SAL_CALL Blob::available()
334 MutexGuard aGuard(m_aMutex);
338 checkDisposed(Blob_BASE::rBHelper.bDisposed);
339 ensureBlobIsOpened();
341 catch (const NotConnectedException&)
343 throw;
345 catch (const IOException&)
347 throw;
349 catch (const RuntimeException&)
351 throw;
353 catch (const Exception& e)
355 css::uno::Any a(cppu::getCaughtException());
356 throw css::lang::WrappedTargetRuntimeException(
357 "wrapped Exception " + e.Message,
358 css::uno::Reference<css::uno::XInterface>(), a);
361 return m_nBlobLength - m_nBlobPosition;
364 void SAL_CALL Blob::closeInput()
368 closeBlob();
370 catch (const NotConnectedException&)
372 throw;
374 catch (const IOException&)
376 throw;
378 catch (const RuntimeException&)
380 throw;
382 catch (const Exception& e)
384 css::uno::Any a(cppu::getCaughtException());
385 throw css::lang::WrappedTargetRuntimeException(
386 "wrapped Exception " + e.Message,
387 css::uno::Reference<css::uno::XInterface>(), a);
391 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */