| 753 | |
| 754 | private: |
| 755 | Status DecodeArrowDense(int num_values, int null_count, const uint8_t* valid_bits, |
| 756 | int64_t valid_bits_offset, |
| 757 | typename EncodingTraits<ByteArrayType>::Accumulator* out, |
| 758 | int* out_values_decoded) { |
| 759 | // We're going to decode `num_values - null_count` PLAIN values, |
| 760 | // and each value has a 4-byte length header that doesn't count for the |
| 761 | // Arrow binary data length. |
| 762 | int64_t estimated_data_length = |
| 763 | len_ - 4 * static_cast<int64_t>(num_values - null_count); |
| 764 | if (ARROW_PREDICT_FALSE(estimated_data_length < 0)) { |
| 765 | return Status::Invalid("Invalid or truncated PLAIN-encoded BYTE_ARRAY data"); |
| 766 | } |
| 767 | |
| 768 | auto visit_binary_helper = [&](auto* helper) { |
| 769 | int values_decoded = 0; |
| 770 | |
| 771 | auto visit_run = [&](int64_t position, int64_t run_length, bool is_valid) { |
| 772 | if (is_valid) { |
| 773 | for (int64_t i = 0; i < run_length; ++i) { |
| 774 | // We ensure `len_` is sufficient thanks to: |
| 775 | // 1. the initial `estimated_data_length` check above, |
| 776 | // 2. the running `value_len > estimated_data_length` check below. |
| 777 | // This precondition follows from those two checks. |
| 778 | DCHECK_GE(len_, 4); |
| 779 | auto value_len = SafeLoadAs<int32_t>(data_); |
| 780 | // This check also ensures that `value_len <= len_ - 4` due to the way |
| 781 | // `estimated_data_length` is computed. |
| 782 | if (ARROW_PREDICT_FALSE(value_len < 0 || value_len > estimated_data_length)) { |
| 783 | return Status::Invalid( |
| 784 | "Invalid or truncated PLAIN-encoded BYTE_ARRAY data"); |
| 785 | } |
| 786 | RETURN_NOT_OK( |
| 787 | helper->AppendValue(data_ + 4, value_len, estimated_data_length)); |
| 788 | auto increment = value_len + 4; |
| 789 | data_ += increment; |
| 790 | len_ -= increment; |
| 791 | estimated_data_length -= value_len; |
| 792 | DCHECK_GE(estimated_data_length, 0); |
| 793 | } |
| 794 | values_decoded += static_cast<int>(run_length); |
| 795 | DCHECK_LE(values_decoded, num_values); |
| 796 | return Status::OK(); |
| 797 | } else { |
| 798 | return helper->AppendNulls(run_length); |
| 799 | } |
| 800 | }; |
| 801 | |
| 802 | RETURN_NOT_OK( |
| 803 | VisitBitRuns(valid_bits, valid_bits_offset, num_values, std::move(visit_run))); |
| 804 | |
| 805 | num_values_ -= values_decoded; |
| 806 | *out_values_decoded = values_decoded; |
| 807 | return Status::OK(); |
| 808 | }; |
| 809 | |
| 810 | return DispatchArrowBinaryHelper<ByteArrayType>( |
| 811 | out, num_values, estimated_data_length, visit_binary_helper); |
| 812 | } |
nothing calls this directly
no test coverage detected