1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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/.
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
):
38 m_pDatabaseHandle(pDatabaseHandle
),
39 m_pTransactionHandle(pTransactionHandle
),
41 #if SAL_TYPES_SIZEOFPOINTER == 8
44 m_blobHandle(nullptr),
53 void Blob::ensureBlobIsOpened()
55 MutexGuard
aGuard(m_aMutex
);
61 aErr
= isc_open_blob2(m_statusVector
,
70 evaluateStatusVector(m_statusVector
, u
"isc_open_blob2", *this);
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
,
89 sizeof(aResultBuffer
),
93 evaluateStatusVector(m_statusVector
, u
"isc_blob_info", *this);
95 char* pIt
= aResultBuffer
;
96 while( *pIt
!= isc_info_end
) // info is in clusters
99 short aResultLength
= static_cast<short>(isc_vax_integer(pIt
, 2));
104 case isc_info_blob_total_length
:
105 m_nBlobLength
= isc_vax_integer(pIt
, aResultLength
);
107 case isc_info_blob_max_segment
:
108 m_nMaxSegmentSize
= isc_vax_integer(pIt
, aResultLength
);
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
,
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
);
163 aErr
= isc_close_blob(m_statusVector
,
166 evaluateStatusVector(m_statusVector
, u
"isc_close_blob", *this);
168 m_bBlobOpened
= false;
169 #if SAL_TYPES_SIZEOFPOINTER == 8
172 m_blobHandle
= nullptr;
176 void SAL_CALL
Blob::disposing()
182 catch (const SQLException
&)
184 // we cannot throw any exceptions here...
185 TOOLS_WARN_EXCEPTION("connectivity.firebird", "isc_close_blob failed");
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
,
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)
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
);
229 uno::Reference
< XInputStream
> SAL_CALL
Blob::getBinaryStream()
234 sal_Int64 SAL_CALL
Blob::position(const uno::Sequence
< sal_Int8
>& /*rPattern*/,
235 sal_Int64
/*nStart*/)
237 ::dbtools::throwFeatureNotImplementedSQLException("Blob::position", *this);
241 sal_Int64 SAL_CALL
Blob::positionOfBlob(const uno::Reference
< XBlob
>& /*rPattern*/,
242 sal_Int64
/*aStart*/)
244 ::dbtools::throwFeatureNotImplementedSQLException("Blob::positionOfBlob", *this);
248 // ---- XInputStream ----------------------------------------------------------
250 sal_Int32 SAL_CALL
Blob::readBytes(uno::Sequence
< sal_Int8
>& rDataOut
,
253 MutexGuard
aGuard(m_aMutex
);
257 checkDisposed(Blob_BASE::rBHelper
.bDisposed
);
258 ensureBlobIsOpened();
260 catch (const NotConnectedException
&)
264 catch (const BufferSizeExceededException
&)
268 catch (const IOException
&)
272 catch (const RuntimeException
&)
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;
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
,
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
&)
345 catch (const IOException
&)
349 catch (const RuntimeException
&)
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()
370 catch (const NotConnectedException
&)
374 catch (const IOException
&)
378 catch (const RuntimeException
&)
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: */