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