Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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 : */
9 :
10 : #include "Blob.hxx"
11 : #include "Connection.hxx"
12 : #include "Util.hxx"
13 :
14 : #include <com/sun/star/lang/IllegalArgumentException.hpp>
15 : #include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
16 : #include <connectivity/dbexception.hxx>
17 : #include <cppuhelper/exc_hlp.hxx>
18 :
19 : using namespace ::connectivity::firebird;
20 :
21 : using namespace ::cppu;
22 : using namespace ::osl;
23 :
24 : using namespace ::com::sun::star;
25 : using namespace ::com::sun::star::io;
26 : using namespace ::com::sun::star::sdbc;
27 : using namespace ::com::sun::star::uno;
28 :
29 0 : Blob::Blob(isc_db_handle* pDatabaseHandle,
30 : isc_tr_handle* pTransactionHandle,
31 : ISC_QUAD& aBlobID):
32 : Blob_BASE(m_aMutex),
33 : m_pDatabaseHandle(pDatabaseHandle),
34 : m_pTransactionHandle(pTransactionHandle),
35 : m_blobID(aBlobID),
36 : m_blobHandle(0),
37 : m_bBlobOpened(false),
38 : m_nBlobLength(0),
39 0 : m_nBlobPosition(0)
40 : {
41 0 : }
42 :
43 0 : void Blob::ensureBlobIsOpened()
44 : throw(SQLException)
45 : {
46 0 : MutexGuard aGuard(m_aMutex);
47 :
48 0 : if (m_bBlobOpened)
49 0 : return;
50 :
51 : ISC_STATUS aErr;
52 : aErr = isc_open_blob2(m_statusVector,
53 : m_pDatabaseHandle,
54 : m_pTransactionHandle,
55 : &m_blobHandle,
56 : &m_blobID,
57 : 0,
58 0 : NULL);
59 :
60 0 : if (aErr)
61 0 : evaluateStatusVector(m_statusVector, "isc_open_blob2", *this);
62 :
63 0 : m_bBlobOpened = true;
64 0 : m_nBlobPosition = 0;
65 :
66 : char aBlobItems[] = {
67 : isc_info_blob_total_length
68 0 : };
69 : char aResultBuffer[20];
70 :
71 : isc_blob_info(m_statusVector,
72 : &m_blobHandle,
73 : sizeof(aBlobItems),
74 : aBlobItems,
75 : sizeof(aResultBuffer),
76 0 : aResultBuffer);
77 :
78 0 : if (aErr)
79 0 : evaluateStatusVector(m_statusVector, "isc_blob_info", *this);
80 :
81 0 : if (*aResultBuffer == isc_info_blob_total_length)
82 : {
83 0 : short aResultLength = (short) isc_vax_integer(aResultBuffer+1, 2);
84 0 : m_nBlobLength = isc_vax_integer(aResultBuffer+3, aResultLength);
85 : }
86 : else
87 : {
88 : assert(false);
89 0 : }
90 : }
91 :
92 0 : void Blob::closeBlob()
93 : throw (SQLException)
94 : {
95 0 : MutexGuard aGuard(m_aMutex);
96 :
97 0 : if (m_bBlobOpened)
98 : {
99 : ISC_STATUS aErr;
100 : aErr = isc_close_blob(m_statusVector,
101 0 : &m_blobHandle);
102 0 : if (aErr)
103 0 : evaluateStatusVector(m_statusVector, "isc_close_blob", *this);
104 :
105 0 : m_bBlobOpened = false;
106 0 : m_blobHandle = 0;
107 0 : }
108 0 : }
109 :
110 0 : void SAL_CALL Blob::disposing(void)
111 : {
112 : try
113 : {
114 0 : closeBlob();
115 : }
116 0 : catch (SQLException &e)
117 : {
118 : // we cannot throw any exceptions here...
119 : SAL_WARN("connectivity.firebird", "isc_close_blob failed\n" <<
120 : e.Message);
121 : assert(false);
122 : }
123 0 : Blob_BASE::disposing();
124 0 : }
125 :
126 0 : sal_Int64 SAL_CALL Blob::length()
127 : throw(SQLException, RuntimeException, std::exception)
128 : {
129 0 : MutexGuard aGuard(m_aMutex);
130 0 : checkDisposed(Blob_BASE::rBHelper.bDisposed);
131 0 : ensureBlobIsOpened();
132 :
133 0 : return m_nBlobLength;
134 : }
135 :
136 0 : uno::Sequence< sal_Int8 > SAL_CALL Blob::getBytes(sal_Int64 nPosition,
137 : sal_Int32 nBytes)
138 : throw(SQLException, RuntimeException, std::exception)
139 : {
140 0 : MutexGuard aGuard(m_aMutex);
141 0 : checkDisposed(Blob_BASE::rBHelper.bDisposed);
142 0 : ensureBlobIsOpened();
143 :
144 0 : if (nPosition > m_nBlobLength)
145 0 : throw lang::IllegalArgumentException("nPosition out of range", *this, 0);
146 : // We only have to read as many bytes as are available, i.e. nPosition+nBytes
147 : // can legally be greater than the total length, hence we don't bother to check.
148 :
149 0 : if (nPosition > m_nBlobPosition)
150 : {
151 : // Resets to the beginning (we can't seek these blobs)
152 0 : closeBlob();
153 0 : ensureBlobIsOpened();
154 : }
155 :
156 0 : skipBytes(nPosition - m_nBlobPosition);
157 :
158 : // Don't bother preallocating: readBytes does the appropriate calculations
159 : // and reallocates for us.
160 0 : uno::Sequence< sal_Int8 > aBytes;
161 0 : readBytes(aBytes, nBytes);
162 0 : return aBytes;
163 : }
164 :
165 0 : uno::Reference< XInputStream > SAL_CALL Blob::getBinaryStream()
166 : throw(SQLException, RuntimeException, std::exception)
167 : {
168 0 : return this;
169 : }
170 :
171 0 : sal_Int64 SAL_CALL Blob::position(const uno::Sequence< sal_Int8 >& /*rPattern*/,
172 : sal_Int64 /*nStart*/)
173 : throw(SQLException, RuntimeException, std::exception)
174 : {
175 0 : ::dbtools::throwFeatureNotImplementedSQLException("Blob::position", *this);
176 0 : return 0;
177 : }
178 :
179 0 : sal_Int64 SAL_CALL Blob::positionOfBlob(const uno::Reference< XBlob >& /*rPattern*/,
180 : sal_Int64 /*aStart*/)
181 : throw(SQLException, RuntimeException, std::exception)
182 : {
183 0 : ::dbtools::throwFeatureNotImplementedSQLException("Blob::positionOfBlob", *this);
184 0 : return 0;
185 : }
186 :
187 : // ---- XInputStream ----------------------------------------------------------
188 :
189 0 : sal_Int32 SAL_CALL Blob::readBytes(uno::Sequence< sal_Int8 >& rDataOut,
190 : sal_Int32 nBytes)
191 : throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception)
192 : {
193 0 : MutexGuard aGuard(m_aMutex);
194 0 : checkDisposed(Blob_BASE::rBHelper.bDisposed);
195 0 : ensureBlobIsOpened();
196 :
197 : // Ensure we have enough space for the amount of data we can actually read.
198 0 : const sal_Int64 nBytesAvailable = m_nBlobLength - m_nBlobPosition;
199 0 : const sal_Int32 nBytesToRead = nBytes < nBytesAvailable ? nBytes : nBytesAvailable;
200 :
201 0 : if (rDataOut.getLength() < nBytesToRead)
202 0 : rDataOut.realloc(nBytesToRead);
203 :
204 0 : sal_Int32 nTotalBytesRead = 0;
205 : ISC_STATUS aErr;
206 0 : while (nTotalBytesRead < nBytesToRead)
207 : {
208 0 : sal_uInt16 nBytesRead = 0;
209 0 : sal_uInt64 nDataRemaining = nBytesToRead - nTotalBytesRead;
210 0 : sal_uInt16 nReadSize = (nDataRemaining > SAL_MAX_UINT16) ? SAL_MAX_UINT16 : nDataRemaining;
211 : aErr = isc_get_segment(m_statusVector,
212 : &m_blobHandle,
213 : &nBytesRead,
214 : nReadSize,
215 0 : (char*) rDataOut.getArray() + nTotalBytesRead);
216 0 : if (aErr && IndicatesError(m_statusVector))
217 : {
218 0 : OUString sError(StatusVectorToString(m_statusVector, "isc_get_segment"));
219 0 : throw IOException(sError, *this);
220 : }
221 0 : nTotalBytesRead += nBytesRead;
222 0 : m_nBlobPosition += nBytesRead;
223 : }
224 :
225 0 : return nTotalBytesRead;
226 : }
227 :
228 0 : sal_Int32 SAL_CALL Blob::readSomeBytes(uno::Sequence< sal_Int8 >& rDataOut,
229 : sal_Int32 nMaximumBytes)
230 : throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception)
231 : {
232 : // We don't have any way of verifying how many bytes are immediately available,
233 : // hence we just pass through direct to readBytes
234 : // (Spec: "reads the available number of bytes, at maximum nMaxBytesToRead.")
235 0 : return readBytes(rDataOut, nMaximumBytes);
236 : }
237 :
238 0 : void SAL_CALL Blob::skipBytes(sal_Int32 nBytesToSkip)
239 : throw (NotConnectedException, BufferSizeExceededException, IOException, RuntimeException, std::exception)
240 : {
241 : // There is no way of directly skipping, hence we have to pretend to skip
242 : // by reading & discarding the data.
243 0 : uno::Sequence< sal_Int8 > aBytes;
244 0 : readBytes(aBytes, nBytesToSkip);
245 0 : }
246 :
247 0 : sal_Int32 SAL_CALL Blob::available()
248 : throw (NotConnectedException, IOException, RuntimeException, std::exception)
249 : {
250 0 : MutexGuard aGuard(m_aMutex);
251 :
252 : try
253 : {
254 0 : checkDisposed(Blob_BASE::rBHelper.bDisposed);
255 0 : ensureBlobIsOpened();
256 : }
257 0 : catch (const NotConnectedException&)
258 : {
259 0 : throw;
260 : }
261 0 : catch (const IOException&)
262 : {
263 0 : throw;
264 : }
265 0 : catch (const RuntimeException&)
266 : {
267 0 : throw;
268 : }
269 0 : catch (const Exception& e)
270 : {
271 0 : css::uno::Any a(cppu::getCaughtException());
272 : throw css::lang::WrappedTargetRuntimeException(
273 0 : "wrapped Exception " + e.Message,
274 0 : css::uno::Reference<css::uno::XInterface>(), a);
275 : }
276 :
277 0 : return m_nBlobLength - m_nBlobPosition;
278 : }
279 :
280 0 : void SAL_CALL Blob::closeInput()
281 : throw(NotConnectedException, IOException, RuntimeException, std::exception)
282 : {
283 : try
284 : {
285 0 : closeBlob();
286 : }
287 0 : catch (const NotConnectedException&)
288 : {
289 0 : throw;
290 : }
291 0 : catch (const IOException&)
292 : {
293 0 : throw;
294 : }
295 0 : catch (const RuntimeException&)
296 : {
297 0 : throw;
298 : }
299 0 : catch (const Exception& e)
300 : {
301 0 : css::uno::Any a(cppu::getCaughtException());
302 : throw css::lang::WrappedTargetRuntimeException(
303 0 : "wrapped Exception " + e.Message,
304 0 : css::uno::Reference<css::uno::XInterface>(), a);
305 : }
306 0 : }
307 :
308 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|