broker/Data: Support unwrapping Broker::Data records

Calling val_to_data() on a Broker::Data ends up wrapping the
Broker::Data record instead of using the contained broker::value
directly.

Seems this should be the default behavior and wonder if the flag
even makes sense, but for a 8.0 backport that seems more reasonable.
This commit is contained in:
Arne Welzel 2025-08-15 21:28:18 +02:00
parent a3983cc939
commit 9e70d8b8ad
2 changed files with 24 additions and 7 deletions

View file

@ -12,6 +12,7 @@
#include "zeek/IntrusivePtr.h" #include "zeek/IntrusivePtr.h"
#include "zeek/RE.h" #include "zeek/RE.h"
#include "zeek/Scope.h" #include "zeek/Scope.h"
#include "zeek/Type.h"
#include "zeek/broker/data.bif.h" #include "zeek/broker/data.bif.h"
#include "zeek/module_util.h" #include "zeek/module_util.h"
@ -718,7 +719,7 @@ ValPtr data_to_val(broker::data& d, Type* type) {
return visit(val_converter{type}, d); return visit(val_converter{type}, d);
} }
std::optional<broker::data> val_to_data(const Val* v) { std::optional<broker::data> val_to_data(const Val* v, bool unwrap_broker_data) {
switch ( v->GetType()->Tag() ) { switch ( v->GetType()->Tag() ) {
case TYPE_BOOL: return {v->AsBool()}; case TYPE_BOOL: return {v->AsBool()};
case TYPE_INT: return {v->AsInt()}; case TYPE_INT: return {v->AsInt()};
@ -804,7 +805,7 @@ std::optional<broker::data> val_to_data(const Val* v) {
composite_key.reserve(vl->Length()); composite_key.reserve(vl->Length());
for ( auto k = 0; k < vl->Length(); ++k ) { for ( auto k = 0; k < vl->Length(); ++k ) {
auto key_part = val_to_data(vl->Idx(k).get()); auto key_part = val_to_data(vl->Idx(k).get(), unwrap_broker_data);
if ( ! key_part ) if ( ! key_part )
return std::nullopt; return std::nullopt;
@ -822,7 +823,7 @@ std::optional<broker::data> val_to_data(const Val* v) {
if ( is_set ) if ( is_set )
get<broker::set>(rval).emplace(std::move(key)); get<broker::set>(rval).emplace(std::move(key));
else { else {
auto val = val_to_data(te.value->GetVal().get()); auto val = val_to_data(te.value->GetVal().get(), unwrap_broker_data);
if ( ! val ) if ( ! val )
return std::nullopt; return std::nullopt;
@ -846,7 +847,7 @@ std::optional<broker::data> val_to_data(const Val* v) {
return std::nullopt; return std::nullopt;
} }
auto item = val_to_data(item_val.get()); auto item = val_to_data(item_val.get(), unwrap_broker_data);
if ( ! item ) if ( ! item )
return std::nullopt; return std::nullopt;
@ -871,7 +872,7 @@ std::optional<broker::data> val_to_data(const Val* v) {
return std::nullopt; return std::nullopt;
} }
auto item = val_to_data(item_val.get()); auto item = val_to_data(item_val.get(), unwrap_broker_data);
if ( ! item ) if ( ! item )
return std::nullopt; return std::nullopt;
@ -883,6 +884,21 @@ std::optional<broker::data> val_to_data(const Val* v) {
} }
case TYPE_RECORD: { case TYPE_RECORD: {
auto rec = v->AsRecordVal(); auto rec = v->AsRecordVal();
// If unwrap_broker_data is set and this record is a Broker::Data record,
// use the contained data field directly.
if ( unwrap_broker_data && rec->GetType() == BifType::Record::Broker::Data ) {
const auto ov = rec->GetField<zeek::OpaqueVal>(0);
// Sanity.
if ( ov->GetType() != opaque_of_data_type ) {
reporter->Error("Broker::Data data field has wrong type: %s",
obj_desc_short(ov->GetType()).c_str());
return std::nullopt;
}
return static_cast<const DataVal*>(ov.get())->data;
}
broker::vector rval; broker::vector rval;
size_t num_fields = v->GetType()->AsRecordType()->NumFields(); size_t num_fields = v->GetType()->AsRecordType()->NumFields();
rval.reserve(num_fields); rval.reserve(num_fields);
@ -895,7 +911,7 @@ std::optional<broker::data> val_to_data(const Val* v) {
continue; continue;
} }
auto item = val_to_data(item_val.get()); auto item = val_to_data(item_val.get(), unwrap_broker_data);
if ( ! item ) if ( ! item )
return std::nullopt; return std::nullopt;

View file

@ -76,9 +76,10 @@ EnumValPtr get_data_type(RecordVal* v, zeek::detail::Frame* frame);
/** /**
* Convert a Zeek value to a Broker data value. * Convert a Zeek value to a Broker data value.
* @param v a Zeek value. * @param v a Zeek value.
* @param unwrap_broker_data If v or any nested value is a Broker::Data record, use its data broker::value directly.
* @return a Broker data value if the Zeek value could be converted to one. * @return a Broker data value if the Zeek value could be converted to one.
*/ */
std::optional<broker::data> val_to_data(const Val* v); std::optional<broker::data> val_to_data(const Val* v, bool unwrap_broker_data = false);
/** /**
* Convert a Broker data value to a Zeek value. * Convert a Broker data value to a Zeek value.