diff --git a/iabgpp-encoder/pom.xml b/iabgpp-encoder/pom.xml
index 03e794e5..07caf281 100644
--- a/iabgpp-encoder/pom.xml
+++ b/iabgpp-encoder/pom.xml
@@ -7,7 +7,7 @@
com.iabgpp
iabgpp-core
- 3.2.5-SNAPSHOT
+ 4.0.0-RC1
iabgpp-encoder
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java
index b4f8cba3..8c8bb223 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/GppModel.java
@@ -5,7 +5,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
+import java.util.PrimitiveIterator;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
import com.iab.gpp.encoder.error.InvalidFieldException;
@@ -13,6 +13,7 @@
import com.iab.gpp.encoder.section.EncodableSection;
import com.iab.gpp.encoder.section.HeaderV1;
import com.iab.gpp.encoder.section.Sections;
+import com.iab.gpp.encoder.section.SlicedCharSequence;
import com.iab.gpp.encoder.section.TcfCaV1;
import com.iab.gpp.encoder.section.TcfEuV2;
import com.iab.gpp.encoder.section.UsCa;
@@ -53,77 +54,82 @@ public void setFieldValue(int sectionId, String fieldName, Object value) {
setFieldValue(Sections.SECTION_ID_NAME_MAP.get(sectionId), fieldName, value);
}
+ private EncodableSection getOrCreateSection(String sectionName) {
+ EncodableSection section = this.sections.get(sectionName);
+ if (section == null) {
+ switch(sectionName) {
+ case TcfEuV2.NAME:
+ section = new TcfEuV2();
+ break;
+ case TcfCaV1.NAME:
+ section = new TcfCaV1();
+ break;
+ case UspV1.NAME:
+ section = new UspV1();
+ break;
+ case UsNat.NAME:
+ section = new UsNat();
+ break;
+ case UsCa.NAME:
+ section = new UsCa();
+ break;
+ case UsVa.NAME:
+ section = new UsVa();
+ break;
+ case UsCo.NAME:
+ section = new UsCo();
+ break;
+ case UsUt.NAME:
+ section = new UsUt();
+ break;
+ case UsCt.NAME:
+ section = new UsCt();
+ break;
+ case UsFl.NAME:
+ section = new UsFl();
+ break;
+ case UsMt.NAME:
+ section = new UsMt();
+ break;
+ case UsOr.NAME:
+ section = new UsOr();
+ break;
+ case UsTx.NAME:
+ section = new UsTx();
+ break;
+ case UsDe.NAME:
+ section = new UsDe();
+ break;
+ case UsIa.NAME:
+ section = new UsIa();
+ break;
+ case UsNe.NAME:
+ section = new UsNe();
+ break;
+ case UsNh.NAME:
+ section = new UsNh();
+ break;
+ case UsNj.NAME:
+ section = new UsNj();
+ break;
+ case UsTn.NAME:
+ section = new UsTn();
+ break;
+ }
+ if (section != null) {
+ this.sections.put(sectionName, section);
+ }
+ }
+ return section;
+ }
+
public void setFieldValue(String sectionName, String fieldName, Object value) {
if (!this.decoded) {
this.sections = this.decodeModel(this.encodedString);
this.dirty = false;
this.decoded = true;
}
-
- EncodableSection section = null;
- if (!this.sections.containsKey(sectionName)) {
- if (sectionName.equals(TcfCaV1.NAME)) {
- section = new TcfCaV1();
- this.sections.put(TcfCaV1.NAME, section);
- } else if (sectionName.equals(TcfEuV2.NAME)) {
- section = new TcfEuV2();
- this.sections.put(TcfEuV2.NAME, section);
- } else if (sectionName.equals(UspV1.NAME)) {
- section = new UspV1();
- this.sections.put(UspV1.NAME, section);
- } else if (sectionName.equals(UsNat.NAME)) {
- section = new UsNat();
- this.sections.put(UsNat.NAME, section);
- } else if (sectionName.equals(UsCa.NAME)) {
- section = new UsCa();
- this.sections.put(UsCa.NAME, section);
- } else if (sectionName.equals(UsVa.NAME)) {
- section = new UsVa();
- this.sections.put(UsVa.NAME, section);
- } else if (sectionName.equals(UsCo.NAME)) {
- section = new UsCo();
- this.sections.put(UsCo.NAME, section);
- } else if (sectionName.equals(UsUt.NAME)) {
- section = new UsUt();
- this.sections.put(UsUt.NAME, section);
- } else if (sectionName.equals(UsCt.NAME)) {
- section = new UsCt();
- this.sections.put(UsCt.NAME, section);
- } else if (sectionName.equals(UsFl.NAME)) {
- section = new UsFl();
- this.sections.put(UsFl.NAME, section);
- } else if (sectionName.equals(UsMt.NAME)) {
- section = new UsMt();
- this.sections.put(UsMt.NAME, section);
- } else if (sectionName.equals(UsOr.NAME)) {
- section = new UsOr();
- this.sections.put(UsOr.NAME, section);
- } else if (sectionName.equals(UsTx.NAME)) {
- section = new UsTx();
- this.sections.put(UsTx.NAME, section);
- } else if (sectionName.equals(UsDe.NAME)) {
- section = new UsDe();
- this.sections.put(UsDe.NAME, section);
- } else if (sectionName.equals(UsIa.NAME)) {
- section = new UsIa();
- this.sections.put(UsIa.NAME, section);
- } else if (sectionName.equals(UsNe.NAME)) {
- section = new UsNe();
- this.sections.put(UsNe.NAME, section);
- } else if (sectionName.equals(UsNh.NAME)) {
- section = new UsNh();
- this.sections.put(UsNh.NAME, section);
- } else if (sectionName.equals(UsNj.NAME)) {
- section = new UsNj();
- this.sections.put(UsNj.NAME, section);
- } else if (sectionName.equals(UsTn.NAME)) {
- section = new UsTn();
- this.sections.put(UsTn.NAME, section);
- }
- } else {
- section = this.sections.get(sectionName);
- }
-
+ EncodableSection section = getOrCreateSection(sectionName);
if (section != null) {
section.setFieldValue(fieldName, value);
this.dirty = true;
@@ -142,9 +148,9 @@ public Object getFieldValue(String sectionName, String fieldName) {
this.dirty = false;
this.decoded = true;
}
-
- if (this.sections.containsKey(sectionName)) {
- return this.sections.get(sectionName).getFieldValue(fieldName);
+ EncodableSection field = this.sections.get(sectionName);
+ if (field != null) {
+ return field.getFieldValue(fieldName);
} else {
return null;
}
@@ -160,9 +166,9 @@ public boolean hasField(String sectionName, String fieldName) {
this.dirty = false;
this.decoded = true;
}
-
- if (this.sections.containsKey(sectionName)) {
- return this.sections.get(sectionName).hasField(fieldName);
+ EncodableSection field = this.sections.get(sectionName);
+ if (field != null) {
+ return field.hasField(fieldName);
} else {
return false;
}
@@ -208,12 +214,7 @@ public EncodableSection getSection(String sectionName) {
this.dirty = false;
this.decoded = true;
}
-
- if (this.sections.containsKey(sectionName)) {
- return this.sections.get(sectionName);
- } else {
- return null;
- }
+ return this.sections.get(sectionName);
}
public void deleteSection(int sectionId) {
@@ -226,9 +227,7 @@ public void deleteSection(String sectionName) {
this.dirty = false;
this.decoded = true;
}
-
- if (this.sections.containsKey(sectionName)) {
- this.sections.remove(sectionName);
+ if (this.sections.remove(sectionName) != null) {
this.dirty = true;
}
}
@@ -322,12 +321,12 @@ public List getSectionIds() {
this.dirty = false;
this.decoded = true;
}
-
- List sectionIds = new ArrayList<>();
- for (int i = 0; i < Sections.SECTION_ORDER.size(); i++) {
+ int length = Sections.SECTION_ORDER.size();
+ List sectionIds = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
String sectionName = Sections.SECTION_ORDER.get(i);
- if (this.sections.containsKey(sectionName)) {
- EncodableSection section = this.sections.get(sectionName);
+ EncodableSection section = this.sections.get(sectionName);
+ if (section != null) {
sectionIds.add(section.getId());
}
}
@@ -335,13 +334,14 @@ public List getSectionIds() {
}
protected String encodeModel(Map sections) {
- List encodedSections = new ArrayList<>();
- List sectionIds = new ArrayList<>();
- for (int i = 0; i < Sections.SECTION_ORDER.size(); i++) {
+ int length = Sections.SECTION_ORDER.size();
+ List encodedSections = new ArrayList<>(length);
+ List sectionIds = new ArrayList<>(length);
+ for (int i = 0; i < length; i++) {
String sectionName = Sections.SECTION_ORDER.get(i);
- if (sections.containsKey(sectionName)) {
- EncodableSection section = sections.get(sectionName);
- encodedSections.add(section.encode());
+ EncodableSection section = sections.get(sectionName);
+ if (section != null) {
+ encodedSections.add(section.encodeCharSequence());
sectionIds.add(section.getId());
}
}
@@ -352,81 +352,81 @@ protected String encodeModel(Map sections) {
} catch (InvalidFieldException e) {
throw new EncodingException(e);
}
- encodedSections.add(0, header.encode());
-
- String encodedString = encodedSections.stream().collect(Collectors.joining("~"));
- return encodedString;
+ encodedSections.add(0, header.encodeCharSequence());
+ return SlicedCharSequence.join('~', encodedSections).toString();
}
protected Map decodeModel(String str) {
if (str == null || str.isEmpty() || str.startsWith("DB")) {
Map sections = new HashMap<>();
- if (str != null && !str.isEmpty()) {
- String[] encodedSections = str.split("~");
- HeaderV1 header = new HeaderV1(encodedSections[0]);
+ if(str != null && !str.isEmpty()) {
+ List encodedSections = SlicedCharSequence.split(str, '~');
+ HeaderV1 header = new HeaderV1(encodedSections.get(0));
sections.put(HeaderV1.NAME, header);
- @SuppressWarnings("unchecked")
- List sectionIds = (List) header.getFieldValue("SectionIds");
- for (int i = 0; i < sectionIds.size(); i++) {
- if (sectionIds.get(i).equals(TcfEuV2.ID)) {
- TcfEuV2 section = new TcfEuV2(encodedSections[i + 1]);
- sections.put(TcfEuV2.NAME, section);
- } else if (sectionIds.get(i).equals(TcfCaV1.ID)) {
- TcfCaV1 section = new TcfCaV1(encodedSections[i + 1]);
- sections.put(TcfCaV1.NAME, section);
- } else if (sectionIds.get(i).equals(UspV1.ID)) {
- UspV1 section = new UspV1(encodedSections[i + 1]);
- sections.put(UspV1.NAME, section);
- } else if (sectionIds.get(i).equals(UsCa.ID)) {
- UsCa section = new UsCa(encodedSections[i + 1]);
- sections.put(UsCa.NAME, section);
- } else if (sectionIds.get(i).equals(UsNat.ID)) {
- UsNat section = new UsNat(encodedSections[i + 1]);
- sections.put(UsNat.NAME, section);
- } else if (sectionIds.get(i).equals(UsVa.ID)) {
- UsVa section = new UsVa(encodedSections[i + 1]);
- sections.put(UsVa.NAME, section);
- } else if (sectionIds.get(i).equals(UsCo.ID)) {
- UsCo section = new UsCo(encodedSections[i + 1]);
- sections.put(UsCo.NAME, section);
- } else if (sectionIds.get(i).equals(UsUt.ID)) {
- UsUt section = new UsUt(encodedSections[i + 1]);
- sections.put(UsUt.NAME, section);
- } else if (sectionIds.get(i).equals(UsCt.ID)) {
- UsCt section = new UsCt(encodedSections[i + 1]);
- sections.put(UsCt.NAME, section);
- } else if (sectionIds.get(i).equals(UsFl.ID)) {
- UsFl section = new UsFl(encodedSections[i + 1]);
- sections.put(UsFl.NAME, section);
- } else if (sectionIds.get(i).equals(UsMt.ID)) {
- UsMt section = new UsMt(encodedSections[i + 1]);
- sections.put(UsMt.NAME, section);
- } else if (sectionIds.get(i).equals(UsOr.ID)) {
- UsOr section = new UsOr(encodedSections[i + 1]);
- sections.put(UsOr.NAME, section);
- } else if (sectionIds.get(i).equals(UsTx.ID)) {
- UsTx section = new UsTx(encodedSections[i + 1]);
- sections.put(UsTx.NAME, section);
- } else if (sectionIds.get(i).equals(UsDe.ID)) {
- UsDe section = new UsDe(encodedSections[i + 1]);
- sections.put(UsDe.NAME, section);
- } else if (sectionIds.get(i).equals(UsIa.ID)) {
- UsIa section = new UsIa(encodedSections[i + 1]);
- sections.put(UsIa.NAME, section);
- } else if (sectionIds.get(i).equals(UsNe.ID)) {
- UsNe section = new UsNe(encodedSections[i + 1]);
- sections.put(UsNe.NAME, section);
- } else if (sectionIds.get(i).equals(UsNh.ID)) {
- UsNh section = new UsNh(encodedSections[i + 1]);
- sections.put(UsNh.NAME, section);
- } else if (sectionIds.get(i).equals(UsNj.ID)) {
- UsNj section = new UsNj(encodedSections[i + 1]);
- sections.put(UsNj.NAME, section);
- } else if (sectionIds.get(i).equals(UsTn.ID)) {
- UsTn section = new UsTn(encodedSections[i + 1]);
- sections.put(UsTn.NAME, section);
+ PrimitiveIterator.OfInt it = header.getSectionsIds().iterator();
+ int i = 1;
+ while (it.hasNext()) {
+ CharSequence section = encodedSections.get(i++);
+ switch (it.nextInt()) {
+ case TcfEuV2.ID:
+ sections.put(TcfEuV2.NAME, new TcfEuV2(section));
+ break;
+ case TcfCaV1.ID:
+ sections.put(TcfCaV1.NAME, new TcfCaV1(section));
+ break;
+ case UspV1.ID:
+ sections.put(UspV1.NAME, new UspV1(section));
+ break;
+ case UsCa.ID:
+ sections.put(UsCa.NAME, new UsCa(section));
+ break;
+ case UsNat.ID:
+ sections.put(UsNat.NAME, new UsNat(section));
+ break;
+ case UsVa.ID:
+ sections.put(UsVa.NAME, new UsVa(section));
+ break;
+ case UsCo.ID:
+ sections.put(UsCo.NAME, new UsCo(section));
+ break;
+ case UsUt.ID:
+ sections.put(UsUt.NAME, new UsUt(section));
+ break;
+ case UsCt.ID:
+ sections.put(UsCt.NAME, new UsCt(section));
+ break;
+ case UsFl.ID:
+ sections.put(UsFl.NAME, new UsFl(section));
+ break;
+ case UsMt.ID:
+ sections.put(UsMt.NAME, new UsMt(section));
+ break;
+ case UsOr.ID:
+ sections.put(UsOr.NAME, new UsOr(section));
+ break;
+ case UsTx.ID:
+ sections.put(UsTx.NAME, new UsTx(section));
+ break;
+ case UsDe.ID:
+ sections.put(UsDe.NAME, new UsDe(section));
+ break;
+ case UsIa.ID:
+ sections.put(UsIa.NAME, new UsIa(section));
+ break;
+ case UsNe.ID:
+ sections.put(UsNe.NAME, new UsNe(section));
+ break;
+ case UsNh.ID:
+ sections.put(UsNh.NAME, new UsNh(section));
+ break;
+ case UsNj.ID:
+ sections.put(UsNj.NAME, new UsNj(section));
+ break;
+ case UsTn.ID:
+ sections.put(UsTn.NAME, new UsTn(section));
+ break;
}
}
}
@@ -459,9 +459,9 @@ public String encodeSection(String sectionName) {
this.dirty = false;
this.decoded = true;
}
-
- if (this.sections.containsKey(sectionName)) {
- return this.sections.get(sectionName).encode();
+ EncodableSection section = this.sections.get(sectionName);
+ if (section != null) {
+ return section.encode();
} else {
return null;
}
@@ -477,71 +477,8 @@ public void decodeSection(String sectionName, String encodedString) {
this.dirty = false;
this.decoded = true;
}
-
- EncodableSection section = null;
- if (!this.sections.containsKey(sectionName)) {
- if (sectionName.equals(TcfEuV2.NAME)) {
- section = new TcfEuV2();
- this.sections.put(TcfEuV2.NAME, section);
- } else if (sectionName.equals(TcfCaV1.NAME)) {
- section = new TcfCaV1();
- this.sections.put(TcfCaV1.NAME, section);
- } else if (sectionName.equals(UspV1.NAME)) {
- section = new UspV1();
- this.sections.put(UspV1.NAME, section);
- } else if (sectionName.equals(UsNat.NAME)) {
- section = new UsNat();
- this.sections.put(UsNat.NAME, section);
- } else if (sectionName.equals(UsCa.NAME)) {
- section = new UsCa();
- this.sections.put(UsCa.NAME, section);
- } else if (sectionName.equals(UsVa.NAME)) {
- section = new UsVa();
- this.sections.put(UsVa.NAME, section);
- } else if (sectionName.equals(UsCo.NAME)) {
- section = new UsCo();
- this.sections.put(UsCo.NAME, section);
- } else if (sectionName.equals(UsUt.NAME)) {
- section = new UsUt();
- this.sections.put(UsUt.NAME, section);
- } else if (sectionName.equals(UsCt.NAME)) {
- section = new UsCt();
- this.sections.put(UsCt.NAME, section);
- } else if (sectionName.equals(UsFl.NAME)) {
- section = new UsFl();
- this.sections.put(UsFl.NAME, section);
- } else if (sectionName.equals(UsMt.NAME)) {
- section = new UsMt();
- this.sections.put(UsMt.NAME, section);
- } else if (sectionName.equals(UsOr.NAME)) {
- section = new UsOr();
- this.sections.put(UsOr.NAME, section);
- } else if (sectionName.equals(UsTx.NAME)) {
- section = new UsTx();
- this.sections.put(UsTx.NAME, section);
- }else if (sectionName.equals(UsDe.NAME)) {
- section = new UsDe();
- this.sections.put(UsDe.NAME, section);
- }else if (sectionName.equals(UsIa.NAME)) {
- section = new UsIa();
- this.sections.put(UsIa.NAME, section);
- }else if (sectionName.equals(UsNe.NAME)) {
- section = new UsNe();
- this.sections.put(UsNe.NAME, section);
- }else if (sectionName.equals(UsNh.NAME)) {
- section = new UsNh();
- this.sections.put(UsNh.NAME, section);
- }else if (sectionName.equals(UsNj.NAME)) {
- section = new UsNj();
- this.sections.put(UsNj.NAME, section);
- }else if (sectionName.equals(UsTn.NAME)) {
- section = new UsTn();
- this.sections.put(UsTn.NAME, section);
- }
- } else {
- section = this.sections.get(sectionName);
- }
+ EncodableSection section = getOrCreateSection(sectionName);
if (section != null) {
section.decode(encodedString);
this.dirty = true;
@@ -564,5 +501,14 @@ public void decode(String encodedString) {
this.decoded = false;
}
+ public String toString() {
+ List sectionIds = getSectionIds();
+ List pieces = new ArrayList<>(sectionIds.size());
+ for (Integer sectionId : sectionIds) {
+ pieces.add(getSection(sectionId).toString());
+ }
+ return pieces.toString();
+ }
+
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/AbstractBase64UrlEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/AbstractBase64UrlEncoder.java
index a5434073..eacd934d 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/AbstractBase64UrlEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/AbstractBase64UrlEncoder.java
@@ -1,56 +1,43 @@
package com.iab.gpp.encoder.base64;
-import java.util.Map;
-import java.util.regex.Pattern;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
public abstract class AbstractBase64UrlEncoder {
- abstract protected String pad(String bitString);
+ protected abstract void pad(BitStringBuilder bitString);
+ private static final int BASE64_BITS = 6;
/**
* Base 64 URL character set. Different from standard Base64 char set in that '+' and '/' are
* replaced with '-' and '_'.
*/
- private static String DICT = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
- // prettier-ignore
- private static Map REVERSE_DICT = Stream
- .of(new Object[][] {{'A', 0}, {'B', 1}, {'C', 2}, {'D', 3}, {'E', 4}, {'F', 5}, {'G', 6}, {'H', 7}, {'I', 8},
- {'J', 9}, {'K', 10}, {'L', 11}, {'M', 12}, {'N', 13}, {'O', 14}, {'P', 15}, {'Q', 16}, {'R', 17}, {'S', 18},
- {'T', 19}, {'U', 20}, {'V', 21}, {'W', 22}, {'X', 23}, {'Y', 24}, {'Z', 25}, {'a', 26}, {'b', 27}, {'c', 28},
- {'d', 29}, {'e', 30}, {'f', 31}, {'g', 32}, {'h', 33}, {'i', 34}, {'j', 35}, {'k', 36}, {'l', 37}, {'m', 38},
- {'n', 39}, {'o', 40}, {'p', 41}, {'q', 42}, {'r', 43}, {'s', 44}, {'t', 45}, {'u', 46}, {'v', 47}, {'w', 48},
- {'x', 49}, {'y', 50}, {'z', 51}, {'0', 52}, {'1', 53}, {'2', 54}, {'3', 55}, {'4', 56}, {'5', 57}, {'6', 58},
- {'7', 59}, {'8', 60}, {'9', 61}, {'-', 62}, {'_', 63}})
- .collect(Collectors.toMap(data -> (Character) data[0], data -> (Integer) data[1]));
-
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
- private static Pattern BASE64URL_VERIFICATION_PATTERN =
- Pattern.compile("^[A-Za-z0-9\\-_]*$", Pattern.CASE_INSENSITIVE);
-
- public String encode(String bitString) {
- // should only be 0 or 1
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) {
- throw new EncodingException("Unencodable Base64Url '" + bitString + "'");
+ private static final String DICT = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+ private static final int REVERSE_DICT_SIZE = 128;
+ private static final BitString[] REVERSE_DICT = new BitString[REVERSE_DICT_SIZE];
+ static {
+ for (int i = 0; i < DICT.length(); i++) {
+ BitStringBuilder builder = new BitStringBuilder();
+ FixedIntegerEncoder.encode(builder, i, 6);
+ REVERSE_DICT[DICT.charAt(i)] = builder.build();
}
+ }
- bitString = pad(bitString);
-
- String str = "";
+ public StringBuilder encode(BitStringBuilder bitStringBuilder) {
+ pad(bitStringBuilder);
+ BitString bitString = bitStringBuilder.build();
+ int length = bitString.length();
+ StringBuilder str = new StringBuilder(length / BASE64_BITS);
int index = 0;
- while (index <= bitString.length() - 6) {
- String s = bitString.substring(index, index + 6);
-
+ while (index <= length - BASE64_BITS) {
try {
- int n = FixedIntegerEncoder.decode(s);
- Character c = AbstractBase64UrlEncoder.DICT.charAt(n);
- str += c;
- index += 6;
+ int n = FixedIntegerEncoder.decode(bitString, index, BASE64_BITS);
+ str.append(DICT.charAt(n));
+ index += BASE64_BITS;
} catch (DecodingException e) {
throw new EncodingException("Unencodable Base64Url '" + bitString + "'");
}
@@ -59,21 +46,21 @@ public String encode(String bitString) {
return str;
}
- public String decode(String str) {
- // should contain only characters from the base64url set
- if (!BASE64URL_VERIFICATION_PATTERN.matcher(str).matches()) {
- throw new DecodingException("Undecodable Base64URL string");
- }
-
- String bitString = "";
-
- for (int i = 0; i < str.length(); i++) {
+ public BitString decode(CharSequence str) {
+ int length = str.length();
+ BitStringBuilder sb = new BitStringBuilder(length * BASE64_BITS);
+ for (int i = 0; i < length; i++) {
char c = str.charAt(i);
- Integer n = AbstractBase64UrlEncoder.REVERSE_DICT.get(c);
- String s = FixedIntegerEncoder.encode(n, 6);
- bitString += s;
- }
+ BitString n = null;
+ if (c < REVERSE_DICT_SIZE) {
+ n = REVERSE_DICT[c];
+ }
+ if (n == null) {
+ throw new DecodingException("Undecodable Base64URL string");
+ }
+ sb.append(n);
- return bitString;
+ }
+ return sb.build();
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/CompressedBase64UrlEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/CompressedBase64UrlEncoder.java
index 4ebd7be7..f94ceb3a 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/CompressedBase64UrlEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/CompressedBase64UrlEncoder.java
@@ -1,38 +1,36 @@
package com.iab.gpp.encoder.base64;
-import java.util.Arrays;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
-public class CompressedBase64UrlEncoder extends AbstractBase64UrlEncoder {
+public final class CompressedBase64UrlEncoder extends AbstractBase64UrlEncoder {
+
+ private static final CompressedBase64UrlEncoder instance = new CompressedBase64UrlEncoder();
- private static CompressedBase64UrlEncoder instance = new CompressedBase64UrlEncoder();
-
private CompressedBase64UrlEncoder() {
-
+
}
-
+
public static CompressedBase64UrlEncoder getInstance() {
return instance;
}
-
+
@Override
- protected String pad(String bitString) {
- char[] chars1 = null;
- if(bitString.length() % 8 > 0) {
- chars1 = new char[8 - (bitString.length() % 8)];
- } else {
- chars1 = new char[0];
+ protected void pad(BitStringBuilder bitString) {
+ int remainder = bitString.length() % 8;
+ if(remainder > 0) {
+ int padding = 8 - remainder;
+ for (int i = 0; i < padding; i++) {
+ bitString.append(false);
+ }
}
- Arrays.fill(chars1, '0');
-
- char[] chars2 = null;
- if((bitString.length() + chars1.length) % 6 > 0) {
- chars2 = new char[6 - ((bitString.length() + chars1.length) % 6)];
- } else {
- chars2 = new char[0];
+
+ remainder = bitString.length() % 6;
+ if(remainder > 0) {
+ int padding = 6 - remainder;
+ for (int i = 0; i < padding; i++) {
+ bitString.append(false);
+ }
}
- Arrays.fill(chars2, '0');
-
- return bitString + new String(chars1) + new String(chars2);
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoder.java
index 78ffe719..43c8e866 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoder.java
@@ -1,27 +1,27 @@
package com.iab.gpp.encoder.base64;
-import java.util.Arrays;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
-public class TraditionalBase64UrlEncoder extends AbstractBase64UrlEncoder {
+public final class TraditionalBase64UrlEncoder extends AbstractBase64UrlEncoder {
+
+ private static final TraditionalBase64UrlEncoder instance = new TraditionalBase64UrlEncoder();
- private static TraditionalBase64UrlEncoder instance = new TraditionalBase64UrlEncoder();
-
private TraditionalBase64UrlEncoder() {
-
+
}
-
+
public static TraditionalBase64UrlEncoder getInstance() {
return instance;
}
-
+
@Override
- protected String pad(String bitString) {
- if(bitString.length() % 24 > 0) {
- char[] chars = new char[24 - (bitString.length() % 24)];
- Arrays.fill(chars, '0');
- return bitString + new String(chars);
- } else {
- return bitString;
+ protected void pad(BitStringBuilder bitString) {
+ int remainder = bitString.length() % 24;
+ if (remainder > 0) {
+ int padding = 24 - remainder;
+ for (int i = 0; i < padding; i++) {
+ bitString.append(false);
+ }
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitString.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitString.java
new file mode 100644
index 00000000..8026d69c
--- /dev/null
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitString.java
@@ -0,0 +1,98 @@
+package com.iab.gpp.encoder.bitstring;
+
+import java.util.BitSet;
+import com.iab.gpp.encoder.datatype.encoder.IntegerBitSet;
+import com.iab.gpp.encoder.datatype.encoder.IntegerSet;
+import com.iab.gpp.encoder.error.DecodingException;
+
+public final class BitString {
+ public static final char TRUE = '1';
+ public static final char FALSE = '0';
+ public static final String TRUE_STRING = new String(new char[] {TRUE});
+ public static final String FALSE_STRING = new String(new char[] {FALSE});
+ private static final BitString EMPTY = new BitString(new BitSet(), 0, 0);
+
+ private final BitSet bitSet;
+ private final int from;
+ private final int to;
+
+ BitString(BitSet bitSet, int from, int to) {
+ this.bitSet = bitSet;
+ this.from = from;
+ this.to = to;
+ }
+
+ public static final BitString empty(int size) {
+ if (size == 0) {
+ return EMPTY;
+ }
+ return new BitString(new BitSet(size), 0, size);
+ }
+
+ public static final BitString of(String str) {
+ int length = str.length();
+ BitStringBuilder builder = new BitStringBuilder(length);
+ for (int i = 0; i < length; i++) {
+ char c = str.charAt(i);
+ if (c == TRUE) {
+ builder.append(true);
+ } else if (c == FALSE) {
+ builder.append(false);
+ } else {
+ throw new DecodingException("Invalid bit string");
+ }
+ }
+ return builder.build();
+ }
+
+ public IntegerSet toIntegerSet() {
+ return new IntegerBitSet(bitSet, from, to, 1);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(length());
+ for (int i = from; i < to; i++) {
+ sb.append(bitSet.get(i) ? TRUE : FALSE);
+ }
+ return sb.toString();
+ }
+
+ public boolean getValue(int i) {
+ return bitSet.get(from + i);
+ }
+
+ public int length() {
+ return to - from;
+ }
+
+ public BitString substring(int i) {
+ return substring(i, length());
+ }
+
+ public BitString substring(int newFrom, int newTo) {
+ int length = length();
+ if (newFrom > newTo || newFrom < 0 || newFrom > length || newTo > length) {
+ throw new IllegalArgumentException("Invalid substring");
+ }
+ int oldFrom = this.from;
+ return new BitString(bitSet, oldFrom + newFrom, oldFrom + newTo);
+ }
+
+ public BitString expandTo(int target) {
+ int needed = target - length();
+ if (needed == 0) {
+ return this;
+ }
+ if (needed < 0) {
+ return substring(0, target);
+ }
+ BitStringBuilder sb = new BitStringBuilder(target);
+ sb.append(this);
+ for (int i = 0; i < needed; i++) {
+ sb.append(false);
+ }
+ return sb.build();
+ }
+
+}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringBuilder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringBuilder.java
new file mode 100644
index 00000000..88d0ffaa
--- /dev/null
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringBuilder.java
@@ -0,0 +1,48 @@
+package com.iab.gpp.encoder.bitstring;
+
+import java.util.BitSet;
+
+public final class BitStringBuilder {
+ private final BitSet bitSet;
+ private int length;
+
+ public BitStringBuilder(int initialCapacity) {
+ this.bitSet = new BitSet(initialCapacity);
+ }
+
+ public BitStringBuilder() {
+ this.bitSet = new BitSet();
+ }
+
+ public BitString build() {
+ return new BitString(bitSet, 0, length);
+ }
+
+ public BitStringBuilder append(boolean value) {
+ int idx = length++;
+ if (value) {
+ bitSet.set(idx);
+ }
+ return this;
+ }
+
+ public BitStringBuilder append(BitString other) {
+ int otherLength = other.length();
+ for (int i = 0; i < otherLength; i++) {
+ append(other.getValue(i));
+ }
+ return this;
+ }
+
+ public int length() {
+ return length;
+ }
+
+ public BitStringBuilder append(BitStringBuilder other) {
+ int otherLength = other.length();
+ for (int i = 0; i < otherLength; i++) {
+ append(other.bitSet.get(i));
+ }
+ return this;
+ }
+}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringEncoder.java
index 12bcb182..79ce4ef6 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringEncoder.java
@@ -7,54 +7,54 @@
import com.iab.gpp.encoder.error.EncodingException;
import com.iab.gpp.encoder.field.EncodableBitStringFields;
-public class BitStringEncoder {
+public final class BitStringEncoder {
+
+ private static final BitStringEncoder instance = new BitStringEncoder();
- private static BitStringEncoder instance = new BitStringEncoder();
-
private BitStringEncoder() {
-
+
}
-
+
public static BitStringEncoder getInstance() {
return instance;
}
-
- public String encode(EncodableBitStringFields fields, List fieldNames) {
- String bitString = "";
+
+ public BitStringBuilder encode(EncodableBitStringFields fields) {
+ BitStringBuilder bitString = new BitStringBuilder();
+ List fieldNames = fields.getNames();
for (int i = 0; i < fieldNames.size(); i++) {
- String fieldName = fieldNames.get(i);
- if (fields.containsKey(fieldName)) {
- AbstractEncodableBitStringDataType> field = fields.get(fieldName);
- bitString += field.encode();
+ AbstractEncodableBitStringDataType> field = fields.get(i);
+ if (field != null) {
+ field.encode(bitString);
} else {
- throw new EncodingException("Field not found: '" + fieldName + "'");
+ throw new EncodingException("Field not found: '" + fieldNames.get(i) + "'");
}
}
return bitString;
}
- public void decode(String bitString, List fieldNames, EncodableBitStringFields fields) {
+ public void decode(BitString bitString, EncodableBitStringFields fields) {
int index = 0;
+ List fieldNames = fields.getNames();
for (int i = 0; i < fieldNames.size(); i++) {
- String fieldName = fieldNames.get(i);
- if (fields.containsKey(fieldName)) {
- AbstractEncodableBitStringDataType> field = fields.get(fieldName);
+ AbstractEncodableBitStringDataType> field = fields.get(i);
+ if (field != null) {
try {
- String substring = field.substring(bitString, index);
+ BitString substring = field.substring(bitString, index);
field.decode(substring);
index += substring.length();
} catch (SubstringException e) {
if(field.getHardFailIfMissing()) {
- throw new DecodingException("Unable to decode " + fieldName, e);
+ throw new DecodingException("Unable to decode " + fieldNames.get(i), e);
} else {
return;
}
} catch (Exception e) {
- throw new DecodingException("Unable to decode " + fieldName, e);
+ throw new DecodingException("Unable to decode " + fieldNames.get(i), e);
}
} else {
- throw new DecodingException("Field not found: '" + fieldName + "'");
+ throw new DecodingException("Field not found: '" + fieldNames.get(i) + "'");
}
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/AbstractEncodableBitStringDataType.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/AbstractEncodableBitStringDataType.java
index 07d9588c..8cb8cdb6 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/AbstractEncodableBitStringDataType.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/AbstractEncodableBitStringDataType.java
@@ -3,23 +3,26 @@
import java.util.Collection;
import java.util.function.Predicate;
import java.util.stream.Collectors;
+
+import com.iab.gpp.encoder.bitstring.BitString;
import com.iab.gpp.encoder.error.ValidationException;
public abstract class AbstractEncodableBitStringDataType implements EncodableDataType {
//this if for backwards compatibility with the newer fields
protected boolean hardFailIfMissing = true;
+ protected boolean dirty = false;
protected Predicate validator = null;
protected T value;
protected AbstractEncodableBitStringDataType(boolean hardFailIfMissing) {
this.hardFailIfMissing = hardFailIfMissing;
}
-
+
public AbstractEncodableBitStringDataType withValidator(Predicate validator) {
this.validator = validator;
return this;
}
-
+
public boolean hasValue() {
return this.value != null;
}
@@ -33,10 +36,11 @@ public void setValue(Object value) {
T v = (T) value;
if (validator == null || validator.test(v)) {
this.value = v;
+ this.dirty = true;
} else {
if (v instanceof Collection) {
throw new ValidationException("Invalid value '"
- + ((Collection>) v).stream().map(i -> i.toString()).collect(Collectors.joining(",")) + "'");
+ + ((Collection>) v).stream().map(Object::toString).collect(Collectors.joining(",")) + "'");
} else {
throw new ValidationException("Invalid value '" + v + "'");
}
@@ -48,10 +52,13 @@ public boolean getHardFailIfMissing() {
return this.hardFailIfMissing;
}
- public abstract String encode();
+ public abstract BitString substring(BitString bitString, int fromIndex) throws SubstringException;
- public abstract void decode(String bitString);
-
- public abstract String substring(String bitString, int fromIndex) throws SubstringException;
+ public boolean isDirty() {
+ return dirty;
+ }
+ public void setDirty(boolean dirty) {
+ this.dirty = dirty;
+ }
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/DataType.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/DataType.java
index 8a0d2c07..58d70730 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/DataType.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/DataType.java
@@ -4,4 +4,6 @@ public interface DataType {
boolean hasValue();
T getValue();
void setValue(Object value);
+ boolean isDirty();
+ void setDirty(boolean dirty);
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedIntegerRanges.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedIntegerRanges.java
index 699e0d26..bcc9ff98 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedIntegerRanges.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedIntegerRanges.java
@@ -1,107 +1,98 @@
package com.iab.gpp.encoder.datatype;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder;
import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder;
+import com.iab.gpp.encoder.datatype.encoder.IntegerSet;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableArrayOfFixedIntegerRanges extends AbstractEncodableBitStringDataType> {
+public final class EncodableArrayOfFixedIntegerRanges extends AbstractEncodableBitStringDataType> {
private int keyBitStringLength;
private int typeBitStringLength;
- protected EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength) {
- super(true);
- this.keyBitStringLength = keyBitStringLength;
- this.typeBitStringLength = typeBitStringLength;
- }
-
- public EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength, List value) {
- super(true);
- this.keyBitStringLength = keyBitStringLength;
- this.typeBitStringLength = typeBitStringLength;
- setValue(value);
- }
-
- public EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength, List value, boolean hardFailIfMissing) {
+ public EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength, boolean hardFailIfMissing) {
super(hardFailIfMissing);
this.keyBitStringLength = keyBitStringLength;
this.typeBitStringLength = typeBitStringLength;
- setValue(value);
+ this.value = Collections.emptyList();
}
@Override
- public String encode() {
+ public void encode(BitStringBuilder sb) {
try {
List entries = this.value;
-
- StringBuilder sb = new StringBuilder();
- sb.append(FixedIntegerEncoder.encode(entries.size(), 12));
+
+ FixedIntegerEncoder.encode(sb, entries.size(), 12);
for (RangeEntry entry : entries) {
- sb.append(FixedIntegerEncoder.encode(entry.getKey(), keyBitStringLength))
- .append(FixedIntegerEncoder.encode(entry.getType(), typeBitStringLength))
- .append(FixedIntegerRangeEncoder.encode(entry.getIds()));
+ FixedIntegerEncoder.encode(sb, entry.getKey(), keyBitStringLength);
+ FixedIntegerEncoder.encode(sb, entry.getType(), typeBitStringLength);
+ FixedIntegerRangeEncoder.encode(sb, entry.getIds());
}
-
- return sb.toString();
+
} catch (Exception e) {
throw new EncodingException(e);
}
}
@Override
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
- List entries = new ArrayList<>();
-
- int size = FixedIntegerEncoder.decode(bitString.substring(0, 12));
+ int size = FixedIntegerEncoder.decode(bitString, 0, 12);
+ List entries = new ArrayList<>(size);
int index = 12;
for (int i = 0; i < size; i++) {
- int key = FixedIntegerEncoder.decode(bitString.substring(index, index + keyBitStringLength));
+ int key = FixedIntegerEncoder.decode(bitString, index, keyBitStringLength);
index += keyBitStringLength;
-
- int type = FixedIntegerEncoder.decode(bitString.substring(index, index + typeBitStringLength));
+
+ int type = FixedIntegerEncoder.decode(bitString, index, typeBitStringLength);
index += typeBitStringLength;
-
- String substring = new EncodableFixedIntegerRange().substring(bitString, index);
- List ids = FixedIntegerRangeEncoder.decode(substring);
+
+ BitString substring = new EncodableFixedIntegerRange().substring(bitString, index);
+ IntegerSet ids = FixedIntegerRangeEncoder.decode(substring);
index += substring.length();
-
+
entries.add(new RangeEntry(key, type, ids));
}
-
- this.value = entries;
+
+ // NOTE: this requires that updates to structure be done using the setter
+ this.value = Collections.unmodifiableList(entries);
} catch (Exception e) {
throw new DecodingException(e);
}
}
@Override
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
- StringBuilder sb = new StringBuilder();
- sb.append(bitString.substring(fromIndex, fromIndex + 12));
-
- int size = FixedIntegerEncoder.decode(sb.toString());
-
- int index = fromIndex + sb.length();
+ BitStringBuilder sb = new BitStringBuilder();
+ BitString lengthString = bitString.substring(fromIndex, fromIndex + 12);
+ sb.append(lengthString);
+
+ int size = FixedIntegerEncoder.decode(lengthString);
+
+ int index = fromIndex + lengthString.length();
for (int i = 0; i < size; i++) {
- String keySubstring = bitString.substring(index, index + keyBitStringLength);
+ BitString keySubstring = bitString.substring(index, index + keyBitStringLength);
index += keySubstring.length();
sb.append(keySubstring);
-
- String typeSubstring = bitString.substring(index, index + typeBitStringLength);
+
+ BitString typeSubstring = bitString.substring(index, index + typeBitStringLength);
index += typeSubstring.length();
sb.append(typeSubstring);
-
- String rangeSubstring = new EncodableFixedIntegerRange().substring(bitString, index);
+
+ BitString rangeSubstring = new EncodableFixedIntegerRange().substring(bitString, index);
index += rangeSubstring.length();
sb.append(rangeSubstring);
}
-
- return sb.toString();
+
+ return sb.build();
} catch (Exception e) {
throw new SubstringException(e);
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableBoolean.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableBoolean.java
index 340be3ab..3c418fd8 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableBoolean.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableBoolean.java
@@ -1,34 +1,27 @@
package com.iab.gpp.encoder.datatype;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.datatype.encoder.BooleanEncoder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableBoolean extends AbstractEncodableBitStringDataType {
-
- protected EncodableBoolean() {
- super(true);
- }
+public final class EncodableBoolean extends AbstractEncodableBitStringDataType {
public EncodableBoolean(Boolean value) {
super(true);
setValue(value);
}
- public EncodableBoolean(Boolean value, boolean hardFailIfMissing) {
- super(hardFailIfMissing);
- setValue(value);
- }
-
- public String encode() {
+ public void encode(BitStringBuilder builder){
try {
- return BooleanEncoder.encode(this.value);
+ BooleanEncoder.encode(builder, this.value);
} catch (Exception e) {
throw new EncodingException(e);
}
}
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
this.value = BooleanEncoder.decode(bitString);
} catch (Exception e) {
@@ -36,7 +29,7 @@ public void decode(String bitString) {
}
}
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
return bitString.substring(fromIndex, fromIndex + 1);
} catch (Exception e) {
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDataType.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDataType.java
index 94d416a6..530ae121 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDataType.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDataType.java
@@ -1,7 +1,10 @@
package com.iab.gpp.encoder.datatype;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
+
public interface EncodableDataType extends DataType {
- String encode();
+ void encode(BitStringBuilder builder);
- void decode(String str);
+ void decode(BitString str);
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDatetime.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDatetime.java
index a96c46f4..9a158820 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDatetime.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDatetime.java
@@ -1,35 +1,33 @@
package com.iab.gpp.encoder.datatype;
-import java.time.ZonedDateTime;
+import java.time.Instant;
+
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.datatype.encoder.DatetimeEncoder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableDatetime extends AbstractEncodableBitStringDataType {
+public final class EncodableDatetime extends AbstractEncodableBitStringDataType {
protected EncodableDatetime() {
super(true);
}
- public EncodableDatetime(ZonedDateTime value) {
+ public EncodableDatetime(Instant value) {
super(true);
setValue(value);
}
- public EncodableDatetime(ZonedDateTime value, boolean hardFailIfMissing) {
- super(hardFailIfMissing);
- setValue(value);
- }
-
- public String encode() {
+ public void encode(BitStringBuilder builder) {
try {
- return DatetimeEncoder.encode(this.value);
+ DatetimeEncoder.encode(builder, this.value);
} catch (Exception e) {
throw new EncodingException(e);
}
}
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
this.value = DatetimeEncoder.decode(bitString);
} catch (Exception e) {
@@ -37,7 +35,7 @@ public void decode(String bitString) {
}
}
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
return bitString.substring(fromIndex, fromIndex + 36);
} catch (Exception e) {
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciInteger.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciInteger.java
index 3da64a15..c0106dc9 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciInteger.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciInteger.java
@@ -1,10 +1,12 @@
package com.iab.gpp.encoder.datatype;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerEncoder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableFibonacciInteger extends AbstractEncodableBitStringDataType {
+public final class EncodableFibonacciInteger extends AbstractEncodableBitStringDataType {
protected EncodableFibonacciInteger() {
super(true);
@@ -20,15 +22,15 @@ public EncodableFibonacciInteger(Integer value, boolean hardFailIfMissing) {
setValue(value);
}
- public String encode() {
+ public void encode(BitStringBuilder builder) {
try {
- return FibonacciIntegerEncoder.encode(this.value);
+ FibonacciIntegerEncoder.encode(builder, this.value);
} catch (Exception e) {
throw new EncodingException(e);
}
}
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
this.value = FibonacciIntegerEncoder.decode(bitString);
} catch (Exception e) {
@@ -36,9 +38,9 @@ public void decode(String bitString) {
}
}
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
- int index = bitString.indexOf("11", fromIndex);
+ int index = FibonacciIntegerEncoder.indexOfEndTag(bitString, fromIndex);
if (index > 0) {
return bitString.substring(fromIndex, index + 2);
} else {
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRange.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRange.java
index 53ab2eb2..19963a55 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRange.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRange.java
@@ -1,38 +1,32 @@
package com.iab.gpp.encoder.datatype;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.TreeSet;
+import java.util.Collection;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
+import com.iab.gpp.encoder.datatype.encoder.IntegerBitSet;
+import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerEncoder;
import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerRangeEncoder;
import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder;
+import com.iab.gpp.encoder.datatype.encoder.IntegerSet;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableFibonacciIntegerRange extends AbstractEncodableBitStringDataType> {
+public final class EncodableFibonacciIntegerRange extends AbstractEncodableBitStringDataType {
- protected EncodableFibonacciIntegerRange() {
+ public EncodableFibonacciIntegerRange() {
super(true);
+ this.value = new IntegerBitSet();
}
- public EncodableFibonacciIntegerRange(List value) {
- super(true);
- setValue(value);
- }
-
- public EncodableFibonacciIntegerRange(List value, boolean hardFailIfMissing) {
- super(hardFailIfMissing);
- setValue(value);
- }
-
- public String encode() {
+ public void encode(BitStringBuilder builder) {
try {
- return FibonacciIntegerRangeEncoder.encode(this.value);
+ FibonacciIntegerRangeEncoder.encode(builder, this.value);
} catch (Exception e) {
throw new EncodingException(e);
}
}
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
this.value = FibonacciIntegerRangeEncoder.decode(bitString);
} catch (Exception e) {
@@ -40,15 +34,15 @@ public void decode(String bitString) {
}
}
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
- int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 12));
+ int count = FixedIntegerEncoder.decode(bitString, fromIndex, 12);
int index = fromIndex + 12;
for (int i = 0; i < count; i++) {
- if (bitString.charAt(index) == '1') {
- index = bitString.indexOf("11", bitString.indexOf("11", index + 1) + 2) + 2;
+ if (bitString.getValue(index)) {
+ index = FibonacciIntegerEncoder.indexOfEndTag(bitString, FibonacciIntegerEncoder.indexOfEndTag(bitString, index + 1) + 2) + 2;
} else {
- index = bitString.indexOf("11", index + 1) + 2;
+ index = FibonacciIntegerEncoder.indexOfEndTag(bitString, index + 1) + 2;
}
}
return bitString.substring(fromIndex, index);
@@ -60,11 +54,12 @@ public String substring(String bitString, int fromIndex) throws SubstringExcepti
@SuppressWarnings("unchecked")
@Override
public void setValue(Object value) {
- super.setValue(new ArrayList<>(new TreeSet<>((List) value)));
+ this.value.clear();
+ this.value.addAll((Collection) value);
}
@Override
- public List getValue() {
- return new ArrayList<>(super.getValue());
+ public IntegerSet getValue() {
+ return new ManagedIntegerSet(this, super.getValue());
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfield.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfield.java
index 5e6890d9..e7404069 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfield.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfield.java
@@ -1,46 +1,33 @@
package com.iab.gpp.encoder.datatype;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Collection;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
+import com.iab.gpp.encoder.datatype.encoder.IntegerBitSet;
import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder;
+import com.iab.gpp.encoder.datatype.encoder.IntegerSet;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableFixedBitfield extends AbstractEncodableBitStringDataType> {
+public final class EncodableFixedBitfield extends AbstractEncodableBitStringDataType {
- private int numElements;
+ private final int numElements;
- protected EncodableFixedBitfield(int numElements) {
+ public EncodableFixedBitfield(int numElements) {
super(true);
this.numElements = numElements;
+ this.value = new IntegerBitSet(numElements);
}
- protected EncodableFixedBitfield(int numElements, boolean hardFailIfMissing) {
- super(hardFailIfMissing);
- this.numElements = numElements;
- }
-
- public EncodableFixedBitfield(List value) {
- super(true);
- this.numElements = value.size();
- setValue(value);
- }
-
- public EncodableFixedBitfield(List value, boolean hardFailIfMissing) {
- super(hardFailIfMissing);
- this.numElements = value.size();
- setValue(value);
- }
-
- public String encode() {
+ public void encode(BitStringBuilder builder) {
try {
- return FixedBitfieldEncoder.encode(this.value, this.numElements);
+ FixedBitfieldEncoder.encode(builder, this.value, this.numElements);
} catch (Exception e) {
throw new EncodingException(e);
}
}
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
this.value = FixedBitfieldEncoder.decode(bitString);
} catch (Exception e) {
@@ -48,7 +35,7 @@ public void decode(String bitString) {
}
}
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
return bitString.substring(fromIndex, fromIndex + this.numElements);
} catch (Exception e) {
@@ -59,18 +46,12 @@ public String substring(String bitString, int fromIndex) throws SubstringExcepti
@SuppressWarnings("unchecked")
@Override
public void setValue(Object value) {
- List v = new ArrayList<>((List) value);
- for (int i = v.size(); i < numElements; i++) {
- v.add(false);
- }
- if (v.size() > numElements) {
- v = v.subList(0, numElements);
- }
- super.setValue(v);
+ this.value.clear();
+ this.value.addAll((Collection) value);
}
@Override
- public List getValue() {
- return new ArrayList<>(super.getValue());
+ public IntegerSet getValue() {
+ return new ManagedIntegerSet(this, super.getValue());
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedInteger.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedInteger.java
index 9fd25fb0..d6dc9775 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedInteger.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedInteger.java
@@ -1,10 +1,12 @@
package com.iab.gpp.encoder.datatype;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableFixedInteger extends AbstractEncodableBitStringDataType {
+public final class EncodableFixedInteger extends AbstractEncodableBitStringDataType {
private int bitStringLength;
@@ -19,21 +21,15 @@ public EncodableFixedInteger(int bitStringLength, Integer value) {
setValue(value);
}
- public EncodableFixedInteger(int bitStringLength, Integer value, boolean hardFailIfMissing) {
- super(hardFailIfMissing);
- this.bitStringLength = bitStringLength;
- setValue(value);
- }
-
- public String encode() {
+ public void encode(BitStringBuilder builder) {
try {
- return FixedIntegerEncoder.encode(this.value, this.bitStringLength);
+ FixedIntegerEncoder.encode(builder, this.value, this.bitStringLength);
} catch (Exception e) {
throw new EncodingException(e);
}
}
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
this.value = FixedIntegerEncoder.decode(bitString);
} catch (Exception e) {
@@ -41,7 +37,7 @@ public void decode(String bitString) {
}
}
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
return bitString.substring(fromIndex, fromIndex + this.bitStringLength);
} catch (Exception e) {
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerList.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerList.java
index f491e5ee..3a4db509 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerList.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerList.java
@@ -2,11 +2,14 @@
import java.util.ArrayList;
import java.util.List;
+
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.datatype.encoder.FixedIntegerListEncoder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableFixedIntegerList extends AbstractEncodableBitStringDataType> {
+public final class EncodableFixedIntegerList extends AbstractEncodableBitStringDataType> {
private int elementBitStringLength;
private int numElements;
@@ -24,22 +27,15 @@ public EncodableFixedIntegerList(int elementBitStringLength, List value
setValue(value);
}
- public EncodableFixedIntegerList(int elementBitStringLength, List value, boolean hardFailIfMissing) {
- super(hardFailIfMissing);
- this.elementBitStringLength = elementBitStringLength;
- this.numElements = value.size();
- setValue(value);
- }
-
- public String encode() {
+ public void encode(BitStringBuilder builder) {
try {
- return FixedIntegerListEncoder.encode(this.value, this.elementBitStringLength, this.numElements);
+ FixedIntegerListEncoder.encode(builder, this.value, this.elementBitStringLength, this.numElements);
} catch (Exception e) {
throw new EncodingException(e);
}
}
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
this.value = FixedIntegerListEncoder.decode(bitString, this.elementBitStringLength, this.numElements);
} catch (Exception e) {
@@ -47,7 +43,7 @@ public void decode(String bitString) {
}
}
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
return bitString.substring(fromIndex, fromIndex + (this.elementBitStringLength * numElements));
} catch (Exception e) {
@@ -70,6 +66,6 @@ public void setValue(Object value) {
@Override
public List getValue() {
- return new ArrayList<>(super.getValue());
+ return new ManagedFixedList<>(this, super.getValue());
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRange.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRange.java
index 7fdbd5a8..7bbbc4a6 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRange.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRange.java
@@ -1,38 +1,31 @@
package com.iab.gpp.encoder.datatype;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.TreeSet;
+import java.util.Collection;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
+import com.iab.gpp.encoder.datatype.encoder.IntegerBitSet;
import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder;
import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder;
+import com.iab.gpp.encoder.datatype.encoder.IntegerSet;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableFixedIntegerRange extends AbstractEncodableBitStringDataType> {
+public final class EncodableFixedIntegerRange extends AbstractEncodableBitStringDataType {
protected EncodableFixedIntegerRange() {
super(true);
+ this.value = new IntegerBitSet();
}
- public EncodableFixedIntegerRange(List value) {
- super(true);
- setValue(value);
- }
-
- public EncodableFixedIntegerRange(List value, boolean hardFailIfMissing) {
- super(hardFailIfMissing);
- setValue(value);
- }
-
- public String encode() {
+ public void encode(BitStringBuilder builder) {
try {
- return FixedIntegerRangeEncoder.encode(this.value);
+ FixedIntegerRangeEncoder.encode(builder, this.value);
} catch (Exception e) {
throw new EncodingException(e);
}
}
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
this.value = FixedIntegerRangeEncoder.decode(bitString);
} catch (Exception e) {
@@ -40,12 +33,12 @@ public void decode(String bitString) {
}
}
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
- int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 12));
+ int count = FixedIntegerEncoder.decode(bitString, fromIndex, 12);
int index = fromIndex + 12;
for (int i = 0; i < count; i++) {
- if (bitString.charAt(index) == '1') {
+ if (bitString.getValue(index)) {
index += 33;
} else {
index += 17;
@@ -60,11 +53,12 @@ public String substring(String bitString, int fromIndex) throws SubstringExcepti
@SuppressWarnings("unchecked")
@Override
public void setValue(Object value) {
- super.setValue(new ArrayList<>(new TreeSet<>((List) value)));
+ this.value.clear();
+ this.value.addAll((Collection) value);
}
@Override
- public List getValue() {
- return new ArrayList<>(super.getValue());
+ public IntegerSet getValue() {
+ return new ManagedIntegerSet(this, super.getValue());
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedString.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedString.java
index 4cea9b48..7221078c 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedString.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFixedString.java
@@ -1,10 +1,12 @@
package com.iab.gpp.encoder.datatype;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.datatype.encoder.FixedStringEncoder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableFixedString extends AbstractEncodableBitStringDataType {
+public final class EncodableFixedString extends AbstractEncodableBitStringDataType {
private int stringLength;
@@ -19,21 +21,15 @@ public EncodableFixedString(int stringLength, String value) {
setValue(value);
}
- public EncodableFixedString(int stringLength, String value, boolean hardFailIfMissing) {
- super(hardFailIfMissing);
- this.stringLength = stringLength;
- setValue(value);
- }
-
- public String encode() {
+ public void encode(BitStringBuilder builder) {
try {
- return FixedStringEncoder.encode(this.value, this.stringLength);
+ FixedStringEncoder.encode(builder, this.value, this.stringLength);
} catch (Exception e) {
throw new EncodingException(e);
}
}
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
this.value = FixedStringEncoder.decode(bitString);
} catch (Exception e) {
@@ -41,7 +37,7 @@ public void decode(String bitString) {
}
}
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
return bitString.substring(fromIndex, fromIndex + this.stringLength * 6);
} catch (Exception e) {
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFlexibleBitfield.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFlexibleBitfield.java
index cb1a0991..46337183 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFlexibleBitfield.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableFlexibleBitfield.java
@@ -1,42 +1,35 @@
package com.iab.gpp.encoder.datatype;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Collection;
import java.util.function.IntSupplier;
+
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
+import com.iab.gpp.encoder.datatype.encoder.IntegerBitSet;
import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder;
+import com.iab.gpp.encoder.datatype.encoder.IntegerSet;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableFlexibleBitfield extends AbstractEncodableBitStringDataType> {
+public final class EncodableFlexibleBitfield extends AbstractEncodableBitStringDataType {
private IntSupplier getLengthSupplier;
- protected EncodableFlexibleBitfield(IntSupplier getLengthSupplier) {
- super(true);
- this.getLengthSupplier = getLengthSupplier;
- }
-
- public EncodableFlexibleBitfield(IntSupplier getLengthSupplier, List value) {
+ public EncodableFlexibleBitfield(IntSupplier getLengthSupplier) {
super(true);
this.getLengthSupplier = getLengthSupplier;
- this.setValue(value);
+ this.value = new IntegerBitSet();
}
- public EncodableFlexibleBitfield(IntSupplier getLengthSupplier, List value, boolean hardFailIfMissing) {
- super(hardFailIfMissing);
- this.getLengthSupplier = getLengthSupplier;
- this.setValue(value);
- }
-
- public String encode() {
+ public void encode(BitStringBuilder builder) {
try {
- return FixedBitfieldEncoder.encode(this.value, this.getLengthSupplier.getAsInt());
+ FixedBitfieldEncoder.encode(builder, this.value, this.getLengthSupplier.getAsInt());
} catch (Exception e) {
throw new EncodingException(e);
}
}
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
this.value = FixedBitfieldEncoder.decode(bitString);
} catch (Exception e) {
@@ -44,7 +37,7 @@ public void decode(String bitString) {
}
}
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
return bitString.substring(fromIndex, fromIndex + this.getLengthSupplier.getAsInt());
} catch (Exception e) {
@@ -55,19 +48,12 @@ public String substring(String bitString, int fromIndex) throws SubstringExcepti
@SuppressWarnings("unchecked")
@Override
public void setValue(Object value) {
- int numElements = this.getLengthSupplier.getAsInt();
- List v = new ArrayList<>((List) value);
- for (int i = v.size(); i < numElements; i++) {
- v.add(false);
- }
- if (v.size() > numElements) {
- v = v.subList(0, numElements);
- }
- super.setValue(v);
+ this.value.clear();
+ this.value.addAll((Collection) value);
}
@Override
- public List getValue() {
- return new ArrayList<>(super.getValue());
+ public IntegerSet getValue() {
+ return new ManagedIntegerSet(this, super.getValue());
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFibonacciRange.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFibonacciRange.java
index 2e49855f..1aba7d88 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFibonacciRange.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFibonacciRange.java
@@ -1,14 +1,16 @@
package com.iab.gpp.encoder.datatype;
-import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
-import java.util.TreeSet;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder;
+import com.iab.gpp.encoder.datatype.encoder.IntegerSet;
import com.iab.gpp.encoder.datatype.encoder.OptimizedFibonacciRangeEncoder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableOptimizedFibonacciRange extends AbstractEncodableBitStringDataType> {
+public final class EncodableOptimizedFibonacciRange extends AbstractEncodableBitStringDataType {
protected EncodableOptimizedFibonacciRange() {
super(true);
@@ -24,15 +26,15 @@ public EncodableOptimizedFibonacciRange(List value, boolean hardFailIfM
setValue(value);
}
- public String encode() {
+ public void encode(BitStringBuilder builder) {
try {
- return OptimizedFibonacciRangeEncoder.encode(this.value);
+ OptimizedFibonacciRangeEncoder.encode(builder, this.value);
} catch (Exception e) {
throw new EncodingException(e);
}
}
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
this.value = OptimizedFibonacciRangeEncoder.decode(bitString);
} catch (Exception e) {
@@ -40,12 +42,14 @@ public void decode(String bitString) {
}
}
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
- int max = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 16));
- if (bitString.charAt(fromIndex + 16) == '1') {
- return (bitString.substring(fromIndex, fromIndex + 17)
- + new EncodableFibonacciIntegerRange().substring(bitString, fromIndex + 17));
+ int max = FixedIntegerEncoder.decode(bitString, fromIndex, 16);
+ if (bitString.getValue(fromIndex + 16)) {
+ BitStringBuilder out = new BitStringBuilder();
+ out.append(bitString.substring(fromIndex, fromIndex + 17));
+ out.append(new EncodableFibonacciIntegerRange().substring(bitString, fromIndex + 17));
+ return out.build();
} else {
return bitString.substring(fromIndex, fromIndex + 17 + max);
}
@@ -57,11 +61,12 @@ public String substring(String bitString, int fromIndex) throws SubstringExcepti
@SuppressWarnings("unchecked")
@Override
public void setValue(Object value) {
- super.setValue(new ArrayList<>(new TreeSet<>((List) value)));
+ this.value.clear();
+ this.value.addAll((Collection) value);
}
@Override
- public List getValue() {
- return new ArrayList<>(super.getValue());
+ public IntegerSet getValue() {
+ return new ManagedIntegerSet(this, super.getValue());
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRange.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRange.java
index 57f4b8e9..a0669607 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRange.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRange.java
@@ -1,39 +1,32 @@
package com.iab.gpp.encoder.datatype;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.TreeSet;
+import java.util.Collection;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
+import com.iab.gpp.encoder.datatype.encoder.IntegerBitSet;
import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder;
+import com.iab.gpp.encoder.datatype.encoder.IntegerSet;
import com.iab.gpp.encoder.datatype.encoder.OptimizedFixedRangeEncoder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
-public class EncodableOptimizedFixedRange extends AbstractEncodableBitStringDataType> {
+public final class EncodableOptimizedFixedRange extends AbstractEncodableBitStringDataType {
- protected EncodableOptimizedFixedRange() {
+ public EncodableOptimizedFixedRange() {
super(true);
+ this.value = new IntegerBitSet();
}
- public EncodableOptimizedFixedRange(List value) {
- super(true);
- setValue(value);
- }
-
- public EncodableOptimizedFixedRange(List value, boolean hardFailIfMissing) {
- super(hardFailIfMissing);
- setValue(value);
- }
-
- public String encode() {
+ public void encode(BitStringBuilder builder) {
try {
- return OptimizedFixedRangeEncoder.encode(this.value);
+ OptimizedFixedRangeEncoder.encode(builder, this.value);
} catch (Exception e) {
throw new EncodingException(e);
}
}
- public void decode(String bitString) {
+ public void decode(BitString bitString) {
try {
this.value = OptimizedFixedRangeEncoder.decode(bitString);
} catch (Exception e) {
@@ -41,12 +34,14 @@ public void decode(String bitString) {
}
}
- public String substring(String bitString, int fromIndex) throws SubstringException {
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
try {
- int max = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 16));
- if (bitString.charAt(fromIndex + 16) == '1') {
- return bitString.substring(fromIndex, fromIndex + 17)
- + new EncodableFixedIntegerRange().substring(bitString, fromIndex + 17);
+ int max = FixedIntegerEncoder.decode(bitString, fromIndex, 16);
+ if (bitString.getValue(fromIndex + 16)) {
+ BitStringBuilder out = new BitStringBuilder();
+ out.append(bitString.substring(fromIndex, fromIndex + 17));
+ out.append(new EncodableFixedIntegerRange().substring(bitString, fromIndex + 17));
+ return out.build();
} else {
return bitString.substring(fromIndex, fromIndex + 17 + max);
}
@@ -58,11 +53,12 @@ public String substring(String bitString, int fromIndex) throws SubstringExcepti
@SuppressWarnings("unchecked")
@Override
public void setValue(Object value) {
- super.setValue(new ArrayList<>(new TreeSet<>((List) value)));
+ this.value.clear();
+ this.value.addAll((Collection) value);
}
@Override
- public List getValue() {
- return new ArrayList<>(super.getValue());
+ public IntegerSet getValue() {
+ return new ManagedIntegerSet(this, super.getValue());
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/ManagedFixedList.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/ManagedFixedList.java
new file mode 100644
index 00000000..df38f67f
--- /dev/null
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/ManagedFixedList.java
@@ -0,0 +1,39 @@
+package com.iab.gpp.encoder.datatype;
+
+import java.util.AbstractList;
+import java.util.List;
+
+final class ManagedFixedList extends AbstractList {
+
+ private final DataType> parent;
+ private final List delegate;
+
+ ManagedFixedList(DataType> parent, List delegate) {
+ this.parent = parent;
+ this.delegate = delegate;
+ }
+
+ @Override
+ public int size() {
+ return delegate.size();
+ }
+
+ @Override
+ public T get(int index) {
+ return delegate.get(index);
+ }
+
+ @Override
+ public T set(int index, T value) {
+ T prior = delegate.set(index, value);
+ if (prior != null) {
+ parent.setDirty(true);
+ }
+ return prior;
+ }
+
+ @Override
+ public String toString() {
+ return delegate.toString();
+ }
+}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/ManagedIntegerSet.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/ManagedIntegerSet.java
new file mode 100644
index 00000000..daccfdb9
--- /dev/null
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/ManagedIntegerSet.java
@@ -0,0 +1,77 @@
+package com.iab.gpp.encoder.datatype;
+
+import java.util.PrimitiveIterator;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+import com.iab.gpp.encoder.datatype.encoder.BaseIntegerSet;
+import com.iab.gpp.encoder.datatype.encoder.IntegerSet;
+
+final class ManagedIntegerSet extends BaseIntegerSet {
+
+ private final DataType> parent;
+ private final IntegerSet delegate;
+
+ ManagedIntegerSet(DataType> parent, IntegerSet delegate) {
+ this.parent = parent;
+ this.delegate = delegate;
+ }
+
+ @Override
+ public void clear() {
+ delegate.clear();
+ parent.setDirty(true);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return delegate.isEmpty();
+ }
+
+ @Override
+ public int size() {
+ return delegate.size();
+ }
+
+ @Override
+ public PrimitiveIterator.OfInt iterator() {
+ return delegate.iterator();
+ }
+
+ @Override
+ public Stream stream(){
+ return delegate.stream();
+ }
+
+ @Override
+ public IntStream intStream() {
+ return delegate.intStream();
+ }
+
+ @Override
+ public boolean containsInt(int value) {
+ return delegate.containsInt(value);
+ }
+
+ @Override
+ public boolean addInt(int value) {
+ boolean modified = delegate.addInt(value);
+ if (modified) {
+ parent.setDirty(true);
+ }
+ return modified;
+ }
+
+ @Override
+ public boolean removeInt(int value) {
+ boolean modified = delegate.removeInt(value);
+ if (modified) {
+ parent.setDirty(true);
+ }
+ return modified;
+ }
+
+ @Override
+ public String toString() {
+ return delegate.toString();
+ }
+}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/RangeEntry.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/RangeEntry.java
index 0237ed18..5ea4bd7f 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/RangeEntry.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/RangeEntry.java
@@ -1,18 +1,22 @@
package com.iab.gpp.encoder.datatype;
-import java.util.List;
+import java.util.Collection;
+import java.util.Set;
+import com.iab.gpp.encoder.datatype.encoder.IntegerBitSet;
+import com.iab.gpp.encoder.datatype.encoder.IntegerSet;
public class RangeEntry {
private int key;
private int type;
- private List ids;
+ private final IntegerSet ids;
- public RangeEntry(int key, int type, List ids) {
+ public RangeEntry(int key, int type, Set ids) {
super();
this.key = key;
this.type = type;
- this.ids = ids;
+ this.ids = new IntegerBitSet();
+ this.ids.addAll(ids);
}
public int getKey() {
@@ -31,12 +35,13 @@ public void setType(int type) {
this.type = type;
}
- public List getIds() {
+ public IntegerSet getIds() {
return ids;
}
- public void setIds(List ids) {
- this.ids = ids;
+ public void setIds(Collection ids) {
+ this.ids.clear();
+ this.ids.addAll(ids);
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableBoolean.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableBoolean.java
new file mode 100644
index 00000000..3284a23b
--- /dev/null
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableBoolean.java
@@ -0,0 +1,28 @@
+package com.iab.gpp.encoder.datatype;
+
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
+
+public final class UnencodableBoolean extends AbstractEncodableBitStringDataType {
+
+ protected UnencodableBoolean() {
+ super(true);
+ }
+
+ public UnencodableBoolean(Boolean value) {
+ super(true);
+ setValue(value);
+ }
+
+ public void encode(BitStringBuilder builder){
+ // pass
+ }
+
+ public void decode(BitString bitString) {
+ // pass
+ }
+
+ public BitString substring(BitString bitString, int fromIndex) throws SubstringException {
+ return BitString.empty(0);
+ }
+}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableCharacter.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableCharacter.java
index 4ef9c256..4b1f84ee 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableCharacter.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableCharacter.java
@@ -3,15 +3,16 @@
import java.util.function.Predicate;
import com.iab.gpp.encoder.error.ValidationException;
-public class UnencodableCharacter implements DataType {
+public final class UnencodableCharacter implements DataType {
+ private boolean dirty = false;
private Predicate validator;
private Character value = null;
public UnencodableCharacter() {
this.validator = v -> true;
}
-
+
public UnencodableCharacter(Character value) {
this.validator = v -> true;
setValue(value);
@@ -25,7 +26,7 @@ public UnencodableCharacter(Character value, Predicate validator) {
public void setValidator(Predicate validator) {
this.validator = validator;
}
-
+
@Override
public boolean hasValue() {
return this.value != null;
@@ -41,9 +42,20 @@ public void setValue(Object value) {
Character c = (Character)value.toString().charAt(0);
if(validator.test(c)) {
this.value = c;
+ this.dirty = true;
} else {
throw new ValidationException("Invalid value '" + c + "'");
}
}
+ @Override
+ public boolean isDirty() {
+ return dirty;
+ }
+
+ @Override
+ public void setDirty(boolean dirty) {
+ this.dirty = dirty;
+ }
+
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableInteger.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableInteger.java
index 60dcddfd..1b40a247 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableInteger.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableInteger.java
@@ -3,15 +3,16 @@
import java.util.function.Predicate;
import com.iab.gpp.encoder.error.ValidationException;
-public class UnencodableInteger implements DataType {
+public final class UnencodableInteger implements DataType {
+ private boolean dirty;
private Predicate validator;
private Integer value = null;
public UnencodableInteger() {
this.validator = v -> true;
}
-
+
public UnencodableInteger(Integer value) {
this.validator = v -> true;
setValue(value);
@@ -25,7 +26,7 @@ public UnencodableInteger(Integer value, Predicate validator) {
public void setValidator(Predicate validator) {
this.validator = validator;
}
-
+
@Override
public boolean hasValue() {
return this.value != null;
@@ -41,9 +42,19 @@ public void setValue(Object value) {
Integer i = (Integer)value;
if(validator.test(i)) {
this.value = i;
+ this.dirty = true;
} else {
throw new ValidationException("Invalid value '" + i + "'");
}
}
+ @Override
+ public boolean isDirty() {
+ return dirty;
+ }
+
+ @Override
+ public void setDirty(boolean dirty) {
+ this.dirty = dirty;
+ }
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/ArrayOfRangesEntryEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/ArrayOfRangesEntryEncoder.java
deleted file mode 100644
index de1449b3..00000000
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/ArrayOfRangesEntryEncoder.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package com.iab.gpp.encoder.datatype.encoder;
-
-import java.util.regex.Pattern;
-import com.iab.gpp.encoder.error.DecodingException;
-
-public class ArrayOfRangesEntryEncoder {
-
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
-
- public static String encode(long value, int bitStringLength) {
- String bitString = "";
- while (value > 0) {
- if ((value & 1) == 1) {
- bitString = "1" + bitString;
- } else {
- bitString = "0" + bitString;
- }
- value = value >> 1;
- }
-
- while (bitString.length() < bitStringLength) {
- bitString = "0" + bitString;
- }
-
- return bitString;
- }
-
- public static long decode(String bitString) throws DecodingException {
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) {
- throw new DecodingException("Undecodable FixedLong '" + bitString + "'");
- }
-
- long value = 0;
-
- for (int i = 0; i < bitString.length(); i++) {
- if (bitString.charAt(bitString.length() - (i + 1)) == '1') {
- value += 1L << i;
- }
- }
-
- return value;
- }
-}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/BaseIntegerSet.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/BaseIntegerSet.java
new file mode 100644
index 00000000..bb872855
--- /dev/null
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/BaseIntegerSet.java
@@ -0,0 +1,56 @@
+package com.iab.gpp.encoder.datatype.encoder;
+
+import java.util.AbstractSet;
+import java.util.Collection;
+
+public abstract class BaseIntegerSet extends AbstractSet implements IntegerSet {
+
+ @Override
+ public final boolean contains(Object value) {
+ if (value instanceof Integer) {
+ return containsInt((Integer) value);
+ }
+ return false;
+ }
+
+ @Override
+ public final boolean add(Integer value) {
+ if (value == null) {
+ return false;
+ }
+ return addInt(value);
+ }
+
+ @Override
+ public final boolean remove(Object value) {
+ if (value instanceof Integer) {
+ return removeInt((Integer) value);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean removeAll(Collection> c) {
+ boolean modified = false;
+ for (Integer i : this) {
+ if (c.contains(i)) {
+ remove(i);
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+ @Override
+ public boolean retainAll(Collection> c) {
+ boolean modified = false;
+ for (Integer i : this) {
+ if (!c.contains(i)) {
+ remove(i);
+ modified = true;
+ }
+ }
+ return modified;
+ }
+
+}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoder.java
index 20e6cbd0..8787b4f9 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoder.java
@@ -1,26 +1,27 @@
package com.iab.gpp.encoder.datatype.encoder;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
public class BooleanEncoder {
- public static String encode(Boolean value) {
- if (value == true) {
- return "1";
- } else if (value == false) {
- return "0";
- } else {
+ private BooleanEncoder() {}
+ public static void encode(BitStringBuilder builder, Boolean value) {
+ if (value == null) {
throw new EncodingException("Unencodable Boolean '" + value + "'");
}
+ builder.append(value);
}
- public static boolean decode(String bitString) {
- if (bitString.equals("1")) {
- return true;
- } else if (bitString.equals("0")) {
- return false;
- } else {
+ public static boolean decode(BitString bitString) {
+ return decode(bitString, 0, bitString.length());
+ }
+
+ public static boolean decode(BitString bitString, int fromIndex, int length) {
+ if (length != 1) {
throw new DecodingException("Undecodable Boolean '" + bitString + "'");
}
+ return bitString.getValue(fromIndex);
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/DatetimeEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/DatetimeEncoder.java
index 77f6f344..ebc2462d 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/DatetimeEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/DatetimeEncoder.java
@@ -1,27 +1,28 @@
package com.iab.gpp.encoder.datatype.encoder;
import java.time.Instant;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.util.regex.Pattern;
+
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.error.DecodingException;
public class DatetimeEncoder {
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
- public static String encode(ZonedDateTime value) {
+ private DatetimeEncoder() {}
+
+ public static void encode(BitStringBuilder builder, Instant value) {
if (value != null) {
- return FixedLongEncoder.encode(value.toInstant().toEpochMilli() / 100, 36);
+ FixedLongEncoder.encode(builder, value.toEpochMilli() / 100, 36);
} else {
- return FixedLongEncoder.encode(0, 36);
+ FixedLongEncoder.encode(builder, 0, 36);
}
}
- public static ZonedDateTime decode(String bitString) throws DecodingException {
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches() || bitString.length() != 36) {
+ public static Instant decode(BitString bitString) throws DecodingException {
+ if (bitString.length() != 36) {
throw new DecodingException("Undecodable Datetime '" + bitString + "'");
}
- return ZonedDateTime.ofInstant(Instant.ofEpochMilli(FixedLongEncoder.decode(bitString) * 100L), ZoneId.of("UTC"));
+ return Instant.ofEpochMilli(FixedLongEncoder.decode(bitString) * 100L);
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FibonacciIntegerEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FibonacciIntegerEncoder.java
index 281b27da..d0f7948a 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FibonacciIntegerEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FibonacciIntegerEncoder.java
@@ -1,72 +1,94 @@
package com.iab.gpp.encoder.datatype.encoder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.error.DecodingException;
+import com.iab.gpp.encoder.error.EncodingException;
public class FibonacciIntegerEncoder {
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
+ private FibonacciIntegerEncoder() {}
- public static String encode(int value) {
- List fib = new ArrayList();
- if (value >= 1) {
- fib.add(1);
-
- if (value >= 2) {
- fib.add(2);
+ // this is the length of the longest fibonacci encoded string of all 1's
+ // which does not overflow a 32-bit integer
+ private static final int FIBONACCI_LIMIT = 42;
+ private static final int[] FIBONACCI_NUMBERS = new int[FIBONACCI_LIMIT];
+ static {
+ for (int i = 0; i < FIBONACCI_LIMIT; i++) {
+ if (i == 0) {
+ FIBONACCI_NUMBERS[i] = 1;
+ } else if (i == 1) {
+ FIBONACCI_NUMBERS[i] = 2;
+ } else {
+ FIBONACCI_NUMBERS[i] = FIBONACCI_NUMBERS[i - 1] + FIBONACCI_NUMBERS[i - 2];
+ }
+ }
+ }
- int i = 2;
- while (value >= fib.get(i - 1) + fib.get(i - 2)) {
- fib.add(fib.get(i - 1) + fib.get(i - 2));
- i++;
- }
+ public static void encode(BitStringBuilder builder, int value) {
+ int largestIndex = 0;
+ for (int i = 0; i < FIBONACCI_LIMIT; i++) {
+ if (value >= FIBONACCI_NUMBERS[i]) {
+ largestIndex++;
+ } else {
+ break;
}
}
+ if (largestIndex == FIBONACCI_LIMIT) {
+ throw new EncodingException("Unencodable FibonacciInteger " + value);
+ }
- String bitString = "1";
- for (int i = fib.size() - 1; i >= 0; i--) {
- int f = fib.get(i);
+ int out = 1;
+ int mask = 1;
+ for (int i = largestIndex - 1; i >= 0; i--) {
+ mask <<= 1;
+ int f = FIBONACCI_NUMBERS[i];
if (value >= f) {
- bitString = "1" + bitString;
+ out |= mask;
value -= f;
- } else {
- bitString = "0" + bitString;
}
}
+ FixedIntegerEncoder.encode(builder, out, largestIndex + 1);
+ }
- return bitString;
+ public static int decode(BitString bitString) throws DecodingException {
+ return decode(bitString, 0, bitString.length());
}
- public static int decode(String bitString) throws DecodingException {
- // enforce a length restriction to avoid overflows
- // 2^16 has a bit string length of 24
- if (bitString.length() > 24) {
- throw new DecodingException("FibonacciInteger too long");
- }
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches() || bitString.length() < 2
- || bitString.indexOf("11") != bitString.length() - 2) {
+ public static int decode(BitString bitString, int fromIndex, int length) throws DecodingException {
+ int limit = length - 1;
+ int end = fromIndex + length;
+ // must not overflow and must end with "11"
+ if (length < 2 || limit > FIBONACCI_LIMIT || !bitString.getValue(end - 2) || !bitString.getValue(end - 1)) {
throw new DecodingException("Undecodable FibonacciInteger '" + bitString + "'");
}
int value = 0;
-
- List fib = new ArrayList<>();
- for (int i = 0; i < bitString.length() - 1; i++) {
- if (i == 0) {
- fib.add(1);
- } else if (i == 1) {
- fib.add(2);
- } else {
- fib.add(fib.get(i - 1) + fib.get(i - 2));
+ for (int i = 0; i < limit; i++) {
+ if (bitString.getValue(fromIndex + i)) {
+ value += FIBONACCI_NUMBERS[i];
}
}
+ return value;
+ }
- for (int i = 0; i < bitString.length() - 1; i++) {
- if (bitString.charAt(i) == '1') {
- value += fib.get(i);
+ public static int indexOfEndTag(BitString bitString, int fromIndex) {
+ int limit = bitString.length() - 1;
+ int i = fromIndex;
+ while (i < limit) {
+ if (bitString.getValue(i)) {
+ // 1X
+ if (bitString.getValue(i + 1)) {
+ // 11
+ return i;
+ } else {
+ // 10, the next can be skipped
+ i += 2;
+ }
+ } else {
+ // 0, next
+ i++;
}
}
- return value;
+ return -1;
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FibonacciIntegerRangeEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FibonacciIntegerRangeEncoder.java
index daafa795..67958875 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FibonacciIntegerRangeEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FibonacciIntegerRangeEncoder.java
@@ -1,96 +1,83 @@
package com.iab.gpp.encoder.datatype.encoder;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.logging.Logger;
-import java.util.regex.Pattern;
+import java.util.Collection;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.error.DecodingException;
public class FibonacciIntegerRangeEncoder {
+ private FibonacciIntegerRangeEncoder() {}
- private static final Logger LOGGER = Logger.getLogger(FibonacciIntegerRangeEncoder.class.getName());
- // NOTE: This is a value roughly the 2x the size of this list
- // https://tools.iabtechlab.com/transparencycenter/explorer/business/gpp
- static final int MAX_SIZE = 8192;
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
-
- public static String encode(List value) {
- Collections.sort(value);
-
- List> groups = new ArrayList<>();
-
+ public static int encode(BitStringBuilder builder, Collection value) {
+ BitStringBuilder rangeBuilder = new BitStringBuilder();
+ int groupStart = -1;
+ int last = Integer.MIN_VALUE;
int offset = 0;
- int groupStartIndex = 0;
- while (groupStartIndex < value.size()) {
- int groupEndIndex = groupStartIndex;
- while (groupEndIndex < value.size() - 1 && value.get(groupEndIndex) + 1 == value.get(groupEndIndex + 1)) {
- groupEndIndex++;
+ int groupCount = 0;
+ for (Integer item : value) {
+ if (last != (item - 1)) {
+ if (groupStart > 0) {
+ groupCount++;
+ writeGroup(rangeBuilder, groupStart, last, offset);
+ offset = last;
+ }
+ groupStart = item;
}
-
- groups.add(value.subList(groupStartIndex, groupEndIndex + 1));
-
- groupStartIndex = groupEndIndex + 1;
+ last = item;
+ }
+ if (groupStart > 0) {
+ groupCount++;
+ writeGroup(rangeBuilder, groupStart, last, offset);
}
+ FixedIntegerEncoder.encode(builder,groupCount, 12);
+ builder.append(rangeBuilder);
+ return last;
+ }
- String bitString = FixedIntegerEncoder.encode(groups.size(), 12);
- for (int i = 0; i < groups.size(); i++) {
- if (groups.get(i).size() == 1) {
- int v = groups.get(i).get(0) - offset;
- offset = groups.get(i).get(0);
- bitString += "0" + FibonacciIntegerEncoder.encode(v);
- } else {
- int startVal = groups.get(i).get(0) - offset;
- offset = groups.get(i).get(0);
- int endVal = groups.get(i).get(groups.get(i).size() - 1) - offset;
- offset = groups.get(i).get(groups.get(i).size() - 1);
- bitString += "1" + FibonacciIntegerEncoder.encode(startVal) + FibonacciIntegerEncoder.encode(endVal);
- }
+ private static void writeGroup(BitStringBuilder builder, int groupStart, int last, int offset) {
+ int base = groupStart - offset;
+ int span = last - groupStart;
+ if (span == 0) {
+ builder.append(false);
+ FibonacciIntegerEncoder.encode(builder, base);
+ } else {
+ builder.append(true);
+ FibonacciIntegerEncoder.encode(builder, base);
+ FibonacciIntegerEncoder.encode(builder, span);
}
- return bitString;
}
- public static List decode(String bitString) throws DecodingException {
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches() || bitString.length() < 12) {
+ public static IntegerSet decode(BitString bitString) throws DecodingException {
+ if (bitString.length() < 12) {
throw new DecodingException("Undecodable FibonacciIntegerRange '" + bitString + "'");
}
- List value = new ArrayList<>();
- int count = FixedIntegerEncoder.decode(bitString.substring(0, 12));
+ int count = FixedIntegerEncoder.decode(bitString, 0, 12);
+ IntegerBitSet value = new IntegerBitSet();
int offset = 0;
int startIndex = 12;
for (int i = 0; i < count; i++) {
- boolean group = BooleanEncoder.decode(bitString.substring(startIndex, startIndex + 1));
+ boolean group = BooleanEncoder.decode(bitString, startIndex, 1);
startIndex++;
- if (group == true) {
- int index = bitString.indexOf("11", startIndex);
- int start = FibonacciIntegerEncoder.decode(bitString.substring(startIndex, index + 2)) + offset;
+ if (group) {
+ int index = FibonacciIntegerEncoder.indexOfEndTag(bitString, startIndex);
+ int start = FibonacciIntegerEncoder.decode(bitString, startIndex, index + 2 - startIndex) + offset;
offset = start;
startIndex = index + 2;
- index = bitString.indexOf("11", startIndex);
- int end = FibonacciIntegerEncoder.decode(bitString.substring(startIndex, index + 2)) + offset;
+ index = FibonacciIntegerEncoder.indexOfEndTag(bitString, startIndex);
+ int end = FibonacciIntegerEncoder.decode(bitString, startIndex, index + 2 - startIndex) + offset;
offset = end;
startIndex = index + 2;
- if (value.size() + (end - start) > MAX_SIZE) {
- LOGGER.warning("FibonacciIntegerRange has too many values");
- break;
- }
- for (int j = start; j <= end; j++) {
- value.add(j);
- }
+ value.addRange(start, end + 1);
} else {
- int index = bitString.indexOf("11", startIndex);
- int val = FibonacciIntegerEncoder.decode(bitString.substring(startIndex, index + 2)) + offset;
+ int index = FibonacciIntegerEncoder.indexOfEndTag(bitString, startIndex);
+ int val = FibonacciIntegerEncoder.decode(bitString, startIndex, index + 2 - startIndex) + offset;
offset = val;
- if (value.size() == MAX_SIZE) {
- LOGGER.warning("FibonacciIntegerRange has too many values");
- break;
- }
- value.add(val);
+ value.addInt(val);
startIndex = index + 2;
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoder.java
index 6c922263..5a59decd 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoder.java
@@ -1,41 +1,18 @@
package com.iab.gpp.encoder.datatype.encoder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
-import com.iab.gpp.encoder.error.DecodingException;
-import com.iab.gpp.encoder.error.EncodingException;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
public class FixedBitfieldEncoder {
+ private FixedBitfieldEncoder() {}
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
-
- public static String encode(List value, int bitStringLength) {
- if (value.size() > bitStringLength) {
- throw new EncodingException("Too many values '" + value.size() + "'");
- }
-
- String bitString = "";
- for (int i = 0; i < value.size(); i++) {
- bitString += BooleanEncoder.encode(value.get(i));
- }
-
- while (bitString.length() < bitStringLength) {
- bitString += "0";
+ public static void encode(BitStringBuilder builder, IntegerSet value, int bitStringLength) {
+ for (int i = 0; i < bitStringLength; i++) {
+ BooleanEncoder.encode(builder, value.containsInt(i));
}
-
- return bitString;
}
- public static List decode(String bitString) {
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) {
- throw new DecodingException("Undecodable FixedBitfield '" + bitString + "'");
- }
-
- List value = new ArrayList<>();
- for (int i = 0; i < bitString.length(); i++) {
- value.add(BooleanEncoder.decode(bitString.substring(i, i + 1)));
- }
- return value;
+ public static IntegerSet decode(BitString bitString) {
+ return bitString.toIntegerSet();
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoder.java
index dfc6802f..6b7105ed 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoder.java
@@ -1,47 +1,52 @@
package com.iab.gpp.encoder.datatype.encoder;
-import java.util.regex.Pattern;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
public class FixedIntegerEncoder {
+ private FixedIntegerEncoder() {}
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
-
- public static String encode(int value, int bitStringLength) {
- // let bitString = value.toString(2);
-
- String bitString = "";
- while (value > 0) {
- if ((value & 1) == 1) {
- bitString = "1" + bitString;
- } else {
- bitString = "0" + bitString;
- }
- value = value >> 1;
- }
-
- if (bitString.length() > bitStringLength) {
+ public static void encode(BitStringBuilder builder, int value, int bitStringLength) {
+ int mask = 1 << bitStringLength;
+ if (value >= mask) {
throw new EncodingException(
- "Numeric value '" + value + "' is too large for a bit string length of '" + bitStringLength + "'");
+ "Numeric value '" + value + "' is too large for a bit string length of '" + bitStringLength + "'");
}
-
- while (bitString.length() < bitStringLength) {
- bitString = "0" + bitString;
+ for (int i = 0; i < bitStringLength; i++) {
+ mask >>= 1;
+ builder.append((value & mask) > 0);
}
+ }
- return bitString;
+ public static int decode(BitString bitString) throws DecodingException {
+ return decode(bitString, 0, bitString.length());
}
- public static int decode(String bitString) throws DecodingException {
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) {
- throw new DecodingException("Undecodable FixedInteger '" + bitString + "'");
+ public static int decode(BitString bitString, int fromIndex, int length) throws DecodingException {
+ int value = 0;
+
+ int base = fromIndex + length - 1;
+ for (int i = 0; i < length; i++) {
+ if (bitString.getValue(base - i)) {
+ value += 1 << i;
+ }
}
+
+ return value;
+ }
+
+ public static int decode(String bitString, int fromIndex, int length) throws DecodingException {
int value = 0;
- for (int i = 0; i < bitString.length(); i++) {
- if (bitString.charAt(bitString.length() - (i + 1)) == '1') {
+ int base = fromIndex + length - 1;
+ for (int i = 0; i < length; i++) {
+ char c = bitString.charAt(base - i);
+ if (c == BitString.TRUE) {
value += 1 << i;
+ } else if (c != BitString.FALSE) {
+ throw new DecodingException("Unencodable Base64Url '" + bitString + "'");
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoder.java
index 044dfe26..7140af9c 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoder.java
@@ -2,56 +2,49 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.regex.Pattern;
+
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
public class FixedIntegerListEncoder {
+ private FixedIntegerListEncoder() {}
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
-
- public static String encode(List value, int elementBitStringLength, int numElements) {
- if(value.size() > numElements) {
+ public static void encode(BitStringBuilder builder, List value, int elementBitStringLength, int numElements) {
+ int length = value.size();
+ if (length > numElements) {
throw new EncodingException("Too many values '" + value.size() + "'");
}
-
- String bitString = "";
- for (int i = 0; i < value.size(); i++) {
- bitString += FixedIntegerEncoder.encode(value.get(i), elementBitStringLength);
- }
- while (bitString.length() < elementBitStringLength * numElements) {
- bitString += "0";
+ for (int i = 0; i < numElements; i++) {
+ if (i < length) {
+ FixedIntegerEncoder.encode(builder, value.get(i), elementBitStringLength);
+ } else {
+ for (int j = 0; j < elementBitStringLength; j++) {
+ builder.append(false);
+ }
+ }
}
-
- return bitString;
}
- public static List decode(String bitString, int elementBitStringLength, int numElements)
+ public static List decode(BitString bitString, int elementBitStringLength, int numElements)
throws DecodingException {
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) {
- throw new DecodingException("Undecodable FixedIntegerList '" + bitString + "'");
- }
-
- if (bitString.length() > elementBitStringLength * numElements) {
+ int length = bitString.length();
+ if (length > elementBitStringLength * numElements) {
throw new DecodingException("Undecodable FixedIntegerList '" + bitString + "'");
}
- if (bitString.length() % elementBitStringLength != 0) {
+ if (length % elementBitStringLength != 0) {
throw new DecodingException("Undecodable FixedIntegerList '" + bitString + "'");
}
- while (bitString.length() < elementBitStringLength * numElements) {
- bitString += "0";
- }
-
- if (bitString.length() > elementBitStringLength * numElements) {
- bitString = bitString.substring(0, elementBitStringLength * numElements);
- }
+ bitString = bitString.expandTo(elementBitStringLength * numElements);
- List value = new ArrayList<>();
- for (int i = 0; i < bitString.length(); i += elementBitStringLength) {
- value.add(FixedIntegerEncoder.decode(bitString.substring(i, i + elementBitStringLength)));
+ List value = new ArrayList<>(numElements);
+ length = bitString.length();
+ for (int i = 0; i < length; i += elementBitStringLength) {
+ value.add(IntegerCache.valueOf(FixedIntegerEncoder.decode(bitString, i, elementBitStringLength)));
}
while (value.size() < numElements) {
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerRangeEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerRangeEncoder.java
index 335952bf..a92e2b09 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerRangeEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerRangeEncoder.java
@@ -1,85 +1,71 @@
package com.iab.gpp.encoder.datatype.encoder;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.logging.Logger;
-import java.util.regex.Pattern;
+import java.util.Collection;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.error.DecodingException;
public class FixedIntegerRangeEncoder {
+ private FixedIntegerRangeEncoder() {}
- private static final Logger LOGGER = Logger.getLogger(FixedIntegerRangeEncoder.class.getName());
- // NOTE: This is a value roughly the 2x the size of this list
- // https://tools.iabtechlab.com/transparencycenter/explorer/business/gpp
- private static final int MAX_SIZE = 8192;
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
-
- public static String encode(List value) {
- Collections.sort(value);
-
- List> groups = new ArrayList<>();
-
- int groupStartIndex = 0;
- while (groupStartIndex < value.size()) {
- int groupEndIndex = groupStartIndex;
- while (groupEndIndex < value.size() - 1 && value.get(groupEndIndex) + 1 == value.get(groupEndIndex + 1)) {
- groupEndIndex++;
+ public static int encode(BitStringBuilder builder, Collection value) {
+ BitStringBuilder rangeBuilder = new BitStringBuilder();
+ int groupStart = -1;
+ int last = Integer.MIN_VALUE;
+ int groupCount = 0;
+ for (Integer item : value) {
+ if (last != (item - 1)) {
+ if (groupStart > 0) {
+ groupCount++;
+ writeGroup(rangeBuilder, groupStart, last);
+ }
+ groupStart = item;
}
-
- groups.add(value.subList(groupStartIndex, groupEndIndex + 1));
-
- groupStartIndex = groupEndIndex + 1;
+ last = item;
+ }
+ if (groupStart > 0) {
+ groupCount++;
+ writeGroup(rangeBuilder, groupStart, last);
}
+ FixedIntegerEncoder.encode(builder,groupCount, 12);
+ builder.append(rangeBuilder);
+ return last;
+ }
- String bitString = FixedIntegerEncoder.encode(groups.size(), 12);
- for (int i = 0; i < groups.size(); i++) {
- if (groups.get(i).size() == 1) {
- bitString += "0" + FixedIntegerEncoder.encode(groups.get(i).get(0), 16);
- } else {
- bitString += "1" + FixedIntegerEncoder.encode(groups.get(i).get(0), 16)
- + FixedIntegerEncoder.encode(groups.get(i).get(groups.get(i).size() - 1), 16);
- }
+ private static void writeGroup(BitStringBuilder builder, int groupStart, int last) {
+ if (groupStart == last) {
+ builder.append(false);
+ FixedIntegerEncoder.encode(builder, groupStart, 16);
+ } else {
+ builder.append(true);
+ FixedIntegerEncoder.encode(builder, groupStart, 16);
+ FixedIntegerEncoder.encode(builder, last, 16);
}
- return bitString;
}
- public static List decode(String bitString) throws DecodingException {
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches() || bitString.length() < 12) {
+ public static IntegerSet decode(BitString bitString) throws DecodingException {
+ if (bitString.length() < 12) {
throw new DecodingException("Undecodable FixedIntegerRange '" + bitString + "'");
}
- List value = new ArrayList<>();
- int count = FixedIntegerEncoder.decode(bitString.substring(0, 12));
+ int count = FixedIntegerEncoder.decode(bitString, 0, 12);
+ IntegerBitSet value = new IntegerBitSet();
int startIndex = 12;
for (int i = 0; i < count; i++) {
- boolean group = BooleanEncoder.decode(bitString.substring(startIndex, startIndex + 1));
+ boolean group = BooleanEncoder.decode(bitString, startIndex, 1);
startIndex++;
- if (group == true) {
- int start = FixedIntegerEncoder.decode(bitString.substring(startIndex, startIndex + 16));
+ if (group) {
+ int start = FixedIntegerEncoder.decode(bitString, startIndex, 16);
startIndex += 16;
- int end = FixedIntegerEncoder.decode(bitString.substring(startIndex, startIndex + 16));
+ int end = FixedIntegerEncoder.decode(bitString, startIndex, 16);
startIndex += 16;
- if (end < start) {
- throw new DecodingException("FixedIntegerRange has invalid range");
- }
- if (value.size() + (end - start) > MAX_SIZE) {
- LOGGER.warning("FixedIntegerRange has too many values");
- break;
- }
- for (int j = start; j <= end; j++) {
- value.add(j);
- }
+ value.addRange(start, end + 1);
} else {
- int val = FixedIntegerEncoder.decode(bitString.substring(startIndex, startIndex + 16));
- if (value.size() == MAX_SIZE) {
- LOGGER.warning("FixedIntegerRange has too many values");
- break;
- }
- value.add(val);
+ int val = FixedIntegerEncoder.decode(bitString, startIndex, 16);
+ value.addInt(val);
startIndex += 16;
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoder.java
index c244a601..9f0dba27 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoder.java
@@ -1,45 +1,31 @@
package com.iab.gpp.encoder.datatype.encoder;
-import java.util.regex.Pattern;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
public class FixedLongEncoder {
+ private FixedLongEncoder() {}
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
-
- public static String encode(long value, int bitStringLength) {
- String bitString = "";
- while (value > 0) {
- if ((value & 1) == 1) {
- bitString = "1" + bitString;
- } else {
- bitString = "0" + bitString;
- }
- value = value >> 1;
- }
-
- if (bitString.length() > bitStringLength) {
+ public static void encode(BitStringBuilder builder, long value, int bitStringLength) {
+ long mask = 1L << bitStringLength;
+ if (value >= mask) {
throw new EncodingException(
- "Numeric value '" + value + "' is too large for a bit string length of '" + bitStringLength + "'");
+ "Numeric value '" + value + "' is too large for a bit string length of '" + bitStringLength + "'");
}
-
- while (bitString.length() < bitStringLength) {
- bitString = "0" + bitString;
+ for (int i = 0; i < bitStringLength; i++) {
+ mask >>= 1;
+ builder.append((value & mask) > 0);
}
-
- return bitString;
}
- public static long decode(String bitString) throws DecodingException {
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) {
- throw new DecodingException("Undecodable FixedLong '" + bitString + "'");
- }
-
+ public static long decode(BitString bitString) throws DecodingException {
long value = 0;
- for (int i = 0; i < bitString.length(); i++) {
- if (bitString.charAt(bitString.length() - (i + 1)) == '1') {
+ int length = bitString.length();
+ for (int i = 0; i < length; i++) {
+ if (bitString.getValue(length - (i + 1))) {
value += 1L << i;
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoder.java
index 38db681e..8c7784d0 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoder.java
@@ -1,50 +1,48 @@
package com.iab.gpp.encoder.datatype.encoder;
-import java.util.regex.Pattern;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
public class FixedStringEncoder {
-
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
-
- public static String encode(String value, int stringLength) {
- while (value.length() < stringLength) {
- value += " ";
- }
-
- String bitString = "";
- for (int i = 0; i < value.length(); i++) {
- int code = (int) value.charAt(i);
- if (code == 32) {
- // space
- bitString += FixedIntegerEncoder.encode(63, 6);
+ private FixedStringEncoder() {}
+ private static final char SPACE = ' ';
+
+ public static void encode(BitStringBuilder builder, String value, int stringLength) {
+ int length = value.length();
+ for (int i = 0; i < stringLength; i++) {
+ int code = SPACE;
+ if (i < length) {
+ code = value.charAt(i);
+ }
+ if (code == SPACE) {
+ FixedIntegerEncoder.encode(builder, 63, 6);
} else if (code >= 65) {
- bitString += FixedIntegerEncoder.encode(((int) value.charAt(i)) - 65, 6);
+ FixedIntegerEncoder.encode(builder, ((int) value.charAt(i)) - 65, 6);
} else {
throw new EncodingException("Unencodable FixedString '" + value + "'");
}
}
-
- return bitString;
}
- public static String decode(String bitString) {
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches() || bitString.length() % 6 != 0) {
+ public static String decode(BitString bitString) {
+ int length = bitString.length();
+ if (length % 6 != 0) {
throw new DecodingException("Undecodable FixedString '" + bitString + "'");
}
- String value = "";
+ StringBuilder value = new StringBuilder(length);
- for (int i = 0; i < bitString.length(); i += 6) {
- int code = FixedIntegerEncoder.decode(bitString.substring(i, i + 6));
+ for (int i = 0; i < length; i += 6) {
+ int code = FixedIntegerEncoder.decode(bitString, i, 6);
if (code == 63) {
- value += " ";
+ value.append(SPACE);
} else {
- value += (char) (code + 65);
+ value.append((char) (code + 65));
}
}
- return value.trim();
+ return value.toString().trim();
}
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/IntegerBitSet.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/IntegerBitSet.java
new file mode 100644
index 00000000..7ff3483d
--- /dev/null
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/IntegerBitSet.java
@@ -0,0 +1,159 @@
+package com.iab.gpp.encoder.datatype.encoder;
+
+import java.util.BitSet;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.logging.Logger;
+import java.util.PrimitiveIterator.OfInt;
+import java.util.stream.IntStream;
+import java.util.stream.StreamSupport;
+
+public final class IntegerBitSet extends BaseIntegerSet {
+ private static final Logger LOGGER = Logger.getLogger(IntegerBitSet.class.getName());
+
+ static final int MAX_COLLECTION_SIZE = 8192;
+
+ protected final BitSet bitSet;
+ protected final int from;
+ protected final int to;
+ private final int adjustment;
+
+ public IntegerBitSet(BitSet bitSet, int from, int to, int adjustment) {
+ this.bitSet = bitSet;
+ this.from = from;
+ this.to = to;
+ this.adjustment = adjustment;
+ }
+
+ public IntegerBitSet(int limit) {
+ this(new BitSet(0), 0, limit, 0);
+ }
+
+ public IntegerBitSet() {
+ this(MAX_COLLECTION_SIZE);
+ }
+
+ @Override
+ public int size() {
+ OfInt it = iterator();
+ int count = 0;
+ while (it.hasNext()) {
+ it.next();
+ count++;
+ }
+ return count;
+ }
+
+ private int getOffset(int value) {
+ int offset = from - adjustment + value;
+ if (offset < from) {
+ throw new IndexOutOfBoundsException("Negative index provided");
+ }
+ return offset;
+ }
+
+ @Override
+ public void clear() {
+ bitSet.clear(from, to);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return bitSet.nextSetBit(from) == -1;
+ }
+
+ @Override
+ public boolean containsInt(int value) {
+ int offset = getOffset(value);
+ return offset < to && bitSet.get(offset);
+ }
+
+ @Override
+ public OfInt iterator() {
+ return new OfInt() {
+ int cursor = bitSet.nextSetBit(from);
+
+ @Override
+ public boolean hasNext() {
+ return cursor < to && cursor != -1;
+ }
+
+ @Override
+ public Integer next() {
+ return IntegerCache.valueOf(nextInt());
+ }
+
+ @Override
+ public int nextInt() {
+ if (!this.hasNext()) {
+ throw new NoSuchElementException();
+ }
+ int next = cursor;
+ cursor = bitSet.nextSetBit(cursor + 1);
+ return next - from + adjustment;
+ }
+ };
+ }
+
+ @Override
+ public Spliterator.OfInt spliterator(){
+ return Spliterators.spliteratorUnknownSize(
+ iterator(),
+ Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.IMMUTABLE | Spliterator.NONNULL);
+ }
+
+ @Override
+ public IntStream intStream() {
+ return StreamSupport.intStream(spliterator(), false);
+ }
+
+ private static final void logOutOfRange(int value) {
+ LOGGER.warning("Exceeding IntegerBitSet.MAX_COLLECTION_SIZE: "+ value);
+ }
+
+ public void addRange(int start, int end) {
+ if (end < start) {
+ throw new IllegalArgumentException("Negative length range");
+ }
+ int realStart = getOffset(start);
+ int realEnd = getOffset(end);
+ if (realStart >= to) {
+ logOutOfRange(start);
+ return;
+ }
+ if (realEnd > to) {
+ logOutOfRange(end);
+ realEnd = to;
+ }
+ bitSet.set(realStart, realEnd);
+ }
+
+ public boolean addInt(int value) {
+ int offset = getOffset(value);
+ if (offset >= to) {
+ logOutOfRange(value);
+ return false;
+ }
+ boolean present = bitSet.get(offset);
+ if (present) {
+ return false;
+ }
+ bitSet.set(offset, true);
+ return true;
+ }
+
+ public boolean removeInt(int value) {
+ int offset = getOffset(value);
+ if (offset >= to) {
+ logOutOfRange(value);
+ return false;
+ }
+ boolean present = bitSet.get(offset);
+ if (!present) {
+ return false;
+ }
+ bitSet.set(offset, false);
+ return true;
+ }
+}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/IntegerCache.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/IntegerCache.java
new file mode 100644
index 00000000..d92823e5
--- /dev/null
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/IntegerCache.java
@@ -0,0 +1,21 @@
+package com.iab.gpp.encoder.datatype.encoder;
+
+import static com.iab.gpp.encoder.datatype.encoder.IntegerBitSet.MAX_COLLECTION_SIZE;
+
+final class IntegerCache {
+ private IntegerCache() {}
+ private static final Integer[] CACHE = new Integer[MAX_COLLECTION_SIZE];
+ static {
+ for (int i = 0; i < MAX_COLLECTION_SIZE; i++) {
+ CACHE[i] = i;
+ }
+ }
+
+ static Integer valueOf(int i) {
+ if (i >=0 && i < MAX_COLLECTION_SIZE) {
+ return CACHE[i];
+ }
+ return i;
+ }
+
+}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/IntegerSet.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/IntegerSet.java
new file mode 100644
index 00000000..bc9aa3f7
--- /dev/null
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/IntegerSet.java
@@ -0,0 +1,28 @@
+package com.iab.gpp.encoder.datatype.encoder;
+
+import java.util.Collection;
+import java.util.PrimitiveIterator;
+import java.util.Set;
+import java.util.stream.IntStream;
+
+public interface IntegerSet extends Set {
+ boolean containsInt(int value);
+
+ default boolean containsAny(Collection> c) {
+ for (Object e : c) {
+ if (!contains(e)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ boolean addInt(int value);
+
+ boolean removeInt(int value);
+
+ IntStream intStream();
+
+ @Override
+ PrimitiveIterator.OfInt iterator();
+}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFibonacciRangeEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFibonacciRangeEncoder.java
index 3492fbcc..66160efd 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFibonacciRangeEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFibonacciRangeEncoder.java
@@ -1,53 +1,47 @@
package com.iab.gpp.encoder.datatype.encoder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
public class OptimizedFibonacciRangeEncoder {
+ private OptimizedFibonacciRangeEncoder() {}
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
-
- public static String encode(List value) throws EncodingException {
+ public static void encode(BitStringBuilder builder, IntegerSet value) throws EncodingException {
// TODO: encoding the range before choosing the shortest is inefficient. There is probably a way
// to identify in advance which will be shorter based on the array length and values
- int max = value.size() > 0 ? value.get(value.size() - 1) : 0;
- String rangeBitString = FibonacciIntegerRangeEncoder.encode(value);
+ BitStringBuilder rangeBitString = new BitStringBuilder();
+ int max = FibonacciIntegerRangeEncoder.encode(rangeBitString, value);
int rangeLength = rangeBitString.length();
int bitFieldLength = max;
if (rangeLength <= bitFieldLength) {
- return FixedIntegerEncoder.encode(max, 16) + "1" + rangeBitString;
+ FixedIntegerEncoder.encode(builder, max, 16);
+ builder.append(true).append(rangeBitString);
} else {
- List bits = new ArrayList<>();
- int index = 0;
+ FixedIntegerEncoder.encode(builder, max, 16);
+ builder.append(false);
for (int i = 0; i < max; i++) {
- if (i == value.get(index) - 1) {
- bits.add(true);
- index++;
- } else {
- bits.add(false);
- }
+ builder.append(value.contains(i + 1));
}
- return FixedIntegerEncoder.encode(max, 16) + "0" + FixedBitfieldEncoder.encode(bits, bitFieldLength);
}
}
- public static List decode(String bitString) throws DecodingException {
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches() || bitString.length() < 12) {
+ public static IntegerSet decode(BitString bitString) throws DecodingException {
+ if (bitString.length() < 12) {
throw new DecodingException("Undecodable FibonacciIntegerRange '" + bitString + "'");
}
- if (bitString.charAt(16) == '1') {
+ if (bitString.getValue(16)) {
return FibonacciIntegerRangeEncoder.decode(bitString.substring(17));
} else {
- List value = new ArrayList<>();
- List bits = FixedBitfieldEncoder.decode(bitString.substring(17));
- for (int i = 0; i < bits.size(); i++) {
- if (bits.get(i) == true) {
- value.add(i + 1);
+ BitString bits = bitString.substring(17);
+ int length = bits.length();
+ IntegerBitSet value = new IntegerBitSet();
+ for (int i = 0; i < length; i++) {
+ if (bits.getValue(i)) {
+ value.addInt(i + 1);
}
}
return value;
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFixedRangeEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFixedRangeEncoder.java
index 73fb5e68..5a5660f8 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFixedRangeEncoder.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFixedRangeEncoder.java
@@ -1,54 +1,46 @@
package com.iab.gpp.encoder.datatype.encoder;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Pattern;
+import com.iab.gpp.encoder.bitstring.BitString;
+import com.iab.gpp.encoder.bitstring.BitStringBuilder;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.EncodingException;
public class OptimizedFixedRangeEncoder {
- private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE);
-
- public static String encode(List value) throws EncodingException {
+ public static void encode(BitStringBuilder builder, IntegerSet value) throws EncodingException {
// TODO: encoding the range before choosing the shortest is inefficient. There is probably a way
// to identify in advance which will be shorter based on the array length and values
- int max = value.size() > 0 ? value.get(value.size() - 1) : 0;
- String rangeBitString = FixedIntegerRangeEncoder.encode(value);
+ BitStringBuilder rangeBitString = new BitStringBuilder();
+ int max = FixedIntegerRangeEncoder.encode(rangeBitString, value);
int rangeLength = rangeBitString.length();
int bitFieldLength = max;
if (rangeLength <= bitFieldLength) {
- return FixedIntegerEncoder.encode(max, 16) + "1" + rangeBitString;
+ FixedIntegerEncoder.encode(builder, max, 16);
+ builder.append(true).append(rangeBitString);
} else {
- List bits = new ArrayList<>();
- int index = 0;
+ FixedIntegerEncoder.encode(builder, max, 16);
+ builder.append(false);
for (int i = 0; i < max; i++) {
- if (i == value.get(index) - 1) {
- bits.add(true);
- index++;
- } else {
- bits.add(false);
- }
+ builder.append(value.containsInt(i + 1));
}
-
- return FixedIntegerEncoder.encode(max, 16) + "0" + FixedBitfieldEncoder.encode(bits, bitFieldLength);
}
}
- public static List decode(String bitString) throws DecodingException {
- if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches() || bitString.length() < 12) {
+ public static IntegerSet decode(BitString bitString) throws DecodingException {
+ if (bitString.length() < 12) {
throw new DecodingException("Undecodable FixedIntegerRange '" + bitString + "'");
}
- if (bitString.charAt(16) == '1') {
+ if (bitString.getValue(16)) {
return FixedIntegerRangeEncoder.decode(bitString.substring(17));
} else {
- List value = new ArrayList<>();
- List bits = FixedBitfieldEncoder.decode(bitString.substring(17));
- for (int i = 0; i < bits.size(); i++) {
- if (bits.get(i) == true) {
- value.add(i + 1);
+ BitString bits = bitString.substring(17);
+ int length = bits.length();
+ IntegerBitSet value = new IntegerBitSet();
+ for (int i = 0; i < length; i++) {
+ if (bits.getValue(i)) {
+ value.addInt(i + 1);
}
}
return value;
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/EncodableBitStringFields.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/EncodableBitStringFields.java
index d2ac0f43..e90c6f2e 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/EncodableBitStringFields.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/EncodableBitStringFields.java
@@ -1,31 +1,11 @@
package com.iab.gpp.encoder.field;
-import java.util.HashMap;
-import java.util.Map;
import com.iab.gpp.encoder.datatype.AbstractEncodableBitStringDataType;
-public class EncodableBitStringFields implements Fields> {
+public final class EncodableBitStringFields extends Fields> {
- private Map> fields = new HashMap<>();
-
- public boolean containsKey(String key) {
- return this.fields.containsKey(key);
- }
-
- public void put(String key, AbstractEncodableBitStringDataType> value) {
- this.fields.put(key, value);
- }
-
- public AbstractEncodableBitStringDataType> get(String key) {
- return this.fields.get(key);
- }
-
- public Map> getAll() {
- return new HashMap<>(this.fields);
+ public EncodableBitStringFields(FieldNames fieldNames) {
+ super(fieldNames);
}
- public void reset(Fields> fields) {
- this.fields.clear();
- this.fields.putAll(fields.getAll());
- }
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/FieldNames.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/FieldNames.java
new file mode 100644
index 00000000..b62037e6
--- /dev/null
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/FieldNames.java
@@ -0,0 +1,36 @@
+package com.iab.gpp.encoder.field;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public final class FieldNames {
+
+ private final List list;
+ private final Map map;
+
+ FieldNames(String... names) {
+ this.list = Collections.unmodifiableList(Arrays.asList(names));
+ this.map = new LinkedHashMap<>();
+ for (int i = 0; i < names.length; i++) {
+ this.map.put(names[i], i);
+ }
+ }
+
+ public boolean contains(String name) {
+ return map.containsKey(name);
+ }
+
+ static final FieldNames of(String... names) {
+ return new FieldNames(names);
+ }
+
+ public List getNames() {
+ return list;
+ }
+ public Integer convertKey(String key) {
+ return map.get(key);
+ }
+}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/Fields.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/Fields.java
index ca091e7f..107b5138 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/Fields.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/Fields.java
@@ -1,14 +1,71 @@
package com.iab.gpp.encoder.field;
-import java.util.Map;
+import java.util.List;
import com.iab.gpp.encoder.datatype.DataType;
-public interface Fields> {
+public abstract class Fields> {
- boolean containsKey(String key);
- void put(String key, T value);
- T get(String key);
- Map getAll();
- void reset(Fields fields);
+ private final FieldNames fieldNames;
+ private final Object[] values;
+ protected Fields(FieldNames fieldNames) {
+ this.fieldNames = fieldNames;
+ this.values = new Object[fieldNames.getNames().size()];
+ }
+
+ public List getNames() {
+ return fieldNames.getNames();
+ }
+
+ public boolean containsKey(String key) {
+ Integer index = fieldNames.convertKey(key);
+ return index != null && values[index] != null;
+ }
+
+ public void put(String key, T value) {
+ Integer index = fieldNames.convertKey(key);
+ if (index != null) {
+ values[index] = value;
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public T get(int index) {
+ return (T) values[index];
+ }
+
+ public T get(String key) {
+ Integer index = fieldNames.convertKey(key);
+ if (index != null) {
+ return get(index);
+ }
+ return null;
+ }
+
+ public void reset(Fields fields) {
+ for (String name : fieldNames.getNames()) {
+ put(name, fields.get(name));
+ }
+ }
+
+ public boolean isDirty() {
+ int size = getNames().size();
+ for (int i = 0; i < size; i++) {
+ T value = get(i);
+ if (value != null && value.isDirty()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void markClean() {
+ int size = getNames().size();
+ for (int i = 0; i < size; i++) {
+ T value = get(i);
+ if (value != null) {
+ value.setDirty(false);
+ }
+ }
+ }
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/GenericFields.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/GenericFields.java
index 00263e55..c644f333 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/GenericFields.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/GenericFields.java
@@ -1,31 +1,11 @@
package com.iab.gpp.encoder.field;
-import java.util.HashMap;
-import java.util.Map;
import com.iab.gpp.encoder.datatype.DataType;
-public class GenericFields implements Fields> {
+public final class GenericFields extends Fields> {
- private Map> fields = new HashMap<>();
-
- public boolean containsKey(String key) {
- return this.fields.containsKey(key);
- }
-
- public void put(String key, DataType> value) {
- this.fields.put(key, value);
- }
-
- public DataType> get(String key) {
- return this.fields.get(key);
- }
-
- public Map> getAll() {
- return new HashMap<>(this.fields);
+ public GenericFields(FieldNames fieldNames) {
+ super(fieldNames);
}
- public void reset(Fields> fields) {
- this.fields.clear();
- this.fields.putAll(fields.getAll());
- }
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/HeaderV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/HeaderV1Field.java
index 17f1f5d9..82c390aa 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/HeaderV1Field.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/HeaderV1Field.java
@@ -1,20 +1,18 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class HeaderV1Field {
+ private HeaderV1Field() {}
-public class HeaderV1Field {
-
- public static String ID = "Id";
- public static String VERSION = "Version";
- public static String SECTION_IDS = "SectionIds";
+ public static final String ID = "Id";
+ public static final String VERSION = "Version";
+ public static final String SECTION_IDS = "SectionIds";
//@formatter:off
- public static List HEADER_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
- HeaderV1Field.ID,
+ public static final FieldNames HEADER_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
+ HeaderV1Field.ID,
HeaderV1Field.VERSION,
HeaderV1Field.SECTION_IDS
- });
+ );
//@formatter:on
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfCaV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfCaV1Field.java
index c87e886d..3f6026b9 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfCaV1Field.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfCaV1Field.java
@@ -1,39 +1,37 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class TcfCaV1Field {
+ private TcfCaV1Field() {}
-public class TcfCaV1Field {
+ public static final String VERSION = "Version";
+ public static final String CREATED = "Created";
+ public static final String LAST_UPDATED = "LastUpdated";
+ public static final String CMP_ID = "CmpId";
+ public static final String CMP_VERSION = "CmpVersion";
+ public static final String CONSENT_SCREEN = "ConsentScreen";
+ public static final String CONSENT_LANGUAGE = "ConsentLanguage";
+ public static final String VENDOR_LIST_VERSION = "VendorListVersion";
+ public static final String TCF_POLICY_VERSION = "TcfPolicyVersion";
+ public static final String USE_NON_STANDARD_STACKS = "UseNonStandardStacks";
+ public static final String SPECIAL_FEATURE_EXPRESS_CONSENT = "SpecialFeatureExpressConsent";
+ public static final String PURPOSES_EXPRESS_CONSENT = "PurposesExpressConsent";
+ public static final String PURPOSES_IMPLIED_CONSENT = "PurposesImpliedConsent";
+ public static final String VENDOR_EXPRESS_CONSENT = "VendorExpressConsent";
+ public static final String VENDOR_IMPLIED_CONSENT = "VendorImpliedConsent";
+ public static final String PUB_RESTRICTIONS = "PubRestrictions";
- public static String VERSION = "Version";
- public static String CREATED = "Created";
- public static String LAST_UPDATED = "LastUpdated";
- public static String CMP_ID = "CmpId";
- public static String CMP_VERSION = "CmpVersion";
- public static String CONSENT_SCREEN = "ConsentScreen";
- public static String CONSENT_LANGUAGE = "ConsentLanguage";
- public static String VENDOR_LIST_VERSION = "VendorListVersion";
- public static String TCF_POLICY_VERSION = "TcfPolicyVersion";
- public static String USE_NON_STANDARD_STACKS = "UseNonStandardStacks";
- public static String SPECIAL_FEATURE_EXPRESS_CONSENT = "SpecialFeatureExpressConsent";
- public static String PURPOSES_EXPRESS_CONSENT = "PurposesExpressConsent";
- public static String PURPOSES_IMPLIED_CONSENT = "PurposesImpliedConsent";
- public static String VENDOR_EXPRESS_CONSENT = "VendorExpressConsent";
- public static String VENDOR_IMPLIED_CONSENT = "VendorImpliedConsent";
- public static String PUB_RESTRICTIONS = "PubRestrictions";
+ public static final String PUB_PURPOSES_SEGMENT_TYPE = "PubPurposesSegmentType";
+ public static final String PUB_PURPOSES_EXPRESS_CONSENT = "PubPurposesExpressConsent";
+ public static final String PUB_PURPOSES_IMPLIED_CONSENT = "PubPurposesImpliedConsent";
+ public static final String NUM_CUSTOM_PURPOSES = "NumCustomPurposes";
+ public static final String CUSTOM_PURPOSES_EXPRESS_CONSENT = "CustomPurposesExpressConsent";
+ public static final String CUSTOM_PURPOSES_IMPLIED_CONSENT = "CustomPurposesImpliedConsent";
- public static String PUB_PURPOSES_SEGMENT_TYPE = "PubPurposesSegmentType";
- public static String PUB_PURPOSES_EXPRESS_CONSENT = "PubPurposesExpressConsent";
- public static String PUB_PURPOSES_IMPLIED_CONSENT = "PubPurposesImpliedConsent";
- public static String NUM_CUSTOM_PURPOSES = "NumCustomPurposes";
- public static String CUSTOM_PURPOSES_EXPRESS_CONSENT = "CustomPurposesExpressConsent";
- public static String CUSTOM_PURPOSES_IMPLIED_CONSENT = "CustomPurposesImpliedConsent";
+ public static final String DISCLOSED_VENDORS_SEGMENT_TYPE = "DisclosedVendorsSegmentType";
+ public static final String DISCLOSED_VENDORS = "DisclosedVendors";
- public static String DISCLOSED_VENDORS_SEGMENT_TYPE = "DisclosedVendorsSegmentType";
- public static String DISCLOSED_VENDORS = "DisclosedVendors";
-
//@formatter:off
- public static List TCFCAV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames TCFCAV1_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
TcfCaV1Field.VERSION,
TcfCaV1Field.CREATED,
TcfCaV1Field.LAST_UPDATED,
@@ -50,24 +48,24 @@ public class TcfCaV1Field {
TcfCaV1Field.VENDOR_EXPRESS_CONSENT,
TcfCaV1Field.VENDOR_IMPLIED_CONSENT,
TcfCaV1Field.PUB_RESTRICTIONS
- });
+ );
//@formatter:on
//@formatter:off
- public static List TCFCAV1_PUBLISHER_PURPOSES_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames TCFCAV1_PUBLISHER_PURPOSES_SEGMENT_FIELD_NAMES = FieldNames.of(
TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE,
TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT,
TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT,
TcfCaV1Field.NUM_CUSTOM_PURPOSES,
TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT,
- TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT,
- });
+ TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT
+ );
//@formatter:on
-
+
//@formatter:off
- public static List TCFCAV1_DISCLOSED_VENDORS_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames TCFCAV1_DISCLOSED_VENDORS_SEGMENT_FIELD_NAMES = FieldNames.of(
TcfCaV1Field.DISCLOSED_VENDORS_SEGMENT_TYPE,
- TcfCaV1Field.DISCLOSED_VENDORS,
- });
+ TcfCaV1Field.DISCLOSED_VENDORS
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfEuV2Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfEuV2Field.java
index fedb510f..3fa0df6d 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfEuV2Field.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/TcfEuV2Field.java
@@ -1,42 +1,40 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class TcfEuV2Field {
+ private TcfEuV2Field() {}
-public class TcfEuV2Field {
-
- public static String VERSION = "Version";
- public static String CREATED = "Created";
- public static String LAST_UPDATED = "LastUpdated";
- public static String CMP_ID = "CmpId";
- public static String CMP_VERSION = "CmpVersion";
- public static String CONSENT_SCREEN = "ConsentScreen";
- public static String CONSENT_LANGUAGE = "ConsentLanguage";
- public static String VENDOR_LIST_VERSION = "VendorListVersion";
- public static String POLICY_VERSION = "PolicyVersion";
- public static String IS_SERVICE_SPECIFIC = "IsServiceSpecific";
- public static String USE_NON_STANDARD_STACKS = "UseNonStandardStacks";
- public static String SPECIAL_FEATURE_OPTINS = "SpecialFeatureOptins";
- public static String PURPOSE_CONSENTS = "PurposeConsents";
- public static String PURPOSE_LEGITIMATE_INTERESTS = "PurposeLegitimateInterests";
- public static String PURPOSE_ONE_TREATMENT = "PurposeOneTreatment";
- public static String PUBLISHER_COUNTRY_CODE = "PublisherCountryCode";
- public static String VENDOR_CONSENTS = "VendorConsents";
- public static String VENDOR_LEGITIMATE_INTERESTS = "VendorLegitimateInterests";
- public static String PUBLISHER_RESTRICTIONS = "PublisherRestrictions";
- public static String PUBLISHER_PURPOSES_SEGMENT_TYPE = "PublisherPurposesSegmentType";
- public static String PUBLISHER_CONSENTS = "PublisherConsents";
- public static String PUBLISHER_LEGITIMATE_INTERESTS = "PublisherLegitimateInterests";
- public static String NUM_CUSTOM_PURPOSES = "NumCustomPurposes";
- public static String PUBLISHER_CUSTOM_CONSENTS = "PublisherCustomConsents";
- public static String PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS = "PublisherCustomLegitimateInterests";
- public static String VENDORS_ALLOWED_SEGMENT_TYPE = "VendorsAllowedSegmentType";
- public static String VENDORS_ALLOWED = "VendorsAllowed";
- public static String VENDORS_DISCLOSED_SEGMENT_TYPE = "VendorsDisclosedSegmentType";
- public static String VENDORS_DISCLOSED = "VendorsDisclosed";
+ public static final String VERSION = "Version";
+ public static final String CREATED = "Created";
+ public static final String LAST_UPDATED = "LastUpdated";
+ public static final String CMP_ID = "CmpId";
+ public static final String CMP_VERSION = "CmpVersion";
+ public static final String CONSENT_SCREEN = "ConsentScreen";
+ public static final String CONSENT_LANGUAGE = "ConsentLanguage";
+ public static final String VENDOR_LIST_VERSION = "VendorListVersion";
+ public static final String POLICY_VERSION = "PolicyVersion";
+ public static final String IS_SERVICE_SPECIFIC = "IsServiceSpecific";
+ public static final String USE_NON_STANDARD_STACKS = "UseNonStandardStacks";
+ public static final String SPECIAL_FEATURE_OPTINS = "SpecialFeatureOptins";
+ public static final String PURPOSE_CONSENTS = "PurposeConsents";
+ public static final String PURPOSE_LEGITIMATE_INTERESTS = "PurposeLegitimateInterests";
+ public static final String PURPOSE_ONE_TREATMENT = "PurposeOneTreatment";
+ public static final String PUBLISHER_COUNTRY_CODE = "PublisherCountryCode";
+ public static final String VENDOR_CONSENTS = "VendorConsents";
+ public static final String VENDOR_LEGITIMATE_INTERESTS = "VendorLegitimateInterests";
+ public static final String PUBLISHER_RESTRICTIONS = "PublisherRestrictions";
+ public static final String PUBLISHER_PURPOSES_SEGMENT_TYPE = "PublisherPurposesSegmentType";
+ public static final String PUBLISHER_CONSENTS = "PublisherConsents";
+ public static final String PUBLISHER_LEGITIMATE_INTERESTS = "PublisherLegitimateInterests";
+ public static final String NUM_CUSTOM_PURPOSES = "NumCustomPurposes";
+ public static final String PUBLISHER_CUSTOM_CONSENTS = "PublisherCustomConsents";
+ public static final String PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS = "PublisherCustomLegitimateInterests";
+ public static final String VENDORS_ALLOWED_SEGMENT_TYPE = "VendorsAllowedSegmentType";
+ public static final String VENDORS_ALLOWED = "VendorsAllowed";
+ public static final String VENDORS_DISCLOSED_SEGMENT_TYPE = "VendorsDisclosedSegmentType";
+ public static final String VENDORS_DISCLOSED = "VendorsDisclosed";
//@formatter:off
- public static List TCFEUV2_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames TCFEUV2_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
TcfEuV2Field.VERSION,
TcfEuV2Field.CREATED,
TcfEuV2Field.LAST_UPDATED,
@@ -56,31 +54,31 @@ public class TcfEuV2Field {
TcfEuV2Field.VENDOR_CONSENTS,
TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS,
TcfEuV2Field.PUBLISHER_RESTRICTIONS
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List TCFEUV2_PUBLISHER_PURPOSES_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames TCFEUV2_PUBLISHER_PURPOSES_SEGMENT_FIELD_NAMES = FieldNames.of(
TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE,
TcfEuV2Field.PUBLISHER_CONSENTS,
TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS,
TcfEuV2Field.NUM_CUSTOM_PURPOSES,
TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS,
- TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS,
- });
+ TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS
+ );
//@formatter:on
-
+
//@formatter:off
- public static List TCFEUV2_VENDORS_ALLOWED_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames TCFEUV2_VENDORS_ALLOWED_SEGMENT_FIELD_NAMES = FieldNames.of(
TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE,
- TcfEuV2Field.VENDORS_ALLOWED,
- });
+ TcfEuV2Field.VENDORS_ALLOWED
+ );
//@formatter:on
-
+
//@formatter:off
- public static List TCFEUV2_VENDORS_DISCLOSED_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames TCFEUV2_VENDORS_DISCLOSED_SEGMENT_FIELD_NAMES = FieldNames.of(
TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE,
- TcfEuV2Field.VENDORS_DISCLOSED,
- });
+ TcfEuV2Field.VENDORS_DISCLOSED
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCaField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCaField.java
index 934f57ac..3b5ef779 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCaField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCaField.java
@@ -1,29 +1,27 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsCaField {
+ private UsCaField() {}
-public class UsCaField {
+ public static final String VERSION = "Version";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String SHARING_OPT_OUT_NOTICE = "SharingOptOutNotice";
+ public static final String SENSITIVE_DATA_LIMIT_USE_NOTICE = "SensitiveDataLimitUseNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String SHARING_OPT_OUT = "SharingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String PERSONAL_DATA_CONSENTS = "PersonalDataConsents";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String SHARING_OPT_OUT_NOTICE = "SharingOptOutNotice";
- public static String SENSITIVE_DATA_LIMIT_USE_NOTICE = "SensitiveDataLimitUseNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String SHARING_OPT_OUT = "SharingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String PERSONAL_DATA_CONSENTS = "PersonalDataConsents";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
-
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
//@formatter:off
- public static List USCA_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USCA_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsCaField.VERSION,
UsCaField.SALE_OPT_OUT_NOTICE,
UsCaField.SHARING_OPT_OUT_NOTICE,
@@ -36,13 +34,14 @@ public class UsCaField {
UsCaField.MSPA_COVERED_TRANSACTION,
UsCaField.MSPA_OPT_OUT_OPTION_MODE,
UsCaField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
//@formatter:off
- public static List USCA_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USCA_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsCaField.GPC_SEGMENT_TYPE,
+ UsCaField.GPC_SEGMENT_INCLUDED,
UsCaField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCoField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCoField.java
index cae4e769..516c32a8 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCoField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCoField.java
@@ -1,28 +1,26 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsCoField {
+ private UsCoField() {}
-public class UsCoField {
+ public static final String VERSION = "Version";
+ public static final String SHARING_NOTICE = "SharingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String SHARING_NOTICE = "SharingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
-
//@formatter:off
- public static List USCO_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USCO_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsCoField.VERSION,
UsCoField.SHARING_NOTICE,
UsCoField.SALE_OPT_OUT_NOTICE,
@@ -34,13 +32,14 @@ public class UsCoField {
UsCoField.MSPA_COVERED_TRANSACTION,
UsCoField.MSPA_OPT_OUT_OPTION_MODE,
UsCoField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List USCO_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USCO_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsCoField.GPC_SEGMENT_TYPE,
+ UsCoField.GPC_SEGMENT_INCLUDED,
UsCoField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCtField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCtField.java
index 9662e1e3..56700df9 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCtField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCtField.java
@@ -1,28 +1,26 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsCtField {
+ private UsCtField() {}
-public class UsCtField {
+ public static final String VERSION = "Version";
+ public static final String SHARING_NOTICE = "SharingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String SHARING_NOTICE = "SharingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
-
//@formatter:off
- public static List USCT_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USCT_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsCtField.VERSION,
UsCtField.SHARING_NOTICE,
UsCtField.SALE_OPT_OUT_NOTICE,
@@ -34,13 +32,14 @@ public class UsCtField {
UsCtField.MSPA_COVERED_TRANSACTION,
UsCtField.MSPA_OPT_OUT_OPTION_MODE,
UsCtField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List USCT_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USCT_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsCtField.GPC_SEGMENT_TYPE,
+ UsCtField.GPC_SEGMENT_INCLUDED,
UsCtField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsDeField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsDeField.java
index 2979f9b6..7e52bcaf 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsDeField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsDeField.java
@@ -1,29 +1,27 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsDeField {
+ private UsDeField() {}
-public class UsDeField {
+ public static final String VERSION = "Version";
+ public static final String PROCESSING_NOTICE = "ProcessingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String PROCESSING_NOTICE = "ProcessingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
-
//@formatter:off
- public static List USDE_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USDE_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsDeField.VERSION,
UsDeField.PROCESSING_NOTICE,
UsDeField.SALE_OPT_OUT_NOTICE,
@@ -36,13 +34,14 @@ public class UsDeField {
UsDeField.MSPA_COVERED_TRANSACTION,
UsDeField.MSPA_OPT_OUT_OPTION_MODE,
UsDeField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List USDE_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USDE_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsDeField.GPC_SEGMENT_TYPE,
+ UsDeField.GPC_SEGMENT_INCLUDED,
UsDeField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsFlField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsFlField.java
index f3647a79..ae50962c 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsFlField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsFlField.java
@@ -1,25 +1,23 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsFlField {
+ private UsFlField() {}
-public class UsFlField {
-
- public static String VERSION = "Version";
- public static String PROCESSING_NOTICE = "ProcessingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String VERSION = "Version";
+ public static final String PROCESSING_NOTICE = "ProcessingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
//@formatter:off
- public static List USFL_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USFL_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsFlField.VERSION,
UsFlField.PROCESSING_NOTICE,
UsFlField.SALE_OPT_OUT_NOTICE,
@@ -32,6 +30,6 @@ public class UsFlField {
UsFlField.MSPA_COVERED_TRANSACTION,
UsFlField.MSPA_OPT_OUT_OPTION_MODE,
UsFlField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsIaField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsIaField.java
index f0c8d523..90d2662a 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsIaField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsIaField.java
@@ -1,29 +1,27 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsIaField {
+ private UsIaField() {}
-public class UsIaField {
+ public static final String VERSION = "Version";
+ public static final String PROCESSING_NOTICE = "ProcessingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SENSITIVE_DATA_OPT_OUT_NOTICE = "SensitiveDataOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String PROCESSING_NOTICE = "ProcessingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SENSITIVE_DATA_OPT_OUT_NOTICE = "SensitiveDataOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
-
//@formatter:off
- public static List USIA_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USIA_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsIaField.VERSION,
UsIaField.PROCESSING_NOTICE,
UsIaField.SALE_OPT_OUT_NOTICE,
@@ -36,13 +34,14 @@ public class UsIaField {
UsIaField.MSPA_COVERED_TRANSACTION,
UsIaField.MSPA_OPT_OUT_OPTION_MODE,
UsIaField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List USIA_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USIA_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsIaField.GPC_SEGMENT_TYPE,
+ UsIaField.GPC_SEGMENT_INCLUDED,
UsIaField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsMtField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsMtField.java
index 6b785f73..f3946b6f 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsMtField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsMtField.java
@@ -1,29 +1,27 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsMtField {
+ private UsMtField() {}
-public class UsMtField {
+ public static final String VERSION = "Version";
+ public static final String SHARING_NOTICE = "SharingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String SHARING_NOTICE = "SharingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
-
//@formatter:off
- public static List USMT_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USMT_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsMtField.VERSION,
UsMtField.SHARING_NOTICE,
UsMtField.SALE_OPT_OUT_NOTICE,
@@ -36,13 +34,14 @@ public class UsMtField {
UsMtField.MSPA_COVERED_TRANSACTION,
UsMtField.MSPA_OPT_OUT_OPTION_MODE,
UsMtField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List USMT_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static FieldNames USMT_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsMtField.GPC_SEGMENT_TYPE,
+ UsMtField.GPC_SEGMENT_INCLUDED,
UsMtField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNatField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNatField.java
index e18427b1..d43cb586 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNatField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNatField.java
@@ -1,33 +1,31 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsNatField {
+ private UsNatField() {}
-public class UsNatField {
+ public static final String VERSION = "Version";
+ public static final String SHARING_NOTICE = "SharingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String SHARING_OPT_OUT_NOTICE = "SharingOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE = "SensitiveDataProcessingOptOutNotice";
+ public static final String SENSITIVE_DATA_LIMIT_USE_NOTICE = "SensitiveDataLimitUseNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String SHARING_OPT_OUT = "SharingOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String PERSONAL_DATA_CONSENTS = "PersonalDataConsents";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String SHARING_NOTICE = "SharingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String SHARING_OPT_OUT_NOTICE = "SharingOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE = "SensitiveDataProcessingOptOutNotice";
- public static String SENSITIVE_DATA_LIMIT_USE_NOTICE = "SensitiveDataLimitUseNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String SHARING_OPT_OUT = "SharingOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String PERSONAL_DATA_CONSENTS = "PersonalDataConsents";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
-
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
//@formatter:off
- public static List USNAT_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USNAT_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsNatField.VERSION,
UsNatField.SHARING_NOTICE,
UsNatField.SALE_OPT_OUT_NOTICE,
@@ -44,13 +42,14 @@ public class UsNatField {
UsNatField.MSPA_COVERED_TRANSACTION,
UsNatField.MSPA_OPT_OUT_OPTION_MODE,
UsNatField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List USNAT_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USNAT_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsNatField.GPC_SEGMENT_TYPE,
+ UsNatField.GPC_SEGMENT_INCLUDED,
UsNatField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNeField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNeField.java
index a4479a87..93a99130 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNeField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNeField.java
@@ -1,29 +1,27 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsNeField {
+ private UsNeField() {}
-public class UsNeField {
+ public static final String VERSION = "Version";
+ public static final String PROCESSING_NOTICE = "ProcessingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String PROCESSING_NOTICE = "ProcessingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
-
//@formatter:off
- public static List USNE_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USNE_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsNeField.VERSION,
UsNeField.PROCESSING_NOTICE,
UsNeField.SALE_OPT_OUT_NOTICE,
@@ -36,13 +34,14 @@ public class UsNeField {
UsNeField.MSPA_COVERED_TRANSACTION,
UsNeField.MSPA_OPT_OUT_OPTION_MODE,
UsNeField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List USNE_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USNE_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsNeField.GPC_SEGMENT_TYPE,
+ UsNeField.GPC_SEGMENT_INCLUDED,
UsNeField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNhField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNhField.java
index 8381dc9b..44b99fbe 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNhField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNhField.java
@@ -1,29 +1,27 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsNhField {
+ private UsNhField() {}
-public class UsNhField {
+ public static final String VERSION = "Version";
+ public static final String PROCESSING_NOTICE = "ProcessingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String PROCESSING_NOTICE = "ProcessingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
-
//@formatter:off
- public static List USNH_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USNH_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsNhField.VERSION,
UsNhField.PROCESSING_NOTICE,
UsNhField.SALE_OPT_OUT_NOTICE,
@@ -36,13 +34,14 @@ public class UsNhField {
UsNhField.MSPA_COVERED_TRANSACTION,
UsNhField.MSPA_OPT_OUT_OPTION_MODE,
UsNhField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List USNH_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USNH_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsNhField.GPC_SEGMENT_TYPE,
+ UsNhField.GPC_SEGMENT_INCLUDED,
UsNhField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNjField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNjField.java
index 2acba850..1ef95e28 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNjField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNjField.java
@@ -1,29 +1,27 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsNjField {
+ private UsNjField() {}
-public class UsNjField {
+ public static final String VERSION = "Version";
+ public static final String PROCESSING_NOTICE = "ProcessingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String PROCESSING_NOTICE = "ProcessingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
-
//@formatter:off
- public static List USNJ_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USNJ_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsNjField.VERSION,
UsNjField.PROCESSING_NOTICE,
UsNjField.SALE_OPT_OUT_NOTICE,
@@ -36,13 +34,14 @@ public class UsNjField {
UsNjField.MSPA_COVERED_TRANSACTION,
UsNjField.MSPA_OPT_OUT_OPTION_MODE,
UsNjField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List USNJ_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USNJ_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsNjField.GPC_SEGMENT_TYPE,
+ UsNjField.GPC_SEGMENT_INCLUDED,
UsNjField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsOrField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsOrField.java
index 3e9021c2..adf05255 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsOrField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsOrField.java
@@ -1,29 +1,27 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsOrField {
+ private UsOrField() {}
-public class UsOrField {
+ public static final String VERSION = "Version";
+ public static final String PROCESSING_NOTICE = "ProcessingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String PROCESSING_NOTICE = "ProcessingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
-
//@formatter:off
- public static List USOR_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USOR_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsOrField.VERSION,
UsOrField.PROCESSING_NOTICE,
UsOrField.SALE_OPT_OUT_NOTICE,
@@ -36,13 +34,14 @@ public class UsOrField {
UsOrField.MSPA_COVERED_TRANSACTION,
UsOrField.MSPA_OPT_OUT_OPTION_MODE,
UsOrField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List USOR_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USOR_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsOrField.GPC_SEGMENT_TYPE,
+ UsOrField.GPC_SEGMENT_INCLUDED,
UsOrField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsTnField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsTnField.java
index 7ef8c75d..4271199e 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsTnField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsTnField.java
@@ -1,29 +1,27 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsTnField {
+ private UsTnField() {}
-public class UsTnField {
+ public static final String VERSION = "Version";
+ public static final String PROCESSING_NOTICE = "ProcessingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String PROCESSING_NOTICE = "ProcessingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
-
//@formatter:off
- public static List USTN_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USTN_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsTnField.VERSION,
UsTnField.PROCESSING_NOTICE,
UsTnField.SALE_OPT_OUT_NOTICE,
@@ -36,13 +34,14 @@ public class UsTnField {
UsTnField.MSPA_COVERED_TRANSACTION,
UsTnField.MSPA_OPT_OUT_OPTION_MODE,
UsTnField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List USTN_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USTN_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsTnField.GPC_SEGMENT_TYPE,
+ UsTnField.GPC_SEGMENT_INCLUDED,
UsTnField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsTxField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsTxField.java
index 44ec7d69..5729593a 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsTxField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsTxField.java
@@ -1,29 +1,27 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsTxField {
+ private UsTxField() {}
-public class UsTxField {
+ public static final String VERSION = "Version";
+ public static final String PROCESSING_NOTICE = "ProcessingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
- public static String VERSION = "Version";
- public static String PROCESSING_NOTICE = "ProcessingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String ADDITIONAL_DATA_PROCESSING_CONSENT = "AdditionalDataProcessingConsent";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String GPC_SEGMENT_TYPE = "GpcSegmentType";
+ public static final String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
+ public static final String GPC = "Gpc";
- public static String GPC_SEGMENT_TYPE = "GpcSegmentType";
- public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded";
- public static String GPC = "Gpc";
-
//@formatter:off
- public static List USTX_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USTX_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsTxField.VERSION,
UsTxField.PROCESSING_NOTICE,
UsTxField.SALE_OPT_OUT_NOTICE,
@@ -36,13 +34,14 @@ public class UsTxField {
UsTxField.MSPA_COVERED_TRANSACTION,
UsTxField.MSPA_OPT_OUT_OPTION_MODE,
UsTxField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
-
+
//@formatter:off
- public static List USTX_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static FieldNames USTX_GPC_SEGMENT_FIELD_NAMES = FieldNames.of(
UsTxField.GPC_SEGMENT_TYPE,
+ UsTxField.GPC_SEGMENT_INCLUDED,
UsTxField.GPC
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsUtField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsUtField.java
index 01cedc67..4cc9ff47 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsUtField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsUtField.java
@@ -1,25 +1,23 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsUtField {
+ private UsUtField() {}
-public class UsUtField {
-
- public static String VERSION = "Version";
- public static String SHARING_NOTICE = "SharingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE = "SensitiveDataProcessingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String VERSION = "Version";
+ public static final String SHARING_NOTICE = "SharingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE = "SensitiveDataProcessingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
//@formatter:off
- public static List USUT_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USUT_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsUtField.VERSION,
UsUtField.SHARING_NOTICE,
UsUtField.SALE_OPT_OUT_NOTICE,
@@ -32,6 +30,6 @@ public class UsUtField {
UsUtField.MSPA_COVERED_TRANSACTION,
UsUtField.MSPA_OPT_OUT_OPTION_MODE,
UsUtField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsVaField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsVaField.java
index 46cb4dbb..dd9e75cf 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsVaField.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsVaField.java
@@ -1,24 +1,22 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UsVaField {
+ private UsVaField() {}
-public class UsVaField {
-
- public static String VERSION = "Version";
- public static String SHARING_NOTICE = "SharingNotice";
- public static String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
- public static String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
- public static String SALE_OPT_OUT = "SaleOptOut";
- public static String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
- public static String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
- public static String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
- public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
- public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
- public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
+ public static final String VERSION = "Version";
+ public static final String SHARING_NOTICE = "SharingNotice";
+ public static final String SALE_OPT_OUT_NOTICE = "SaleOptOutNotice";
+ public static final String TARGETED_ADVERTISING_OPT_OUT_NOTICE = "TargetedAdvertisingOptOutNotice";
+ public static final String SALE_OPT_OUT = "SaleOptOut";
+ public static final String TARGETED_ADVERTISING_OPT_OUT = "TargetedAdvertisingOptOut";
+ public static final String SENSITIVE_DATA_PROCESSING = "SensitiveDataProcessing";
+ public static final String KNOWN_CHILD_SENSITIVE_DATA_CONSENTS = "KnownChildSensitiveDataConsents";
+ public static final String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction";
+ public static final String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode";
+ public static final String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode";
//@formatter:off
- public static List USVA_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USVA_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UsVaField.VERSION,
UsVaField.SHARING_NOTICE,
UsVaField.SALE_OPT_OUT_NOTICE,
@@ -30,6 +28,6 @@ public class UsVaField {
UsVaField.MSPA_COVERED_TRANSACTION,
UsVaField.MSPA_OPT_OUT_OPTION_MODE,
UsVaField.MSPA_SERVICE_PROVIDER_MODE
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1Field.java
index 2551632c..9b497991 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1Field.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1Field.java
@@ -1,21 +1,19 @@
package com.iab.gpp.encoder.field;
-import java.util.Arrays;
-import java.util.List;
+public final class UspV1Field {
+ private UspV1Field() {}
-public class UspV1Field {
-
- public static String VERSION = "Version";
- public static String NOTICE = "Notice";
- public static String OPT_OUT_SALE = "OptOutSale";
- public static String LSPA_COVERED = "LspaCovered";
+ public static final String VERSION = "Version";
+ public static final String NOTICE = "Notice";
+ public static final String OPT_OUT_SALE = "OptOutSale";
+ public static final String LSPA_COVERED = "LspaCovered";
//@formatter:off
- public static List USPV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] {
+ public static final FieldNames USPV1_CORE_SEGMENT_FIELD_NAMES = FieldNames.of(
UspV1Field.VERSION,
UspV1Field.NOTICE,
UspV1Field.OPT_OUT_SALE,
UspV1Field.LSPA_COVERED
- });
+ );
//@formatter:on
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableSegmentedBitStringSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableSegmentedBitStringSection.java
deleted file mode 100644
index eb5d5459..00000000
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableSegmentedBitStringSection.java
+++ /dev/null
@@ -1,110 +0,0 @@
-package com.iab.gpp.encoder.section;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import com.iab.gpp.encoder.datatype.AbstractEncodableBitStringDataType;
-import com.iab.gpp.encoder.datatype.SubstringException;
-import com.iab.gpp.encoder.error.DecodingException;
-import com.iab.gpp.encoder.error.EncodingException;
-import com.iab.gpp.encoder.error.InvalidFieldException;
-
-public abstract class AbstractEncodableSegmentedBitStringSection implements EncodableSection {
- protected Map> fields;
- protected String[][] segments;
-
- @Override
- public boolean hasField(String fieldName) {
- return this.fields.containsKey(fieldName);
- }
-
- @Override
- public Object getFieldValue(String fieldName) {
- if (this.fields.containsKey(fieldName)) {
- return this.fields.get(fieldName).getValue();
- } else {
- return null;
- }
- }
-
- @Override
- public void setFieldValue(String fieldName, Object value) throws InvalidFieldException {
- if (this.fields.containsKey(fieldName)) {
- this.fields.get(fieldName).setValue(value);
- } else {
- throw new InvalidFieldException(fieldName + " not found");
- }
- }
-
- public String[][] getSegments() {
- return this.segments;
- }
-
- public List encodeSegmentsToBitStrings() throws EncodingException {
- List segmentBitStrings = new ArrayList<>();
- for (int i = 0; i < this.segments.length; i++) {
- String segmentBitString = "";
- for (int j = 0; j < this.segments[i].length; j++) {
- String fieldName = this.segments[i][j];
- if (this.fields.containsKey(fieldName)) {
- try {
- AbstractEncodableBitStringDataType> field = this.fields.get(fieldName);
- segmentBitString += field.encode();
- } catch (Exception e) {
- throw new EncodingException("Unable to encode " + fieldName, e);
- }
- } else {
- throw new EncodingException("Field not found: '" + fieldName + "'");
- }
- }
- segmentBitStrings.add(segmentBitString);
- }
-
- return segmentBitStrings;
- }
-
- public void decodeSegmentsFromBitStrings(List segmentBitStrings) throws DecodingException {
- for (int i = 0; i < this.segments.length && i < segmentBitStrings.size(); i++) {
- decodeSegmentFromBitString(segments[i], segmentBitStrings.get(i));
- }
- }
-
- private void decodeSegmentFromBitString(String[] segment, String segmentBitString) throws DecodingException {
- if (segmentBitString != null && segmentBitString.length() > 0) {
- int index = 0;
- for (int j = 0; j < segment.length; j++) {
- String fieldName = segment[j];
- AbstractEncodableBitStringDataType> field = this.fields.get(fieldName);
- if (this.fields.containsKey(fieldName)) {
- try {
- String substring = field.substring(segmentBitString, index);
- field.decode(substring);
- index += substring.length();
- } catch (SubstringException e) {
- if(field.getHardFailIfMissing()) {
- throw new DecodingException("Unable to decode " + fieldName, e);
- } else {
- return;
- }
- } catch (Exception e) {
- throw new DecodingException("Unable to decode " + fieldName, e);
- }
- } else {
- throw new DecodingException("Field not found: '" + fieldName + "'");
- }
- }
- }
- }
-
- @Override
- public abstract String encode() throws EncodingException;
-
- @Override
- public abstract void decode(String encodedString) throws DecodingException;
-
- @Override
- public abstract int getId();
-
- @Override
- public abstract String getName();
-}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractLazilyEncodableSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractLazilyEncodableSection.java
index 1f31a592..167e7188 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractLazilyEncodableSection.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractLazilyEncodableSection.java
@@ -6,36 +6,36 @@
public abstract class AbstractLazilyEncodableSection implements EncodableSection {
- private List segments;
-
- private String encodedString = null;
+ protected List segments;
+
+ private CharSequence encodedString = null;
private boolean dirty = false;
private boolean decoded = true;
- public AbstractLazilyEncodableSection() {
+ protected AbstractLazilyEncodableSection() {
this.segments = initializeSegments();
}
protected abstract List initializeSegments();
-
- protected abstract String encodeSection(List segments);
- protected abstract List decodeSection(String encodedString);
-
+ protected abstract CharSequence encodeSection(List segments);
+
+ protected abstract List decodeSection(CharSequence encodedString);
+
public boolean hasField(String fieldName) {
if (!this.decoded) {
this.segments = this.decodeSection(this.encodedString);
this.dirty = false;
this.decoded = true;
}
-
+
for(EncodableSegment segment : segments) {
- if(segment.getFieldNames().contains(fieldName)) {
- return segment.hasField(fieldName);
+ if (segment.hasField(fieldName)) {
+ return true;
}
}
-
+
return false;
}
@@ -74,7 +74,11 @@ public void setFieldValue(String fieldName, Object value) {
}
public String encode() {
- if (this.encodedString == null || this.encodedString.isEmpty() || this.dirty) {
+ return encodeCharSequence().toString();
+ }
+
+ public CharSequence encodeCharSequence() {
+ if (this.encodedString == null || this.encodedString.length() == 0 || this.dirty) {
this.encodedString = this.encodeSection(this.segments);
this.dirty = false;
this.decoded = true;
@@ -83,10 +87,19 @@ public String encode() {
return this.encodedString;
}
- public void decode(String encodedString) {
+ public void decode(CharSequence encodedString) {
this.encodedString = encodedString;
this.dirty = false;
this.decoded = false;
}
-
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("{id=").append(getId()).append(", name=").append(getName()).append(", version=").append(getVersion());
+ for (EncodableSegment segment: segments) {
+ sb.append(", ").append(segment.toString());
+ }
+ sb.append('}');
+ return sb.toString();
+ }
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/EncodableSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/EncodableSection.java
index e1f0a854..a7324eef 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/EncodableSection.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/EncodableSection.java
@@ -16,5 +16,7 @@ public interface EncodableSection {
String encode();
- void decode(String encodedString);
+ CharSequence encodeCharSequence();
+
+ void decode(CharSequence encodedString);
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/HeaderV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/HeaderV1.java
index fd5d991c..3e6faa0c 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/HeaderV1.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/HeaderV1.java
@@ -1,22 +1,24 @@
package com.iab.gpp.encoder.section;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import com.iab.gpp.encoder.datatype.encoder.IntegerSet;
import com.iab.gpp.encoder.field.HeaderV1Field;
import com.iab.gpp.encoder.segment.EncodableSegment;
import com.iab.gpp.encoder.segment.HeaderV1CoreSegment;
public class HeaderV1 extends AbstractLazilyEncodableSection {
-
- public static int ID = 3;
- public static int VERSION = 1;
- public static String NAME = "header";
+
+ public static final int ID = 3;
+ public static final int VERSION = 1;
+ public static final String NAME = "header";
public HeaderV1() {
super();
}
- public HeaderV1(String encodedString) {
+ public HeaderV1(CharSequence encodedString) {
super();
decode(encodedString);
}
@@ -38,42 +40,37 @@ public int getVersion() {
@Override
protected List initializeSegments() {
- List segments = new ArrayList<>();
- segments.add(new HeaderV1CoreSegment());
- return segments;
+ return Collections.singletonList(new HeaderV1CoreSegment());
}
-
+
@Override
- protected List decodeSection(String encodedString) {
- List segments = initializeSegments();
-
- if(encodedString != null && !encodedString.isEmpty()) {
- String[] encodedSegments = encodedString.split("\\.");
-
- for(int i=0; i i) {
- segments.get(i).decode(encodedSegments[i]);
+ protected List decodeSection(CharSequence encodedString) {
+ if(encodedString != null && encodedString.length() > 0) {
+ List encodedSegments = SlicedCharSequence.split(encodedString, '.');
+
+ for (int i=0; i i) {
+ segments.get(i).decode(encodedSegments.get(i));
}
}
}
-
+
return segments;
}
@Override
- protected String encodeSection(List segments) {
- List encodedSegments = new ArrayList<>();
+ protected CharSequence encodeSection(List segments) {
+ List encodedSegments = new ArrayList<>(segments.size());
for(EncodableSegment segment : segments) {
- encodedSegments.add(segment.encode());
+ encodedSegments.add(segment.encodeCharSequence());
}
- return String.join(".", encodedSegments);
+ return SlicedCharSequence.join('.', encodedSegments);
}
-
- @SuppressWarnings("unchecked")
- public List getSectionsIds() {
- return (List) this.getFieldValue(HeaderV1Field.SECTION_IDS);
+
+ public IntegerSet getSectionsIds() {
+ return (IntegerSet) this.getFieldValue(HeaderV1Field.SECTION_IDS);
}
-
-
+
+
}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java
index 976805d3..a438d217 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/Sections.java
@@ -6,11 +6,12 @@
import java.util.Map;
import java.util.stream.Collectors;
-public class Sections {
+public final class Sections {
+ private Sections() {}
- public static List SECTION_ORDER;
+ public static final List SECTION_ORDER;
- public static Map SECTION_ID_NAME_MAP;
+ public static final Map SECTION_ID_NAME_MAP;
static {
SECTION_ID_NAME_MAP = new HashMap<>();
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/SlicedCharSequence.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/SlicedCharSequence.java
new file mode 100644
index 00000000..234bf439
--- /dev/null
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/SlicedCharSequence.java
@@ -0,0 +1,74 @@
+package com.iab.gpp.encoder.section;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public final class SlicedCharSequence implements CharSequence {
+
+ private static final String EMPTY = "";
+ private final CharSequence base;
+ private final int start;
+ private final int end;
+
+ private SlicedCharSequence(CharSequence base, int start, int end) {
+ this.base = base;
+ this.start = start;
+ this.end = end;
+ }
+
+ public static List split(CharSequence charSequence, char splitter) {
+ List out = new ArrayList<>(1);
+ int length = charSequence.length();
+ int start = 0;
+ for (int i = 0; i < length; i++) {
+ if (charSequence.charAt(i) == splitter) {
+ out.add(new SlicedCharSequence(charSequence, start, i));
+ start = i + 1;
+ }
+ }
+ out.add(new SlicedCharSequence(charSequence, start, length));
+ return out;
+ }
+
+ public static final CharSequence join(char glue, List pieces) {
+ int size = pieces.size();
+ if (size > 1) {
+ int length = size - 1;
+ for (int i = 0; i < size; i++) {
+ length += pieces.get(i).length();
+ }
+ StringBuilder sb = new StringBuilder(length);
+ sb.append(pieces.get(0));
+ for (int i = 1; i < size; i++) {
+ sb.append(glue).append(pieces.get(i));
+ }
+ return sb;
+ }
+ if (size == 1) {
+ return pieces.get(0);
+ }
+ return EMPTY;
+ }
+
+
+ @Override
+ public int length() {
+ return end - start;
+ }
+
+ @Override
+ public char charAt(int index) {
+ return base.charAt(start + index);
+ }
+
+ @Override
+ public CharSequence subSequence(int newStart, int newEnd) {
+ return base.subSequence(start + newStart, start + newEnd);
+ }
+
+ @Override
+ public String toString() {
+ return base.subSequence(start, end).toString();
+ }
+
+}
diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfCaV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfCaV1.java
index 194a82dc..e082f067 100644
--- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfCaV1.java
+++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfCaV1.java
@@ -1,10 +1,11 @@
package com.iab.gpp.encoder.section;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
+import java.time.Instant;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import com.iab.gpp.encoder.datatype.RangeEntry;
+import com.iab.gpp.encoder.datatype.encoder.IntegerSet;
import com.iab.gpp.encoder.error.DecodingException;
import com.iab.gpp.encoder.error.InvalidFieldException;
import com.iab.gpp.encoder.field.TcfCaV1Field;
@@ -14,16 +15,16 @@
import com.iab.gpp.encoder.segment.TcfCaV1PublisherPurposesSegment;
public class TcfCaV1 extends AbstractLazilyEncodableSection {
-
- public static int ID = 5;
- public static int VERSION = 1;
- public static String NAME = "tcfcav1";
+
+ public static final int ID = 5;
+ public static final int VERSION = 1;
+ public static final String NAME = "tcfcav1";
public TcfCaV1() {
super();
}
- public TcfCaV1(String encodedString) {
+ public TcfCaV1(CharSequence encodedString) {
super();
decode(encodedString);
}
@@ -45,63 +46,57 @@ public int getVersion() {
@Override
protected List initializeSegments() {
- List segments = new ArrayList<>();
- segments.add(new TcfCaV1CoreSegment());
- segments.add(new TcfCaV1PublisherPurposesSegment());
- segments.add(new TcfCaV1DisclosedVendorsSegment());
- return segments;
+ return Arrays.asList(new TcfCaV1CoreSegment(), new TcfCaV1PublisherPurposesSegment(), new TcfCaV1DisclosedVendorsSegment());
}
-
+
@Override
- public List decodeSection(String encodedString) {
- List segments = initializeSegments();
-
- if(encodedString != null && !encodedString.isEmpty()) {
- String[] encodedSegments = encodedString.split("\\.");
- for (int i = 0; i < encodedSegments.length; i++) {
-
+ public List decodeSection(CharSequence encodedString) {
+ if (encodedString != null && encodedString.length() > 0) {
+ List encodedSegments = SlicedCharSequence.split(encodedString, '.');
+ for (int i = 0; i < encodedSegments.size(); i++) {
+
/**
* The first 3 bits contain the segment id. Rather than decode the entire string, just check the first character.
- *
+ *
* A-H = '000' = 0
* I-P = '001' = 1
* Y-Z,a-f = '011' = 3
- *
- * Note that there is no segment id field for the core segment. Instead the first 6 bits are reserved
+ *
+ * Note that there is no segment id field for the core segment. Instead the first 6 bits are reserved
* for the encoding version which only coincidentally works here because the version value is less than 8.
*/
-
- String encodedSegment = encodedSegments[i];
- if(!encodedSegment.isEmpty()) {
+
+ CharSequence encodedSegment = encodedSegments.get(i);
+ if (encodedSegment.length() > 0) {
char firstChar = encodedSegment.charAt(0);
-
+
if(firstChar >= 'A' && firstChar <= 'H') {
- segments.get(0).decode(encodedSegments[i]);
+ segments.get(0).decode(encodedSegment);
} else if(firstChar >= 'I' && firstChar <= 'P') {
- segments.get(2).decode(encodedSegments[i]);
+ segments.get(2).decode(encodedSegment);
} else if((firstChar >= 'Y' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'f')) {
- segments.get(1).decode(encodedSegments[i]);
+ segments.get(1).decode(encodedSegment);
} else {
throw new DecodingException("Invalid segment '" + encodedSegment + "'");
}
}
}
}
-
+
return segments;
}
@Override
- public String encodeSection(List segments) {
- List encodedSegments = new ArrayList<>();
+ public CharSequence encodeSection(List segments) {
+ List encodedSegments = new ArrayList<>(segments.size());
- encodedSegments.add(segments.get(0).encode());
- encodedSegments.add(segments.get(1).encode());
+ encodedSegments.add(segments.get(0).encodeCharSequence());
+ encodedSegments.add(segments.get(1).encodeCharSequence());
if(!this.getDisclosedVendors().isEmpty()) {
- encodedSegments.add(segments.get(2).encode());
+ encodedSegments.add(segments.get(2).encodeCharSequence());
}
-
- return String.join(".", encodedSegments);
+
+ return SlicedCharSequence.join('.', encodedSegments);
}
@Override
@@ -109,20 +104,20 @@ public void setFieldValue(String fieldName, Object value) throws InvalidFieldExc
super.setFieldValue(fieldName, value);
if (!fieldName.equals(TcfCaV1Field.CREATED) && !fieldName.equals(TcfCaV1Field.LAST_UPDATED)) {
- ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC"));
+ Instant utcDateTime = Instant.now();
super.setFieldValue(TcfCaV1Field.CREATED, utcDateTime);
super.setFieldValue(TcfCaV1Field.LAST_UPDATED, utcDateTime);
}
}
-
- public ZonedDateTime getCreated() {
- return (ZonedDateTime) this.getFieldValue(TcfCaV1Field.CREATED);
+
+ public Instant getCreated() {
+ return (Instant) this.getFieldValue(TcfCaV1Field.CREATED);
}
- public ZonedDateTime getLastUpdated() {
- return (ZonedDateTime) this.getFieldValue(TcfCaV1Field.LAST_UPDATED);
+ public Instant getLastUpdated() {
+ return (Instant) this.getFieldValue(TcfCaV1Field.LAST_UPDATED);
}
public Integer getCmpId() {
@@ -153,71 +148,61 @@ public Boolean getUseNonStandardStacks() {
return (Boolean) this.getFieldValue(TcfCaV1Field.USE_NON_STANDARD_STACKS);
}
- @SuppressWarnings("unchecked")
- public List getSpecialFeatureExpressConsent() {
- return (List) this.getFieldValue(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT);
+ public IntegerSet getSpecialFeatureExpressConsent() {
+ return (IntegerSet) this.getFieldValue(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT);
}
- @SuppressWarnings("unchecked")
- public List getPurposesExpressConsent() {
- return (List