/* * The contents of this file are subject to the Initial * Developer's Public License Version 1.0 (the "License"); * you may not use this file except in compliance with the * License. You may obtain a copy of the License at * http://www.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl. * * Software distributed under the License is distributed AS IS, * WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the License for the specific language governing rights * and limitations under the License. * * The Original Code was created by Claudio Valderrama on 16-Mar-2007 * for the Firebird Open Source RDBMS project. * * Copyright (c) 2007 Claudio Valderrama * and all contributors signed below. * * All Rights Reserved. * Contributor(s): ______________________________________. * */ #include "UserBlob.h" #include "../jrd/ibase.h" #include "../jrd/common.h" static const USHORT SEGMENT_LIMIT = 65535; bool UserBlob::open(FB_API_HANDLE& db, FB_API_HANDLE& trans, ISC_QUAD& blobid) { if (m_direction != dir_none) return false; if (!blobIsNull(blobid) && !isc_open_blob(m_status, &db, &trans, &m_blob, &blobid)) { m_direction = dir_read; return true; } return false; } bool UserBlob::open(FB_API_HANDLE& db, FB_API_HANDLE& trans, ISC_QUAD& blobid, USHORT bpb_len, const UCHAR* bpb) { if (m_direction != dir_none) return false; if (bpb_len > 0 && !bpb || blobIsNull(blobid)) return false; if (!isc_open_blob2(m_status, &db, &trans, &m_blob, &blobid, bpb_len, bpb)) { m_direction = dir_read; return true; } return false; } bool UserBlob::create(FB_API_HANDLE& db, FB_API_HANDLE& trans, ISC_QUAD& blobid) { if (m_direction != dir_none) return false; blobid.gds_quad_high = blobid.gds_quad_low = 0; if (!isc_create_blob(m_status, &db, &trans, &m_blob, &blobid)) { m_direction = dir_write; return true; } return false; } bool UserBlob::create(FB_API_HANDLE& db, FB_API_HANDLE& trans, ISC_QUAD& blobid, USHORT bpb_len, const UCHAR* bpb) { if (m_direction != dir_none) return false; if (bpb_len > 0 && !bpb) return false; const char* bpb2 = reinterpret_cast(bpb); blobid.gds_quad_high = blobid.gds_quad_low = 0; if (!isc_create_blob2(m_status, &db, &trans, &m_blob, &blobid, bpb_len, bpb2)) { m_direction = dir_write; return true; } return false; } bool UserBlob::close(bool force_internal_SV) { bool rc = false; if (m_blob) { rc = !isc_close_blob(force_internal_SV ? m_default_status : m_status, &m_blob); m_blob = 0; m_direction = dir_none; } return rc; } bool UserBlob::getSegment(size_t len, size_t& real_len, void* buffer) { if (!m_blob || m_direction == dir_write) return false; if (!len || !buffer) return false; real_len = 0; USHORT olen = 0; USHORT ilen = len > SEGMENT_LIMIT ? SEGMENT_LIMIT : static_cast(len); char* buf2 = static_cast(buffer); if (!isc_get_segment(m_status, &m_blob, &olen, ilen, buf2) || m_status[1] == isc_segment) { real_len = olen; return true; } return false; } bool UserBlob::getData(size_t len, size_t& real_len, void* buffer, bool use_sep, const UCHAR separator) { if (!m_blob || m_direction == dir_write) return false; if (!len || !buffer) return false; bool rc = false; real_len = 0; char* buf2 = static_cast(buffer); while (len) { USHORT olen = 0; USHORT ilen = len > SEGMENT_LIMIT ? SEGMENT_LIMIT : static_cast(len); if (!isc_get_segment(m_status, &m_blob, &olen, ilen, buf2) || m_status[1] == isc_segment) { len -= olen; buf2 += olen; real_len += olen; if (len && use_sep) // Append the segment separator. { --len; *buf2++ = separator; ++real_len; } rc = true; } else break; } return rc; } bool UserBlob::putSegment(size_t len, const void* buffer) { if (!m_blob || m_direction == dir_read) return false; if (len > 0 && !buffer) return false; USHORT ilen = len > SEGMENT_LIMIT ? SEGMENT_LIMIT : static_cast(len); const char* buf2 = static_cast(buffer); return !isc_put_segment(m_status, &m_blob, ilen, buf2); } bool UserBlob::putSegment(size_t len, size_t& real_len, const void* buffer) { if (!m_blob || m_direction == dir_read) return false; if (len > 0 && !buffer) return false; real_len = 0; USHORT ilen = len > SEGMENT_LIMIT ? SEGMENT_LIMIT : static_cast(len); const char* buf2 = static_cast(buffer); if (isc_put_segment(m_status, &m_blob, ilen, buf2)) return false; real_len = ilen; return true; } bool UserBlob::putData(size_t len, size_t& real_len, const void* buffer) { if (!m_blob || m_direction == dir_read) return false; if (len > 0 && !buffer) return false; real_len = 0; const char* buf2 = static_cast(buffer); while (len) { USHORT ilen = len > SEGMENT_LIMIT ? SEGMENT_LIMIT : static_cast(len); if (isc_put_segment(m_status, &m_blob, ilen, buf2)) return false; len -= ilen; buf2 += ilen; real_len += ilen; } return true; } bool UserBlob::getInfo(size_t items_size, const UCHAR* blr_items, size_t info_size, UCHAR* blob_info) const { if (!m_blob || m_direction != dir_read) return false; // We have to cater for the API limitations. SSHORT in_len = items_size > MAX_SSHORT ? MAX_SSHORT : static_cast(items_size); SSHORT out_len = info_size > MAX_SSHORT ? MAX_SSHORT : static_cast(info_size); // That the API declares the second param as non const is a bug. FB_API_HANDLE blob = m_blob; return !isc_blob_info(m_status, &blob, in_len, reinterpret_cast(blr_items), out_len, reinterpret_cast(blob_info)); }