Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correct bit allocation and clean encoding #3

Merged
merged 1 commit into from
Sep 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,41 @@ const (
RestrictionTypeRequireLI RestrictionType = 2
RestrictionTypeUndefined RestrictionType = 3
)

const (
bitsBool = 1
bitsChar = 6
bitsTime = 36

bitsSegmentType = 3

bitsVersion = 6
bitsCreated = bitsTime
bitsLastUpdated = bitsTime
bitsCmpId = 12
bitsCmpVersion = 12
bitsConsentScreen = 6
bitsConsentLanguage = bitsChar * 2
bitsVendorListVersion = 12
bitsTcfPolicyVersion = 6
bitsIsServiceSpecific = bitsBool
bitsUseNonStandardTexts = bitsBool
bitsSpecialFeatureOptIns = 12
bitsPurposesConsent = 24
bitsPurposesLITransparency = 24
bitsPurposeOneTreatment = bitsBool
bitsPublisherCC = bitsChar * 2

bitsMaxVendorId = 16
bitsIsRangeEncoding = bitsBool
bitsNumEntries = 12
bitsVendorId = 16

bitsNumPubRestrictions = 12
bitsPubRestrictionsEntryPurposeId = 6
bitsPubRestrictionsEntryRestrictionType = 2

bitsPubPurposesConsent = 24
bitsPubPurposesLITransparency = 24
bitsNumCustomPurposes = 6
)
73 changes: 34 additions & 39 deletions decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func GetVersion(s string) (version TcfVersion, err error) {
}

var e = newTCEncoder(b)
return TcfVersion(e.readInt(6)), nil
return TcfVersion(e.readInt(bitsVersion)), nil
}

// Decodes a segment value and returns the SegmentType
Expand All @@ -51,7 +51,7 @@ func GetSegmentType(segment string) (segmentType SegmentType, err error) {
}

var e = newTCEncoder(b)
return SegmentType(e.readInt(3)), nil
return SegmentType(e.readInt(bitsSegmentType)), nil
}

