Use COMReference to handle COM pointers in CreateShortcut
[LibreOffice.git] / connectivity / source / drivers / firebird / Blob.cxx
blob774246fa18d4ff014f8e7dc56aacdfdf3f7db684
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 <comphelper/diagnose_ex.hxx>
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(std::vector<char>& rDataOut)
127 checkDisposed(Blob_BASE::rBHelper.bDisposed);
128 ensureBlobIsOpened();
130 sal_uInt16 nMaxSize = getMaximumSegmentSize();
132 if(rDataOut.size() < nMaxSize)
133 rDataOut.resize(nMaxSize);
135 sal_uInt16 nActualSize = 0;
136 ISC_STATUS aRet = isc_get_segment(m_statusVector,
137 &m_blobHandle,
138 &nActualSize,
139 nMaxSize,
140 rDataOut.data() );
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.size() > nActualSize)
149 rDataOut.resize(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(u"nPosition out of range"_ustr, *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(u"Blob::position"_ustr, *this);
240 sal_Int64 SAL_CALL Blob::positionOfBlob(const uno::Reference< XBlob >& /*rPattern*/,
241 sal_Int64 /*aStart*/)
243 ::dbtools::throwFeatureNotImplementedSQLException(u"Blob::positionOfBlob"_ustr, *this);
246 // ---- XInputStream ----------------------------------------------------------
248 sal_Int32 SAL_CALL Blob::readBytes(uno::Sequence< sal_Int8 >& rDataOut,
249 sal_Int32 nBytes)
251 MutexGuard aGuard(m_aMutex);
255 checkDisposed(Blob_BASE::rBHelper.bDisposed);
256 ensureBlobIsOpened();
258 catch (const NotConnectedException&)
260 throw;
262 catch (const BufferSizeExceededException&)
264 throw;
266 catch (const IOException&)
268 throw;
270 catch (const RuntimeException&)
272 throw;
274 catch (const Exception& e)
276 css::uno::Any a(cppu::getCaughtException());
277 throw css::lang::WrappedTargetRuntimeException(
278 "wrapped Exception " + e.Message,
279 css::uno::Reference<css::uno::XInterface>(), a);
282 // Ensure we have enough space for the amount of data we can actually read.
283 const sal_Int64 nBytesAvailable = m_nBlobLength - m_nBlobPosition;
284 const sal_Int32 nBytesToRead = std::min<sal_Int64>(nBytes, nBytesAvailable);
286 if (rDataOut.getLength() < nBytesToRead)
287 rDataOut.realloc(nBytesToRead);
289 sal_Int32 nTotalBytesRead = 0;
290 ISC_STATUS aErr;
291 while (nTotalBytesRead < nBytesToRead)
293 sal_uInt16 nBytesRead = 0;
294 sal_uInt64 nDataRemaining = nBytesToRead - nTotalBytesRead;
295 sal_uInt16 nReadSize = std::min<sal_uInt64>(nDataRemaining, SAL_MAX_UINT16);
296 aErr = isc_get_segment(m_statusVector,
297 &m_blobHandle,
298 &nBytesRead,
299 nReadSize,
300 reinterpret_cast<char*>(rDataOut.getArray()) + nTotalBytesRead);
301 if (aErr && IndicatesError(m_statusVector))
303 OUString sError(StatusVectorToString(m_statusVector, u"isc_get_segment"));
304 throw IOException(sError, *this);
306 nTotalBytesRead += nBytesRead;
307 m_nBlobPosition += nBytesRead;
310 return nTotalBytesRead;
313 sal_Int32 SAL_CALL Blob::readSomeBytes(uno::Sequence< sal_Int8 >& rDataOut,
314 sal_Int32 nMaximumBytes)
316 // We don't have any way of verifying how many bytes are immediately available,
317 // hence we just pass through direct to readBytes
318 // (Spec: "reads the available number of bytes, at maximum nMaxBytesToRead.")
319 return readBytes(rDataOut, nMaximumBytes);
322 void SAL_CALL Blob::skipBytes(sal_Int32 nBytesToSkip)
324 // There is no way of directly skipping, hence we have to pretend to skip
325 // by reading & discarding the data.
326 uno::Sequence< sal_Int8 > aBytes;
327 readBytes(aBytes, nBytesToSkip);
330 sal_Int32 SAL_CALL Blob::available()
332 MutexGuard aGuard(m_aMutex);
336 checkDisposed(Blob_BASE::rBHelper.bDisposed);
337 ensureBlobIsOpened();
339 catch (const NotConnectedException&)
341 throw;
343 catch (const IOException&)
345 throw;
347 catch (const RuntimeException&)
349 throw;
351 catch (const Exception& e)
353 css::uno::Any a(cppu::getCaughtException());
354 throw css::lang::WrappedTargetRuntimeException(
355 "wrapped Exception " + e.Message,
356 css::uno::Reference<css::uno::XInterface>(), a);
359 return m_nBlobLength - m_nBlobPosition;
362 void SAL_CALL Blob::closeInput()
366 closeBlob();
368 catch (const NotConnectedException&)
370 throw;
372 catch (const IOException&)
374 throw;
376 catch (const RuntimeException&)
378 throw;
380 catch (const Exception& e)
382 css::uno::Any a(cppu::getCaughtException());
383 throw css::lang::WrappedTargetRuntimeException(
384 "wrapped Exception " + e.Message,
385 css::uno::Reference<css::uno::XInterface>(), a);
389 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */