Skip to content

Commit

Permalink
improve bitutils to also return next offset in array context via want…
Browse files Browse the repository at this point in the history
…array
  • Loading branch information
peczenyj committed Dec 11, 2023
1 parent 0f44544 commit 3d0ce8e
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 41 deletions.
53 changes: 31 additions & 22 deletions lib/GDPR/IAB/TCFv2.pm
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ sub tc_string {
sub version {
my $self = shift;

return get_uint6( $self->{data}, VERSION_OFFSET );
return scalar( get_uint6( $self->{data}, VERSION_OFFSET ) );
}

sub created {
Expand All @@ -171,7 +171,7 @@ sub last_updated {
sub _get_epoch {
my ( $self, $offset ) = @_;

my $deciseconds = get_uint36( $self->{data}, $offset );
my $deciseconds = scalar( get_uint36( $self->{data}, $offset ) );

return (
( $deciseconds / 10 ),
Expand All @@ -182,49 +182,49 @@ sub _get_epoch {
sub cmp_id {
my $self = shift;

return get_uint12( $self->{data}, CMP_ID_OFFSET );
return scalar( get_uint12( $self->{data}, CMP_ID_OFFSET ) );
}

sub cmp_version {
my $self = shift;

return get_uint12( $self->{data}, CMP_VERSION_OFFSET );
return scalar( get_uint12( $self->{data}, CMP_VERSION_OFFSET ) );
}

sub consent_screen {
my $self = shift;

return get_uint6( $self->{data}, CONSENT_SCREEN_OFFSET );
return scalar( get_uint6( $self->{data}, CONSENT_SCREEN_OFFSET ) );
}

sub consent_language {
my $self = shift;

return get_char6_pair( $self->{data}, CONSENT_LANGUAGE_OFFSET );
return scalar( get_char6_pair( $self->{data}, CONSENT_LANGUAGE_OFFSET ) );
}

sub vendor_list_version {
my $self = shift;

return get_uint12( $self->{data}, VENDOR_LIST_VERSION_OFFSET );
return scalar( get_uint12( $self->{data}, VENDOR_LIST_VERSION_OFFSET ) );
}

sub policy_version {
my $self = shift;

return get_uint6( $self->{data}, POLICY_VERSION_OFFSET );
return scalar( get_uint6( $self->{data}, POLICY_VERSION_OFFSET ) );
}

sub is_service_specific {
my $self = shift;

return is_set( $self->{data}, SERVICE_SPECIFIC_OFFSET );
return scalar( is_set( $self->{data}, SERVICE_SPECIFIC_OFFSET ) );
}

sub use_non_standard_stacks {
my $self = shift;

return is_set( $self->{data}, USE_NON_STANDARD_STACKS_OFFSET );
return scalar( is_set( $self->{data}, USE_NON_STANDARD_STACKS_OFFSET ) );
}

sub is_special_feature_opt_in {
Expand All @@ -233,7 +233,9 @@ sub is_special_feature_opt_in {
croak "invalid special feature id $id: must be between 1 and 12"
if $id < 1 || $id > 12;

return is_set( $self->{data}, SPECIAL_FEATURE_OPT_IN_OFFSET + $id - 1 );
return
scalar(
is_set( $self->{data}, SPECIAL_FEATURE_OPT_IN_OFFSET + $id - 1 ) );
}

sub is_purpose_consent_allowed {
Expand All @@ -242,7 +244,9 @@ sub is_purpose_consent_allowed {
croak "invalid purpose id $id: must be between 1 and 24"
if $id < 1 || $id > 24;

return is_set( $self->{data}, PURPOSE_CONSENT_ALLOWED_OFFSET + $id - 1 );
return
scalar(
is_set( $self->{data}, PURPOSE_CONSENT_ALLOWED_OFFSET + $id - 1 ) );
}

sub is_purpose_legitimate_interest_allowed {
Expand All @@ -251,25 +255,27 @@ sub is_purpose_legitimate_interest_allowed {
croak "invalid purpose id $id: must be between 1 and 24"
if $id < 1 || $id > 24;

return is_set( $self->{data}, PURPOSE_LIT_ALLOWED_OFFSET + $id - 1 );
return
scalar( is_set( $self->{data}, PURPOSE_LIT_ALLOWED_OFFSET + $id - 1 ) );
}

sub purpose_one_treatment {
my $self = shift;

return is_set( $self->{data}, PURPOSE_ONE_TREATMENT_OFFSET );
return scalar( is_set( $self->{data}, PURPOSE_ONE_TREATMENT_OFFSET ) );
}

sub publisher_country_code {
my $self = shift;

return get_char6_pair( $self->{data}, PUBLISHER_COUNTRY_CODE_OFFSET );
return
scalar( get_char6_pair( $self->{data}, PUBLISHER_COUNTRY_CODE_OFFSET ) );
}

sub max_vendor_id_consent {
my $self = shift;

return get_uint16( $self->{data}, MAX_VENDOR_ID_CONSENT_OFFSET );
return scalar( get_uint16( $self->{data}, MAX_VENDOR_ID_CONSENT_OFFSET ) );
}

sub max_vendor_id_legitimate_interest {
Expand Down Expand Up @@ -420,7 +426,7 @@ sub _parse_vendor_legitimate_interests {
my ( $self, $legitimate_interest_start ) = @_;

my $legitimate_interest_max_vendor =
get_uint16( $self->{data}, $legitimate_interest_start );
scalar( get_uint16( $self->{data}, $legitimate_interest_start ) );

$self->{legitimate_interest_max_vendor} = $legitimate_interest_max_vendor;

Expand All @@ -430,7 +436,7 @@ sub _parse_vendor_legitimate_interests {
if $legitimate_interest_start + 16 > $data_size;

my $is_vendor_legitimate_interest_range =
is_set( $self->{data}, $legitimate_interest_start + 16 );
scalar( is_set( $self->{data}, $legitimate_interest_start + 16 ) );

my ( $vendor_legitimate_interests, $pub_restrict_start );

Expand All @@ -457,16 +463,18 @@ sub _parse_vendor_legitimate_interests {
sub _parse_publisher_restrictions {
my ( $self, $pub_restrict_start ) = @_;

my $num_restrictions = get_uint12( $self->{data}, $pub_restrict_start );
my $num_restrictions =
scalar( get_uint12( $self->{data}, $pub_restrict_start ) );

my %restrictions;

my $current_offset = $pub_restrict_start + 12;

for ( 1 .. $num_restrictions ) {
my $purpose_id = get_uint6( $self->{data}, $current_offset );
my $purpose_id = scalar( get_uint6( $self->{data}, $current_offset ) );
$current_offset += 6;
my $restriction_type = get_uint2( $self->{data}, $current_offset );
my $restriction_type =
scalar( get_uint2( $self->{data}, $current_offset ) );
$current_offset += 2;

my ( $vendor_restrictions, $next_offset ) =
Expand Down Expand Up @@ -529,7 +537,8 @@ sub _decode_base64url {
sub _is_vendor_consent_range_encoding {
my $self = shift;

return is_set( $self->{data}, VENDOR_CONSENT_RANGE_ENCODING_OFFSET );
return
scalar( is_set( $self->{data}, VENDOR_CONSENT_RANGE_ENCODING_OFFSET ) );
}

sub _parse_range_section {
Expand Down
83 changes: 64 additions & 19 deletions lib/GDPR/IAB/TCFv2/BitUtils.pm
Original file line number Diff line number Diff line change
Expand Up @@ -34,34 +34,53 @@ sub is_set {

croak "index our of bounds on offset $offset" if $offset >= length($data);

return substr( $data, $offset, 1 ) == 1;
my $r = substr( $data, $offset, 1 ) == 1;

return wantarray ? ( $r, $offset + 1 ) : $r;
}

sub get_uint2 {
my ( $data, $offset ) = @_;

return unpack(
my ( $bits_with_pading, $next_offset ) =
_get_bits_with_padding( $data, 8, $offset, 2 );

my $r = unpack(
"C",
_get_bits_with_padding( $data, 8, $offset, 2 )
$bits_with_pading
);

return wantarray ? ( $r, $next_offset ) : $r;
}

sub get_uint6 {
my ( $data, $offset ) = @_;

return unpack(
my ( $bits_with_pading, $next_offset ) =
_get_bits_with_padding( $data, 8, $offset, 6 );

my $r = unpack(
"C",
_get_bits_with_padding( $data, 8, $offset, 6 )
$bits_with_pading
);

return wantarray ? ( $r, $next_offset ) : $r;
}

sub get_char6_pair {
my ( $data, $offset ) = @_;

my $first_letter = chr( ASCII_OFFSET + get_uint6( $data, $offset ) );
my $second_letter = chr( ASCII_OFFSET + get_uint6( $data, $offset + 6 ) );
my $pair;

return $first_letter . $second_letter;
for ( 1 .. 2 ) {
my ( $byte, $next_offset ) = get_uint6( $data, $offset );

$pair .= chr( ASCII_OFFSET + $byte );

$offset = $next_offset;
}

return wantarray ? ( $pair, $offset ) : $pair;
}

sub get_uint12 {
Expand All @@ -79,38 +98,64 @@ sub get_uint16 {
sub _get_big_endian_short_16bits {
my ( $data, $offset, $nbits ) = @_;

return unpack(
"S>",
_get_bits_with_padding( $data, 16, $offset, $nbits )
) if $CAN_FORCE_BIG_ENDIAN;
if ($CAN_FORCE_BIG_ENDIAN) {
my ( $bits_with_pading, $next_offset ) =
_get_bits_with_padding( $data, 16, $offset, $nbits );

my $r = unpack( "S>", $bits_with_pading );

return wantarray ? ( $r, $next_offset ) : $r;
}

return Math::BigInt->new(
"0b" . _add_padding( $data, 16, $offset, $nbits ) );
my ( $data_with_padding, $next_offset ) =
_add_padding( $data, 16, $offset, $nbits );

my $r = Math::BigInt->new( "0b" . $data_with_padding );

return wantarray ? ( $r, $next_offset ) : $r;
}

sub get_uint36 {
my ( $data, $offset ) = @_;

return unpack( "Q>", _get_bits_with_padding( $data, 64, $offset, 36 ) )
if $CAN_PACK_QUADS;
if ($CAN_PACK_QUADS) {
my ( $bits_with_pading, $next_offset ) =
_get_bits_with_padding( $data, 64, $offset, 36 );

my $r = unpack( "Q>", $bits_with_pading );

return wantarray ? ( $r, $next_offset ) : $r;
}

my ( $data_with_padding, $next_offset ) =
_add_padding( $data, 64, $offset, 36 );

return Math::BigInt->new( "0b" . _add_padding( $data, 64, $offset, 36 ) );
my $r = Math::BigInt->new( "0b" . $data_with_padding );

return wantarray ? ( $r, $next_offset ) : $r;
}

sub _get_bits_with_padding {
my ( $data, $bits, $offset, $nbits ) = @_;

# TODO check if offset is in range of $data ?

return pack( "B${bits}", _add_padding( $data, $bits, $offset, $nbits ) );
my ( $data_with_padding, $next_offset ) =
_add_padding( $data, $bits, $offset, $nbits );

my $r = pack( "B${bits}", $data_with_padding );

return wantarray ? ( $r, $next_offset ) : $r;
}

sub _add_padding {
my ( $data, $bits, $offset, $nbits ) = @_;

my $padding = "0" x ( $bits - $nbits );

return $padding . substr( $data, $offset, $nbits );
my $r = $padding . substr( $data, $offset, $nbits );

return wantarray ? ( $r, $offset + $nbits ) : $r;
}

1;
Expand Down

0 comments on commit 3d0ce8e

Please sign in to comment.