// Decode a TC String and returns it as a TCData structure
Expand Down Expand Up @@ -138,43 +138,40 @@ func DecodeCoreString(coreString string) (c *CoreString, err error) {
var e = newTCEncoder(b)

c = &CoreString{}
c.Version = e.readInt(6)
c.Version = e.readInt(bitsVersion)
c.Created = e.readTime()
c.LastUpdated = e.readTime()
c.CmpId = e.readInt(12)
c.CmpVersion = e.readInt(12)
c.ConsentScreen = e.readInt(6)
c.ConsentLanguage = e.readIsoCode()
c.VendorListVersion = e.readInt(12)
c.TcfPolicyVersion = e.readInt(6)
c.CmpId = e.readInt(bitsCmpId)
c.CmpVersion = e.readInt(bitsCmpVersion)
c.ConsentScreen = e.readInt(bitsConsentScreen)
c.ConsentLanguage = e.readChars(bitsConsentLanguage)
c.VendorListVersion = e.readInt(bitsVendorListVersion)
c.TcfPolicyVersion = e.readInt(bitsTcfPolicyVersion)
c.IsServiceSpecific = e.readBool()
c.UseNonStandardStacks = e.readBool()
c.SpecialFeatureOptIns = e.readBitField(12)
c.PurposesConsent = e.readBitField(24)
c.PurposesLITransparency = e.readBitField(24)
c.SpecialFeatureOptIns = e.readBitField(bitsSpecialFeatureOptIns)
c.PurposesConsent = e.readBitField(bitsPurposesConsent)
c.PurposesLITransparency = e.readBitField(bitsPurposesLITransparency)
c.PurposeOneTreatment = e.readBool()
c.PublisherCC = e.readIsoCode()
c.PublisherCC = e.readChars(bitsPublisherCC)

c.MaxVendorId = e.readInt(16)
c.MaxVendorId = e.readInt(bitsMaxVendorId)
c.IsRangeEncoding = e.readBool()
if c.IsRangeEncoding {
c.NumEntries = e.readInt(12)
c.RangeEntries = e.readRangeEntries(uint(c.NumEntries))
c.NumEntries, c.RangeEntries = e.readRangeEntries()
} else {
c.VendorsConsent = e.readBitField(uint(c.MaxVendorId))
}

c.MaxVendorIdLI = e.readInt(16)
c.MaxVendorIdLI = e.readInt(bitsMaxVendorId)
c.IsRangeEncodingLI = e.readBool()
if c.IsRangeEncodingLI {
c.NumEntriesLI = e.readInt(12)
c.RangeEntriesLI = e.readRangeEntries(uint(c.NumEntriesLI))
c.NumEntriesLI, c.RangeEntriesLI = e.readRangeEntries()
} else {
c.VendorsLITransparency = e.readBitField(uint(c.MaxVendorIdLI))
}

c.NumPubRestrictions = e.readInt(12)
c.PubRestrictions = e.readPubRestrictions(uint(c.NumPubRestrictions))
c.NumPubRestrictions, c.PubRestrictions = e.readPubRestrictions()

return c, nil
}
Expand All @@ -195,18 +192,17 @@ func DecodeDisclosedVendors(disclosedVendors string) (d *DisclosedVendors, err e
var e = newTCEncoder(b)

d = &DisclosedVendors{}
d.SegmentType = e.readInt(3)
d.MaxVendorId = e.readInt(16)
d.SegmentType = e.readInt(bitsSegmentType)
d.MaxVendorId = e.readInt(bitsMaxVendorId)
d.IsRangeEncoding = e.readBool()
if d.IsRangeEncoding {
d.NumEntries = e.readInt(12)
d.RangeEntries = e.readRangeEntries(uint(d.NumEntries))
d.NumEntries, d.RangeEntries = e.readRangeEntries()
} else {
d.DisclosedVendors = e.readBitField(uint(d.MaxVendorId))
}

if d.SegmentType != 1 {
err = fmt.Errorf("disclosed vendors segment type must be 1")
if d.SegmentType != int(SegmentTypeDisclosedVendors) {
err = fmt.Errorf("disclosed vendors segment type must be %d", SegmentTypeDisclosedVendors)
return nil, err
}

Expand All @@ -229,18 +225,17 @@ func DecodeAllowedVendors(allowedVendors string) (a *AllowedVendors, err error)
var e = newTCEncoder(b)

a = &AllowedVendors{}
a.SegmentType = e.readInt(3)
a.MaxVendorId = e.readInt(16)
a.SegmentType = e.readInt(bitsSegmentType)
a.MaxVendorId = e.readInt(bitsMaxVendorId)
a.IsRangeEncoding = e.readBool()
if a.IsRangeEncoding {
a.NumEntries = e.readInt(12)
a.RangeEntries = e.readRangeEntries(uint(a.NumEntries))
a.NumEntries, a.RangeEntries = e.readRangeEntries()
} else {
a.AllowedVendors = e.readBitField(uint(a.MaxVendorId))
}

if a.SegmentType != 2 {
return nil, fmt.Errorf("allowed vendors segment type must be 2")
if a.SegmentType != int(SegmentTypeAllowedVendors) {
return nil, fmt.Errorf("allowed vendors segment type must be %d", SegmentTypeAllowedVendors)
}

return a, nil
Expand All @@ -262,15 +257,15 @@ func DecodePublisherTC(publisherTC string) (p *PublisherTC, err error) {
var e = newTCEncoder(b)

p = &PublisherTC{}
p.SegmentType = e.readInt(3)
p.PubPurposesConsent = e.readBitField(24)
p.PubPurposesLITransparency = e.readBitField(24)
p.NumCustomPurposes = e.readInt(6)
p.SegmentType = e.readInt(bitsSegmentType)
p.PubPurposesConsent = e.readBitField(bitsPubPurposesConsent)
p.PubPurposesLITransparency = e.readBitField(bitsPubPurposesLITransparency)
p.NumCustomPurposes = e.readInt(bitsNumCustomPurposes)
p.CustomPurposesConsent = e.readBitField(uint(p.NumCustomPurposes))
p.CustomPurposesLITransparency = e.readBitField(uint(p.NumCustomPurposes))

if p.SegmentType != 3 {
return nil, fmt.Errorf("allowed vendors segment type must be 3")
if p.SegmentType != int(SegmentTypePublisherTC) {
return nil, fmt.Errorf("publisher TC segment type must be %d", SegmentTypePublisherTC)
}

return p, nil
Expand Down
30 changes: 10 additions & 20 deletions segment_allowed_vendors.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,16 @@ func (a *AllowedVendors) IsVendorAllowed(id int) bool {

// Returns structure as a base64 raw url encoded string
func (a *AllowedVendors) Encode() string {
bitSize := 20
var bitSize int
bitSize += bitsSegmentType

bitSize += bitsMaxVendorId
bitSize += bitsIsRangeEncoding
if a.IsRangeEncoding {
bitSize += 12
entriesSize := len(a.RangeEntries)
bitSize += bitsNumEntries
for _, entry := range a.RangeEntries {
if entry.EndVendorID > entry.StartVendorID {
entriesSize += 16 * 2
} else {
entriesSize += 16
}
bitSize += entry.getBitSize()
}
bitSize += entriesSize
} else {
if a.MaxVendorId == 0 {
for id, _ := range a.AllowedVendors {
Expand All @@ -53,21 +50,14 @@ func (a *AllowedVendors) Encode() string {
bitSize += a.MaxVendorId
}

var e = newTCEncoder(make([]byte, bitSize/8))
if bitSize%8 != 0 {
e = newTCEncoder(make([]byte, bitSize/8+1))
}

e.writeInt(a.SegmentType, 3)
e.writeInt(a.MaxVendorId, 16)
e := newTCEncoderFromSize(bitSize)
e.writeInt(a.SegmentType, bitsSegmentType)
e.writeInt(a.MaxVendorId, bitsMaxVendorId)
e.writeBool(a.IsRangeEncoding)
if a.IsRangeEncoding {
e.writeInt(len(a.RangeEntries), 12)
e.writeRangeEntries(a.RangeEntries)
} else {
for i := 0; i < a.MaxVendorId; i++ {
e.writeBool(a.IsVendorAllowed(i + 1))
}
e.writeBools(a.IsVendorAllowed, a.MaxVendorId)
}

return base64.RawURLEncoding.EncodeToString(e.bytes)
Expand Down
Loading