Skip to content

Commit 3e70a3e

Browse files
chuffchad
andauthored
tcfca pub restrictions and disclosed vendors (#39)
* rename missed multistate usp* methods to us* * 3.1.1 * 3.1.2-SNAPSHOT * tcfca publisher restrictions and disclosed vendors * deprecate multi-state usp* methods * substring error handling * remove deprecated usp methods * Update README * tcfeu pub restrictions fix * pub restrictions getters * tcfeu pub restirctions fix * cleanup * pub restrictions fix --------- Co-authored-by: chad <[email protected]>
1 parent d51c324 commit 3e70a3e

File tree

68 files changed

+1347
-315
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+1347
-315
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,12 +161,15 @@ CmpList cmpList = loader.cmpList(cmpListContent);
161161
|tcfcav1|5|PurposesImpliedConsent|Boolean list of size 24|
162162
|tcfcav1|5|VendorExpressConsent|Integer list of variable size|
163163
|tcfcav1|5|VendorImpliedConsent|Integer list of variable size|
164+
|tcfcav1|5|PubRestrictions|RangeEntry list of variable size|
164165
|tcfcav1|5|PubPurposesSegmentType|3 bit int. Value is 3|
165166
|tcfcav1|5|PubPurposesExpressConsent|Boolean list of size 24|
166167
|tcfcav1|5|PubPurposesImpliedConsent|Boolean list of size 24|
167168
|tcfcav1|5|NumCustomPurposes|6 bit int|
168169
|tcfcav1|5|CustomPurposesExpressConsent|Boolean list where size is set by the NumCustomPurposes field|
169170
|tcfcav1|5|CustomPurposesImpliedConsent|Boolean list where size is set by the NumCustomPurposes field|
171+
|tcfcav1|5|DisclosedVendorsSegmentType|3 bit int. Value is 1|
172+
|tcfcav1|5|DisclosedVendors|Integer list of variable size|
170173
|uspv1|6|Version|6 bit int. Value is 1|
171174
|uspv1|6|Notice|2 bit int|
172175
|uspv1|6|OptOutSale|2 bit int|

iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java

Lines changed: 58 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package com.iab.gpp.encoder;
22

33
import java.util.ArrayList;
4+
import java.util.Arrays;
45
import java.util.HashMap;
56
import java.util.List;
67
import java.util.Map;
78
import java.util.stream.Collectors;
9+
import com.iab.gpp.encoder.error.DecodingException;
810
import com.iab.gpp.encoder.error.EncodingException;
911
import com.iab.gpp.encoder.error.InvalidFieldException;
12+
import com.iab.gpp.encoder.field.HeaderV1Field;
1013
import com.iab.gpp.encoder.section.EncodableSection;
1114
import com.iab.gpp.encoder.section.HeaderV1;
1215
import com.iab.gpp.encoder.section.Sections;
@@ -276,48 +279,64 @@ protected String encodeModel(Map<String, EncodableSection> sections) {
276279
}
277280

278281
protected Map<String, EncodableSection> decodeModel(String str) {
279-
Map<String, EncodableSection> sections = new HashMap<>();
280-
281-
if(str != null && !str.isEmpty()) {
282-
String[] encodedSections = str.split("~");
283-
HeaderV1 header = new HeaderV1(encodedSections[0]);
284-
sections.put(HeaderV1.NAME, header);
285-
286-
@SuppressWarnings("unchecked")
287-
List<Integer> sectionIds = (List<Integer>) header.getFieldValue("SectionIds");
288-
for (int i = 0; i < sectionIds.size(); i++) {
289-
if (sectionIds.get(i).equals(TcfEuV2.ID)) {
290-
TcfEuV2 section = new TcfEuV2(encodedSections[i + 1]);
291-
sections.put(TcfEuV2.NAME, section);
292-
} else if (sectionIds.get(i).equals(TcfCaV1.ID)) {
293-
TcfCaV1 section = new TcfCaV1(encodedSections[i + 1]);
294-
sections.put(TcfCaV1.NAME, section);
295-
} else if (sectionIds.get(i).equals(UspV1.ID)) {
296-
UspV1 section = new UspV1(encodedSections[i + 1]);
297-
sections.put(UspV1.NAME, section);
298-
} else if (sectionIds.get(i).equals(UsCaV1.ID)) {
299-
UsCaV1 section = new UsCaV1(encodedSections[i + 1]);
300-
sections.put(UsCaV1.NAME, section);
301-
} else if (sectionIds.get(i).equals(UsNatV1.ID)) {
302-
UsNatV1 section = new UsNatV1(encodedSections[i + 1]);
303-
sections.put(UsNatV1.NAME, section);
304-
} else if (sectionIds.get(i).equals(UsVaV1.ID)) {
305-
UsVaV1 section = new UsVaV1(encodedSections[i + 1]);
306-
sections.put(UsVaV1.NAME, section);
307-
} else if (sectionIds.get(i).equals(UsCoV1.ID)) {
308-
UsCoV1 section = new UsCoV1(encodedSections[i + 1]);
309-
sections.put(UsCoV1.NAME, section);
310-
} else if (sectionIds.get(i).equals(UsUtV1.ID)) {
311-
UsUtV1 section = new UsUtV1(encodedSections[i + 1]);
312-
sections.put(UsUtV1.NAME, section);
313-
} else if (sectionIds.get(i).equals(UsCtV1.ID)) {
314-
UsCtV1 section = new UsCtV1(encodedSections[i + 1]);
315-
sections.put(UsCtV1.NAME, section);
282+
if(str == null || str.isEmpty() || str.startsWith("D")) {
283+
Map<String, EncodableSection> sections = new HashMap<>();
284+
285+
if(str != null && !str.isEmpty()) {
286+
String[] encodedSections = str.split("~");
287+
HeaderV1 header = new HeaderV1(encodedSections[0]);
288+
sections.put(HeaderV1.NAME, header);
289+
290+
@SuppressWarnings("unchecked")
291+
List<Integer> sectionIds = (List<Integer>) header.getFieldValue("SectionIds");
292+
for (int i = 0; i < sectionIds.size(); i++) {
293+
if (sectionIds.get(i).equals(TcfEuV2.ID)) {
294+
TcfEuV2 section = new TcfEuV2(encodedSections[i + 1]);
295+
sections.put(TcfEuV2.NAME, section);
296+
} else if (sectionIds.get(i).equals(TcfCaV1.ID)) {
297+
TcfCaV1 section = new TcfCaV1(encodedSections[i + 1]);
298+
sections.put(TcfCaV1.NAME, section);
299+
} else if (sectionIds.get(i).equals(UspV1.ID)) {
300+
UspV1 section = new UspV1(encodedSections[i + 1]);
301+
sections.put(UspV1.NAME, section);
302+
} else if (sectionIds.get(i).equals(UsCaV1.ID)) {
303+
UsCaV1 section = new UsCaV1(encodedSections[i + 1]);
304+
sections.put(UsCaV1.NAME, section);
305+
} else if (sectionIds.get(i).equals(UsNatV1.ID)) {
306+
UsNatV1 section = new UsNatV1(encodedSections[i + 1]);
307+
sections.put(UsNatV1.NAME, section);
308+
} else if (sectionIds.get(i).equals(UsVaV1.ID)) {
309+
UsVaV1 section = new UsVaV1(encodedSections[i + 1]);
310+
sections.put(UsVaV1.NAME, section);
311+
} else if (sectionIds.get(i).equals(UsCoV1.ID)) {
312+
UsCoV1 section = new UsCoV1(encodedSections[i + 1]);
313+
sections.put(UsCoV1.NAME, section);
314+
} else if (sectionIds.get(i).equals(UsUtV1.ID)) {
315+
UsUtV1 section = new UsUtV1(encodedSections[i + 1]);
316+
sections.put(UsUtV1.NAME, section);
317+
} else if (sectionIds.get(i).equals(UsCtV1.ID)) {
318+
UsCtV1 section = new UsCtV1(encodedSections[i + 1]);
319+
sections.put(UsCtV1.NAME, section);
320+
}
316321
}
317322
}
323+
324+
return sections;
325+
} else if(str.startsWith("C")) {
326+
// old tcfeu only string
327+
Map<String, EncodableSection> sections = new HashMap<>();
328+
329+
TcfEuV2 section = new TcfEuV2(str);
330+
sections.put(TcfEuV2.NAME, section);
331+
332+
HeaderV1 header = new HeaderV1();
333+
header.setFieldValue(HeaderV1Field.SECTION_IDS, Arrays.asList(2));
334+
sections.put(HeaderV1.NAME, section);
335+
336+
return sections;
337+
} else {
338+
throw new DecodingException("Unable to decode '" + str + "'");
318339
}
319-
320-
return sections;
321340
}
322341

323342
public String encodeSection(int sectionId) {

iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringEncoder.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.List;
44
import com.iab.gpp.encoder.datatype.AbstractEncodableBitStringDataType;
5+
import com.iab.gpp.encoder.datatype.SubstringException;
56
import com.iab.gpp.encoder.error.DecodingException;
67
import com.iab.gpp.encoder.error.EncodingException;
78
import com.iab.gpp.encoder.field.EncodableBitStringFields;
@@ -39,9 +40,19 @@ public void decode(String bitString, List<String> fieldNames, EncodableBitString
3940
String fieldName = fieldNames.get(i);
4041
if (fields.containsKey(fieldName)) {
4142
AbstractEncodableBitStringDataType<?> field = fields.get(fieldName);
42-
String substring = field.substring(bitString, index);
43-
field.decode(substring);
44-
index += substring.length();
43+
try {
44+
String substring = field.substring(bitString, index);
45+
field.decode(substring);
46+
index += substring.length();
47+
} catch (SubstringException e) {
48+
if(field.getHardFailIfMissing()) {
49+
throw new DecodingException("Unable to decode " + fieldName, e);
50+
} else {
51+
return;
52+
}
53+
} catch (Exception e) {
54+
throw new DecodingException("Unable to decode " + fieldName, e);
55+
}
4556
} else {
4657
throw new DecodingException("Field not found: '" + fieldName + "'");
4758
}

iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/AbstractEncodableBitStringDataType.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
import com.iab.gpp.encoder.error.ValidationException;
77

88
public abstract class AbstractEncodableBitStringDataType<T> implements EncodableDataType<T> {
9-
protected Predicate<T> validator;
9+
//this if for backwards compatibility with the newer fields
10+
protected boolean hardFailIfMissing = true;
11+
protected Predicate<T> validator = null;
1012
protected T value;
1113

12-
protected AbstractEncodableBitStringDataType() {
13-
14+
protected AbstractEncodableBitStringDataType(boolean hardFailIfMissing) {
15+
this.hardFailIfMissing = hardFailIfMissing;
1416
}
1517

1618
public AbstractEncodableBitStringDataType<T> withValidator(Predicate<T> validator) {
@@ -42,5 +44,14 @@ public void setValue(Object value) {
4244

4345
}
4446

45-
public abstract String substring(String str, int fromIndex);
47+
public boolean getHardFailIfMissing() {
48+
return this.hardFailIfMissing;
49+
}
50+
51+
public abstract String encode();
52+
53+
public abstract void decode(String bitString);
54+
55+
public abstract String substring(String bitString, int fromIndex) throws SubstringException;
56+
4657
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package com.iab.gpp.encoder.datatype;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder;
6+
import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder;
7+
import com.iab.gpp.encoder.error.DecodingException;
8+
import com.iab.gpp.encoder.error.EncodingException;
9+
10+
public class EncodableArrayOfFixedIntegerRanges extends AbstractEncodableBitStringDataType<List<RangeEntry>> {
11+
12+
private int keyBitStringLength;
13+
private int typeBitStringLength;
14+
15+
protected EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength) {
16+
super(true);
17+
this.keyBitStringLength = keyBitStringLength;
18+
this.typeBitStringLength = typeBitStringLength;
19+
}
20+
21+
public EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength, List<RangeEntry> value) {
22+
super(true);
23+
this.keyBitStringLength = keyBitStringLength;
24+
this.typeBitStringLength = typeBitStringLength;
25+
setValue(value);
26+
}
27+
28+
public EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength, List<RangeEntry> value, boolean hardFailIfMissing) {
29+
super(hardFailIfMissing);
30+
this.keyBitStringLength = keyBitStringLength;
31+
this.typeBitStringLength = typeBitStringLength;
32+
setValue(value);
33+
}
34+
35+
@Override
36+
public String encode() {
37+
try {
38+
List<RangeEntry> entries = this.value;
39+
40+
StringBuilder sb = new StringBuilder();
41+
sb.append(FixedIntegerEncoder.encode(entries.size(), 12));
42+
for (RangeEntry entry : entries) {
43+
sb.append(FixedIntegerEncoder.encode(entry.getKey(), keyBitStringLength))
44+
.append(FixedIntegerEncoder.encode(entry.getType(), typeBitStringLength))
45+
.append(FixedIntegerRangeEncoder.encode(entry.getIds()));
46+
}
47+
48+
return sb.toString();
49+
} catch (Exception e) {
50+
throw new EncodingException(e);
51+
}
52+
}
53+
54+
@Override
55+
public void decode(String bitString) {
56+
try {
57+
List<RangeEntry> entries = new ArrayList<>();
58+
59+
int size = FixedIntegerEncoder.decode(bitString.substring(0, 12));
60+
int index = 12;
61+
for (int i = 0; i < size; i++) {
62+
int key = FixedIntegerEncoder.decode(bitString.substring(index, index + keyBitStringLength));
63+
index += keyBitStringLength;
64+
65+
int type = FixedIntegerEncoder.decode(bitString.substring(index, index + typeBitStringLength));
66+
index += typeBitStringLength;
67+
68+
String substring = new EncodableFixedIntegerRange().substring(bitString, index);
69+
List<Integer> ids = FixedIntegerRangeEncoder.decode(substring);
70+
index += substring.length();
71+
72+
entries.add(new RangeEntry(key, type, ids));
73+
}
74+
75+
this.value = entries;
76+
} catch (Exception e) {
77+
throw new DecodingException(e);
78+
}
79+
}
80+
81+
@Override
82+
public String substring(String bitString, int fromIndex) throws SubstringException {
83+
try {
84+
StringBuilder sb = new StringBuilder();
85+
sb.append(bitString.substring(fromIndex, fromIndex + 12));
86+
87+
int size = FixedIntegerEncoder.decode(sb.toString());
88+
89+
int index = fromIndex + sb.length();
90+
for (int i = 0; i < size; i++) {
91+
String keySubstring = bitString.substring(index, index + keyBitStringLength);
92+
index += keySubstring.length();
93+
sb.append(keySubstring);
94+
95+
String typeSubstring = bitString.substring(index, index + typeBitStringLength);
96+
index += typeSubstring.length();
97+
sb.append(typeSubstring);
98+
99+
String rangeSubstring = new EncodableFixedIntegerRange().substring(bitString, index);
100+
index += rangeSubstring.length();
101+
sb.append(rangeSubstring);
102+
}
103+
104+
return sb.toString();
105+
} catch (Exception e) {
106+
throw new SubstringException(e);
107+
}
108+
}
109+
110+
}
Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,46 @@
11
package com.iab.gpp.encoder.datatype;
22

33
import com.iab.gpp.encoder.datatype.encoder.BooleanEncoder;
4+
import com.iab.gpp.encoder.error.DecodingException;
5+
import com.iab.gpp.encoder.error.EncodingException;
46

57
public class EncodableBoolean extends AbstractEncodableBitStringDataType<Boolean> {
68

79
protected EncodableBoolean() {
8-
super();
10+
super(true);
911
}
1012

1113
public EncodableBoolean(Boolean value) {
12-
super();
14+
super(true);
15+
setValue(value);
16+
}
17+
18+
public EncodableBoolean(Boolean value, boolean hardFailIfMissing) {
19+
super(hardFailIfMissing);
1320
setValue(value);
1421
}
1522

1623
public String encode() {
17-
return BooleanEncoder.encode(this.value);
24+
try {
25+
return BooleanEncoder.encode(this.value);
26+
} catch (Exception e) {
27+
throw new EncodingException(e);
28+
}
1829
}
1930

2031
public void decode(String bitString) {
21-
this.value = BooleanEncoder.decode(bitString);
32+
try {
33+
this.value = BooleanEncoder.decode(bitString);
34+
} catch (Exception e) {
35+
throw new DecodingException(e);
36+
}
2237
}
2338

24-
public String substring(String bitString, int fromIndex) {
25-
return bitString.substring(fromIndex, fromIndex + 1);
39+
public String substring(String bitString, int fromIndex) throws SubstringException {
40+
try {
41+
return bitString.substring(fromIndex, fromIndex + 1);
42+
} catch (Exception e) {
43+
throw new SubstringException(e);
44+
}
2645
}
2746
}

0 commit comments

Comments
 (0)