diff --git a/src/fb-cpp/Blob.cpp b/src/fb-cpp/Blob.cpp index 0f272f6..7a11fa3 100644 --- a/src/fb-cpp/Blob.cpp +++ b/src/fb-cpp/Blob.cpp @@ -66,37 +66,42 @@ Blob::Blob(Attachment& attachment, Transaction& transaction, const BlobId& blobI std::vector Blob::prepareBpb(const BlobOptions& options) { - const auto util = attachment.getClient().getUtil(); + // IXpbBuilder::BPB only exists since Firebird 4, so the BPB is built by hand to work with Firebird 3 clients. - auto builder = fbUnique(util->getXpbBuilder(&statusWrapper, fb::IXpbBuilder::BPB, - reinterpret_cast(options.getBpb().data()), - static_cast(options.getBpb().size()))); + const auto& userBpb = options.getBpb(); + std::vector bpb(userBpb.begin(), userBpb.end()); + + const auto addInt = [&](std::uint8_t tag, int value) + { + if (bpb.empty()) + bpb.push_back(isc_bpb_version1); + + const auto unsignedValue = static_cast(value); + + bpb.push_back(tag); + bpb.push_back(4u); + + for (unsigned shift = 0u; shift < 32u; shift += 8u) + bpb.push_back(static_cast((unsignedValue >> shift) & 0xFFu)); + }; if (const auto type = options.getType(); type.has_value()) - builder->insertInt(&statusWrapper, isc_bpb_type, static_cast(type.value())); + addInt(isc_bpb_type, static_cast(type.value())); if (const auto sourceType = options.getSourceType(); sourceType.has_value()) - builder->insertInt(&statusWrapper, isc_bpb_source_type, static_cast(sourceType.value())); + addInt(isc_bpb_source_type, static_cast(sourceType.value())); if (const auto targetType = options.getTargetType(); targetType.has_value()) - builder->insertInt(&statusWrapper, isc_bpb_target_type, static_cast(targetType.value())); + addInt(isc_bpb_target_type, static_cast(targetType.value())); if (const auto sourceCharSet = options.getSourceCharSet(); sourceCharSet.has_value()) - builder->insertInt(&statusWrapper, isc_bpb_source_interp, static_cast(sourceCharSet.value())); + addInt(isc_bpb_source_interp, static_cast(sourceCharSet.value())); if (const auto targetCharSet = options.getTargetCharSet(); targetCharSet.has_value()) - builder->insertInt(&statusWrapper, isc_bpb_target_interp, static_cast(targetCharSet.value())); + addInt(isc_bpb_target_interp, static_cast(targetCharSet.value())); if (const auto storage = options.getStorage(); storage.has_value()) - builder->insertInt(&statusWrapper, isc_bpb_storage, static_cast(storage.value())); - - const auto buffer = builder->getBuffer(&statusWrapper); - const auto length = builder->getBufferLength(&statusWrapper); - - std::vector bpb(length); - - if (length != 0) - std::memcpy(bpb.data(), buffer, length); + addInt(isc_bpb_storage, static_cast(storage.value())); return bpb; }