Skip to content

Commit

Permalink
Correct bit allocation and clean encoding (#3)
Browse files Browse the repository at this point in the history
  • Loading branch information
tla-sirdata authored Sep 12, 2023
1 parent edda30b commit c1322a7
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 191 deletions.
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

0 comments on commit c1322a7

Please sign in to comment.