From 8b844276e2c1252e898f3d384cd9294533aaccae Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 30 Aug 2023 16:17:43 -0600 Subject: [PATCH 01/36] lazy decoding --- .../java/com/iab/gpp/encoder/GppModel.java | 190 +++++++++++++++--- .../com/iab/gpp/encoder/GppModelTest.java | 17 +- .../iab/gpp/encoder/section/TcfCaV1Test.java | 2 +- 3 files changed, 167 insertions(+), 42 deletions(-) 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 626fb82a..501ec737 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 @@ -8,6 +8,7 @@ import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.error.LazyDecodingException; import com.iab.gpp.encoder.section.EncodableSection; import com.iab.gpp.encoder.section.HeaderV1; import com.iab.gpp.encoder.section.Sections; @@ -18,27 +19,45 @@ import com.iab.gpp.encoder.section.UsCtV1; import com.iab.gpp.encoder.section.UsNatV1; import com.iab.gpp.encoder.section.UsUtV1; -import com.iab.gpp.encoder.section.UspV1; import com.iab.gpp.encoder.section.UsVaV1; +import com.iab.gpp.encoder.section.UspV1; public class GppModel { private Map sections = new HashMap<>(); - public GppModel() { + private String encodedString; + private boolean decoded; + private boolean dirty; + public GppModel() { + this.encodedString = "DBAA"; + this.decoded = false; + this.dirty = false; } - public GppModel(String encodedString) throws DecodingException { - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + public GppModel(String encodedString) { + this.encodedString = encodedString; + this.decoded = false; + this.dirty = false; } - public void setFieldValue(int sectionId, String fieldName, Object value) throws InvalidFieldException { + public void setFieldValue(int sectionId, String fieldName, Object value) + throws InvalidFieldException, LazyDecodingException { setFieldValue(Sections.SECTION_ID_NAME_MAP.get(sectionId), fieldName, value); + this.dirty = true; } - public void setFieldValue(String sectionName, String fieldName, Object value) throws InvalidFieldException { + public void setFieldValue(String sectionName, String fieldName, Object value) + throws InvalidFieldException, LazyDecodingException { + // lazily decode + if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { + try { + this.decode(this.encodedString); + } catch (DecodingException e) { + throw new LazyDecodingException(e); + } + } + EncodableSection section = null; if (!this.sections.containsKey(sectionName)) { if (sectionName.equals(TcfCaV1.NAME)) { @@ -75,16 +94,26 @@ public void setFieldValue(String sectionName, String fieldName, Object value) th if (section != null) { section.setFieldValue(fieldName, value); + this.dirty = true; } else { throw new InvalidFieldException(sectionName + "." + fieldName + " not found"); } } - public Object getFieldValue(int sectionId, String fieldName) { + public Object getFieldValue(int sectionId, String fieldName) throws LazyDecodingException { return getFieldValue(Sections.SECTION_ID_NAME_MAP.get(sectionId), fieldName); } - public Object getFieldValue(String sectionName, String fieldName) { + public Object getFieldValue(String sectionName, String fieldName) throws LazyDecodingException { + // lazily decode + if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { + try { + this.decode(this.encodedString); + } catch (DecodingException e) { + throw new LazyDecodingException(e); + } + } + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName).getFieldValue(fieldName); } else { @@ -92,11 +121,20 @@ public Object getFieldValue(String sectionName, String fieldName) { } } - public boolean hasField(int sectionId, String fieldName) { + public boolean hasField(int sectionId, String fieldName) throws LazyDecodingException { return hasField(Sections.SECTION_ID_NAME_MAP.get(sectionId), fieldName); } - public boolean hasField(String sectionName, String fieldName) { + public boolean hasField(String sectionName, String fieldName) throws LazyDecodingException { + // lazily decode + if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { + try { + this.decode(this.encodedString); + } catch (DecodingException e) { + throw new LazyDecodingException(e); + } + } + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName).hasField(fieldName); } else { @@ -104,15 +142,33 @@ public boolean hasField(String sectionName, String fieldName) { } } - public boolean hasSection(int sectionId) { + public boolean hasSection(int sectionId) throws LazyDecodingException { return hasSection(Sections.SECTION_ID_NAME_MAP.get(sectionId)); } - public boolean hasSection(String sectionName) { + public boolean hasSection(String sectionName) throws LazyDecodingException { + // lazily decode + if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { + try { + this.decode(this.encodedString); + } catch (DecodingException e) { + throw new LazyDecodingException(e); + } + } + return this.sections.containsKey(sectionName); } - public HeaderV1 getHeader() { + public HeaderV1 getHeader() throws LazyDecodingException { + // lazily decode + if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { + try { + this.decode(this.encodedString); + } catch (DecodingException e) { + throw new LazyDecodingException(e); + } + } + HeaderV1 header = new HeaderV1(); try { header.setFieldValue("SectionIds", this.getSectionIds()); @@ -122,11 +178,20 @@ public HeaderV1 getHeader() { return header; } - public EncodableSection getSection(int sectionId) { + public EncodableSection getSection(int sectionId) throws LazyDecodingException { return getSection(Sections.SECTION_ID_NAME_MAP.get(sectionId)); } - public EncodableSection getSection(String sectionName) { + public EncodableSection getSection(String sectionName) throws LazyDecodingException { + // lazily decode + if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { + try { + this.decode(this.encodedString); + } catch (DecodingException e) { + throw new LazyDecodingException(e); + } + } + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName); } else { @@ -134,57 +199,79 @@ public EncodableSection getSection(String sectionName) { } } - public void deleteSection(int sectionId) { + public void deleteSection(int sectionId) throws LazyDecodingException { deleteSection(Sections.SECTION_ID_NAME_MAP.get(sectionId)); } - public void deleteSection(String sectionName) { + public void deleteSection(String sectionName) throws LazyDecodingException { + // lazily decode + if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { + try { + this.decode(this.encodedString); + } catch (DecodingException e) { + throw new LazyDecodingException(e); + } + } + if (this.sections.containsKey(sectionName)) { this.sections.remove(sectionName); + this.dirty = true; } } public void clear() { this.sections.clear(); + this.encodedString = "DBAA"; + this.decoded = false; + this.dirty = false; } - public TcfCaV1 getTcfCaV1Section() { + public TcfCaV1 getTcfCaV1Section() throws LazyDecodingException { return (TcfCaV1) getSection(TcfCaV1.NAME); } - public TcfEuV2 getTcfEuV2Section() { + public TcfEuV2 getTcfEuV2Section() throws LazyDecodingException { return (TcfEuV2) getSection(TcfEuV2.NAME); } - public UspV1 getUspV1Section() { + public UspV1 getUspV1Section() throws LazyDecodingException { return (UspV1) getSection(UspV1.NAME); } - public UsNatV1 getUspNatV1Section() { + public UsNatV1 getUsNatV1Section() throws LazyDecodingException { return (UsNatV1) getSection(UsNatV1.NAME); } - public UsCaV1 getUspCaV1Section() { + public UsCaV1 getUsCaV1Section() throws LazyDecodingException { return (UsCaV1) getSection(UsCaV1.NAME); } - public UsVaV1 getUspVaV1Section() { + public UsVaV1 getUsVaV1Section() throws LazyDecodingException { return (UsVaV1) getSection(UsVaV1.NAME); } - public UsCoV1 getUspCoV1Section() { + public UsCoV1 getUsCoV1Section() throws LazyDecodingException { return (UsCoV1) getSection(UsCoV1.NAME); } - public UsUtV1 getUspUtV1Section() { + public UsUtV1 getUsUtV1Section() throws LazyDecodingException { return (UsUtV1) getSection(UsUtV1.NAME); } - public UsCtV1 getUspCtV1Section() { + public UsCtV1 getUsCtV1Section() throws LazyDecodingException { return (UsCtV1) getSection(UsCtV1.NAME); } - public List getSectionIds() { + public List getSectionIds() throws LazyDecodingException { + // lazily decode + if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { + try { + this.decode(this.encodedString); + } catch (DecodingException e) { + throw new LazyDecodingException(e); + } + } + List sectionIds = new ArrayList<>(); for (int i = 0; i < Sections.SECTION_ORDER.size(); i++) { String sectionName = Sections.SECTION_ORDER.get(i); @@ -196,7 +283,20 @@ public List getSectionIds() { return sectionIds; } - public String encode() throws EncodingException { + public String encode() throws EncodingException, LazyDecodingException { + if (!this.dirty) { + return this.encodedString; + } + + // lazily decode + if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { + try { + this.decode(this.encodedString); + } catch (DecodingException e) { + throw new LazyDecodingException(e); + } + } + List encodedSections = new ArrayList<>(); List sectionIds = new ArrayList<>(); for (int i = 0; i < Sections.SECTION_ORDER.size(); i++) { @@ -216,11 +316,13 @@ public String encode() throws EncodingException { } encodedSections.add(0, header.encode()); - String encodedString = encodedSections.stream().collect(Collectors.joining("~")); + this.encodedString = encodedSections.stream().collect(Collectors.joining("~")); + this.dirty = false; return encodedString; } public void decode(String str) throws DecodingException { + this.encodedString = str; this.sections.clear(); String[] encodedSections = str.split("~"); @@ -259,13 +361,25 @@ public void decode(String str) throws DecodingException { this.sections.put(UsCtV1.NAME, section); } } + + this.decoded = true; + this.dirty = false; } - public String encodeSection(int sectionId) throws EncodingException { + public String encodeSection(int sectionId) throws EncodingException, LazyDecodingException { return encodeSection(Sections.SECTION_ID_NAME_MAP.get(sectionId)); } - public String encodeSection(String sectionName) throws EncodingException { + public String encodeSection(String sectionName) throws EncodingException, LazyDecodingException { + // lazily decode + if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { + try { + this.decode(this.encodedString); + } catch (DecodingException e) { + throw new LazyDecodingException(e); + } + } + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName).encode(); } else { @@ -278,6 +392,15 @@ public void decodeSection(int sectionId, String encodedString) throws DecodingEx } public void decodeSection(String sectionName, String encodedString) throws DecodingException { + // lazily decode + if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { + try { + this.decode(this.encodedString); + } catch (DecodingException e) { + throw new LazyDecodingException(e); + } + } + EncodableSection section = null; if (!this.sections.containsKey(sectionName)) { if (sectionName.equals(TcfEuV2.NAME)) { @@ -314,6 +437,7 @@ public void decodeSection(String sectionName, String encodedString) throws Decod if (section != null) { section.decode(encodedString); + this.dirty = true; } } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index a28858af..38180f4e 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -60,11 +60,12 @@ public void testEncodeDefault() throws EncodingException, LazyDecodingException } @Test - public void testDecodingException() { + public void testLazyDecodingException() { + GppModel gppModel = new GppModel("invalid gpp string"); try { - GppModel gppModel = new GppModel("invalid gpp string"); + gppModel.getHeader(); Assertions.fail("Expected LazyDecodingException"); - } catch (DecodingException e) { + } catch (LazyDecodingException e) { } } @@ -655,9 +656,9 @@ public void testConsistency() throws InvalidFieldException, EncodingException, D GppModel fromObjectModel = new GppModel(); fromObjectModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.PURPOSE_CONSENTS, - Arrays.asList(true, true, true, true, true, true, true, true, true, true)); + new ArrayList<>(List.of(true, true, true, true, true, true, true, true, true, true))); fromObjectModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS, - Arrays.asList(32, 128, 81, 210, 755, 21, 173, 238)); + new ArrayList<>(List.of(32, 128, 81, 210, 755, 21, 173, 238))); Assertions.assertEquals(fromObjectModel.getSection(TcfEuV2.NAME).encode(), fromObjectModel.getSection(TcfEuV2.NAME).encode()); @@ -666,10 +667,10 @@ public void testConsistency() throws InvalidFieldException, EncodingException, D GppModel decodedModel = new GppModel(fromObjectModel.encode()); Assertions.assertEquals( - Arrays.asList(true, true, true, true, true, true, true, true, true, true, false, false, false, false, - false, false, false, false, false, false, false, false, false, false), + new ArrayList<>(List.of(true, true, true, true, true, true, true, true, true, true, false, false, false, false, + false, false, false, false, false, false, false, false, false, false)), decodedModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.PURPOSE_CONSENTS)); - Assertions.assertEquals(Arrays.asList(21, 32, 81, 128, 173, 210, 238, 755), + Assertions.assertEquals(new ArrayList<>(List.of(21, 32, 81, 128, 173, 210, 238, 755)), decodedModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java index 49b204d2..eae50785 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java @@ -100,7 +100,7 @@ public void testDecode1() throws DecodingException { @Test public void testDecode2() throws DecodingException { - TcfCaV1 tcfCaV1 = new TcfCaV1("CPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACAC.fHHHA4444ao"); + TcfCaV1 tcfCaV1 = new TcfCaV1("BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACAC.fHHHA4444ao"); Assertions.assertEquals(50, tcfCaV1.getCmpId()); Assertions.assertEquals(2, tcfCaV1.getCmpVersion()); From 89c5567249b0c7aac574c0005a9930ed58d4e5bd Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 30 Aug 2023 21:21:31 -0600 Subject: [PATCH 02/36] java 8 compatible gppmodel tests --- .../java/com/iab/gpp/encoder/GppModelTest.java | 15 +++++++-------- .../test/resources/vendorlist/v2/purposes-fr.json | 1 + .../resources/vendorlist/v3.0/purposes-fr.json | 1 + 3 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 iabgpp-extras-jackson/src/test/resources/vendorlist/v2/purposes-fr.json create mode 100644 iabgpp-extras-jackson/src/test/resources/vendorlist/v3.0/purposes-fr.json diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index 38180f4e..f46c51ab 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -4,7 +4,6 @@ import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; @@ -18,8 +17,8 @@ import com.iab.gpp.encoder.field.UsCtV1Field; import com.iab.gpp.encoder.field.UsNatV1Field; import com.iab.gpp.encoder.field.UsUtV1Field; -import com.iab.gpp.encoder.field.UspV1Field; import com.iab.gpp.encoder.field.UsVaV1Field; +import com.iab.gpp.encoder.field.UspV1Field; import com.iab.gpp.encoder.section.TcfCaV1; import com.iab.gpp.encoder.section.TcfEuV2; import com.iab.gpp.encoder.section.UsCaV1; @@ -27,8 +26,8 @@ import com.iab.gpp.encoder.section.UsCtV1; import com.iab.gpp.encoder.section.UsNatV1; import com.iab.gpp.encoder.section.UsUtV1; -import com.iab.gpp.encoder.section.UspV1; import com.iab.gpp.encoder.section.UsVaV1; +import com.iab.gpp.encoder.section.UspV1; public class GppModelTest { @@ -656,9 +655,9 @@ public void testConsistency() throws InvalidFieldException, EncodingException, D GppModel fromObjectModel = new GppModel(); fromObjectModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.PURPOSE_CONSENTS, - new ArrayList<>(List.of(true, true, true, true, true, true, true, true, true, true))); + Arrays.asList(true, true, true, true, true, true, true, true, true, true)); fromObjectModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS, - new ArrayList<>(List.of(32, 128, 81, 210, 755, 21, 173, 238))); + Arrays.asList(32, 128, 81, 210, 755, 21, 173, 238)); Assertions.assertEquals(fromObjectModel.getSection(TcfEuV2.NAME).encode(), fromObjectModel.getSection(TcfEuV2.NAME).encode()); @@ -667,10 +666,10 @@ public void testConsistency() throws InvalidFieldException, EncodingException, D GppModel decodedModel = new GppModel(fromObjectModel.encode()); Assertions.assertEquals( - new ArrayList<>(List.of(true, true, true, true, true, true, true, true, true, true, false, false, false, false, - false, false, false, false, false, false, false, false, false, false)), + Arrays.asList(true, true, true, true, true, true, true, true, true, true, false, false, false, false, + false, false, false, false, false, false, false, false, false, false), decodedModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.PURPOSE_CONSENTS)); - Assertions.assertEquals(new ArrayList<>(List.of(21, 32, 81, 128, 173, 210, 238, 755)), + Assertions.assertEquals(Arrays.asList(21, 32, 81, 128, 173, 210, 238, 755), decodedModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS)); } diff --git a/iabgpp-extras-jackson/src/test/resources/vendorlist/v2/purposes-fr.json b/iabgpp-extras-jackson/src/test/resources/vendorlist/v2/purposes-fr.json new file mode 100644 index 00000000..98cfa81b --- /dev/null +++ b/iabgpp-extras-jackson/src/test/resources/vendorlist/v2/purposes-fr.json @@ -0,0 +1 @@ +{"vendorListVersion":29,"lastUpdated":"2020-03-12T16:40:38Z","purposes":{"1":{"id":1,"name":"Stocker et/ou acc\u00e9der \u00e0 des informations stock\u00e9es sur un terminal","description":"Les cookies, identifiants de votre terminal ou autres informations peuvent \u00eatre stock\u00e9s ou consult\u00e9s sur votre terminal pour les finalit\u00e9s qui vous sont pr\u00e9sent\u00e9es.","descriptionLegal":"Les partenaires peuvent :\n* Stocker des informations et acc\u00e9der \u00e0 des informations stock\u00e9es sur le terminal, comme les cookies et les identifiants du terminal pr\u00e9sent\u00e9s \u00e0 un utilisateur.\n"},"2":{"id":2,"name":"S\u00e9lectionner des publicit\u00e9s standard","description":"Les publicit\u00e9s peuvent vous \u00eatre pr\u00e9sent\u00e9es en fonction du contenu \u00e9ditorial que vous consultez, de l\u2019application que vous utilisez, de votre localisation approximative, ou de votre type de terminal\n","descriptionLegal":"Pour s\u00e9lectionner des publicit\u00e9s standard, les partenaires peuvent :\n* Utiliser des informations en temps r\u00e9el sur le contexte dans lequel la publicit\u00e9 sera affich\u00e9e, pour afficher la publicit\u00e9, y compris des informations sur le contenu et le terminal, telles que : type de terminal et capacit\u00e9s, user agent, URL, adresse IP \n* Utiliser des donn\u00e9es de g\u00e9olocalisation non-pr\u00e9cises d\u2019un utilisateur\n* Contr\u00f4ler la fr\u00e9quence de diffusion des publicit\u00e9s \u00e0 un utilisateur.\n* D\u00e9finir l\u2019ordre dans lequel les publicit\u00e9s sont pr\u00e9sent\u00e9es \u00e0 un utilisateur.\n* Emp\u00eacher une publicit\u00e9 de s\u2019afficher dans un contexte \u00e9ditorial inadapt\u00e9 (dangereux pour la marque)\nLes partenaires ne peuvent pas :\n* Cr\u00e9er un profil publicitaire personnalis\u00e9 \u00e0 l\u2019aide de ces informations pour la s\u00e9lection de publicit\u00e9s futures sans base l\u00e9gale distincte. \nN.B. \u00ab Non-pr\u00e9cises \u00bb signifie qu\u2019une g\u00e9olocalisation approximative dans un rayon d\u2019au moins 500 m\u00e8tres est autoris\u00e9e.\n"},"3":{"id":3,"name":"Cr\u00e9er un profil personnalis\u00e9 de publicit\u00e9s","description":"Un profil peut \u00eatre cr\u00e9\u00e9 sur vous et sur vos centres d\u2019int\u00e9r\u00eat pour vous pr\u00e9senter des publicit\u00e9s personnalis\u00e9es susceptibles de vous int\u00e9resser.","descriptionLegal":"Pour cr\u00e9er un profil de publicit\u00e9s personnalis\u00e9es, les partenaires peuvent :\n* Collecter des informations sur un utilisateur, notamment son activit\u00e9, ses centres d\u2019int\u00e9r\u00eat, les sites ou applications consult\u00e9s, les donn\u00e9es d\u00e9mographiques ou la g\u00e9olocalisation d\u2019un utilisateur, pour cr\u00e9er ou modifier un profil utilisateur \u00e0 utiliser dans des publicit\u00e9s personnalis\u00e9es.\n"},"4":{"id":4,"name":"S\u00e9lectionner des publicit\u00e9s personnalis\u00e9es","description":"Des publicit\u00e9s personnalis\u00e9es peuvent vous \u00eatre pr\u00e9sent\u00e9es sur la base d\u2019un profil cr\u00e9\u00e9 sur vous.","descriptionLegal":"Pour s\u00e9lectionner des publicit\u00e9s personnalis\u00e9es, les partenaires peuvent :\n* S\u00e9lectionner des publicit\u00e9s personnalis\u00e9es sur la base d\u2019un profil utilisateur ou d\u2019autres donn\u00e9es d\u2019utilisateur historiques, y compris l\u2019activit\u00e9 pass\u00e9e d\u2019un utilisateur, ses centres d\u2019int\u00e9r\u00eat, les sites qu\u2019il a visit\u00e9s ou les applications qu\u2019il a utilis\u00e9es, sa localisation ou ses donn\u00e9es d\u00e9mographiques.\n"},"5":{"id":5,"name":"Cr\u00e9er un profil pour afficher un contenu personnalis\u00e9","description":"Un profil peut \u00eatre cr\u00e9\u00e9 sur vous et sur vos centres d\u2019int\u00e9r\u00eat afin de vous pr\u00e9senter du contenu personnalis\u00e9 susceptible de vous int\u00e9resser.","descriptionLegal":"Pour cr\u00e9er un profil pour afficher du contenu personnalis\u00e9, les partenaires peuvent :\n* Collecter des informations sur un utilisateur, y compris l\u2019activit\u00e9 d\u2019un utilisateur, ses centres d\u2019int\u00e9r\u00eat, les sites qu\u2019il a visit\u00e9s ou les applications qu\u2019il a utilis\u00e9es, ses donn\u00e9es d\u00e9mographiques ou sa localisation, pour cr\u00e9er ou modifier un profil utilisateur pour afficher du contenu personnalis\u00e9.\n"},"6":{"id":6,"name":"S\u00e9lectionner du contenu personnalis\u00e9","description":"Du contenu personnalis\u00e9 peut vous \u00eatre pr\u00e9sent\u00e9 sur la base de votre profil utilisateur. ","descriptionLegal":"Pour s\u00e9lectionner du contenu personnalis\u00e9, les partenaires peuvent :\n* S\u00e9lectionner du contenu personnalis\u00e9 sur la base d\u2019un profil utilisateur induit des donn\u00e9es relatives \u00e0 son activit\u00e9 en ligne, ses centres d\u2019int\u00e9r\u00eat, les sites qu\u2019il a visit\u00e9s, les applications qu\u2019il a utilis\u00e9es, sa localisation ou ses donn\u00e9es socio-d\u00e9mographiques.\n"},"7":{"id":7,"name":"Mesurer la performance des publicit\u00e9s","description":"La performance et l\u2019efficacit\u00e9 des publicit\u00e9s que vous voyez ou avec lesquelles vous interagissez peuvent \u00eatre mesur\u00e9es.","descriptionLegal":"Pour mesurer la performance des publicit\u00e9s, les partenaires peuvent:\n* Mesurer si et comment des publicit\u00e9s ont \u00e9t\u00e9 pr\u00e9sent\u00e9e \u00e0 un utilisateur et comment celui-ci a interagi avec celles-ci\n* G\u00e9n\u00e9rer des rapports sur les publicit\u00e9s, notamment sur leur performance\n* G\u00e9n\u00e9rer des rapports sur les utilisateurs ayant interagi avec des publicit\u00e9s en utilisant des donn\u00e9es issues de cette interaction \n* Fournir des rapports aux \u00e9diteurs sur les publicit\u00e9s pr\u00e9sent\u00e9es/affich\u00e9es sur leurs propri\u00e9t\u00e9s num\u00e9riques \n* \u00c9valuer si une publicit\u00e9 diffus\u00e9e dans un contexte \u00e9ditorial appropri\u00e9 (conforme \u00e0 l\u2019image de la marque) sans danger pour la marque)\n* D\u00e9terminer le pourcentage du visionnage \u00e9ventuel de la publicit\u00e9 et sa dur\u00e9e \n* Combiner ces informations avec d\u2019autres informations collect\u00e9es au pr\u00e9alable, pouvant provenir de sites internet et applications\nLes partenaires ne peuvent pas: \n* Croiser des donn\u00e9es d\u2019audience, issues ou d\u00e9riv\u00e9es d\u2019un panel, avec des donn\u00e9es de mesure de performance, sans base l\u00e9gale pour titre \"Finalit\u00e9 9\". \n"},"8":{"id":8,"name":"Mesurer la performance du contenu","description":"La performance et l\u2019efficacit\u00e9 du contenu que vous voyez ou avec lequel vous interagissez peuvent \u00eatre mesur\u00e9es.","descriptionLegal":"Pour mesurer la performance du contenu, les partenaires peuvent:\n* Mesurer comment le contenu a \u00e9t\u00e9 diffus\u00e9 et comment les utilisateurs ont interagi avec, et g\u00e9n\u00e9rer des rapports.\n* G\u00e9n\u00e9rer des rapports \u00e0 l\u2019aide d\u2019informations directement mesurables ou connues, sur les utilisateurs qui ont interagi avec le contenu\nLes partenaires ne peuvent pas:\n* Mesurer si et comment des publicit\u00e9s (y compris des publicit\u00e9s natives) ont \u00e9t\u00e9 pr\u00e9sent\u00e9es \u00e0 un utilisateur et comment celui-ci a interagi avec, sans base l\u00e9gale distincte\n* Croiser des donn\u00e9es d\u2019audience, issues ou d\u00e9riv\u00e9es d\u2019un panel, avec des donn\u00e9es de mesure de performance, sans base l\u00e9gale pour titre \"Finalit\u00e9 9\u201d. "},"9":{"id":9,"name":"Exploiter des \u00e9tudes de march\u00e9 afin de g\u00e9n\u00e9rer des donn\u00e9es d\u2019audience","description":"Les \u00e9tudes de march\u00e9 peuvent servir \u00e0 en apprendre davantage sur les audiences qui visitent des sites/utilisent des applications et voient des publicit\u00e9s.","descriptionLegal":"Pour utiliser des \u00e9tudes de march\u00e9 afin de g\u00e9n\u00e9rer des donn\u00e9es d\u2019audience, les partenaires peuvent:\n* Fournir des rapports agr\u00e9g\u00e9s aux annonceurs ou \u00e0 leurs repr\u00e9sentants sur les audiences expos\u00e9es \u00e0 leurs publicit\u00e9s, en utilisant des donn\u00e9es issues d\u2019un panel ou d\u2019un autre dispositif.\n* Fournir des rapports agr\u00e9g\u00e9s aux \u00e9diteurs sur les audiences expos\u00e9es \u00e0 des contenus et/ou des publicit\u00e9s ou qui ont interagi avec des contenus et/ou les publicit\u00e9s sur leurs sites, en utilisant des donn\u00e9es issues d\u2019un panel ou d\u2019un autre dispositif. \n* Combiner des donn\u00e9es hors ligne \u00e0 celles d\u2019un utilisateur en ligne dans le cadre d\u2019\u00e9tudes de march\u00e9 pour g\u00e9n\u00e9rer des donn\u00e9es d\u2019audience si les partenaires ont d\u00e9clar\u00e9 faire correspondre et associer des sources de donn\u00e9es hors ligne (Fonctionnalit\u00e9 1)\n* Texte dans la version anglaise : Combiner ces informations avec des donn\u00e9es d\u00e9j\u00e0 collect\u00e9es que ce soit sur le web ou via des applications. \nLes partenaires ne peuvent pas : \n* Mesurer la performance et l\u2019efficacit\u00e9 des publicit\u00e9s qui ont \u00e9t\u00e9 pr\u00e9sent\u00e9es \u00e0 un utilisateur en particulier, ou avec lesquelles il a interagi, sans s\u2019appuyer sur une base l\u00e9gale sp\u00e9cifique pour la mesure de la performance publicitaire.\n* \u00c9valuer le contenu qui a \u00e9t\u00e9 pr\u00e9sent\u00e9 \u00e0 un utilisateur en particulier et la fa\u00e7on dont ce dernier a r\u00e9agi sans s\u2019appuyer sur une base l\u00e9gale sp\u00e9cifique pour la mesure de la performance des contenus.\n"},"10":{"id":10,"name":"D\u00e9velopper et am\u00e9liorer les produits","description":"Vos donn\u00e9es peuvent \u00eatre utilis\u00e9es pour am\u00e9liorer les syst\u00e8mes et logiciels existants et pour d\u00e9velopper de nouveaux produits.","descriptionLegal":"Pour d\u00e9velopper de nouveaux produits et am\u00e9liorer des produits existants, les partenaires peuvent:\n* Utiliser des informations pour am\u00e9liorer leurs produits existants en y ajoutant de nouvelles fonctionnalit\u00e9s et pour d\u00e9velopper de nouveaux produits\n* Cr\u00e9er de nouveaux mod\u00e8les et algorithmes gr\u00e2ce au machine-learning \nLes partenaires ne peuvent pas:\n* Effectuer toute autre op\u00e9ration de traitement des donn\u00e9es autoris\u00e9e par une autre finalit\u00e9 dans le cadre de cette finalit\u00e9\n"}},"specialPurposes":{"1":{"id":1,"name":"Assurer la s\u00e9curit\u00e9, pr\u00e9venir la fraude et d\u00e9boguer","description":"Vos donn\u00e9es peuvent \u00eatre utilis\u00e9es pour surveiller et pr\u00e9venir les activit\u00e9s frauduleuses, et s\u2019assurer que les syst\u00e8mes et processus fonctionnent correctement et en toute s\u00e9curit\u00e9.","descriptionLegal":"Pour garantir la s\u00e9curit\u00e9, pr\u00e9venir la fraude et d\u00e9boguer, les partenaires peuvent:\n* Veiller \u00e0 ce que les donn\u00e9es soient transmises en toute s\u00e9curit\u00e9 \n* D\u00e9tecter et pr\u00e9venir les activit\u00e9s malveillantes, frauduleuses, inappropri\u00e9es ou ill\u00e9gales.\n* Assurer un fonctionnement correct et efficace des syst\u00e8mes et des processus, y compris surveiller et am\u00e9liorer la performance des syst\u00e8mes et processus utilis\u00e9s pour des finalit\u00e9s autoris\u00e9es\nLes partenaires ne peuvent pas:\n* Effectuer, au titre de cette finalit\u00e9, toute autre op\u00e9ration de traitement des donn\u00e9es autoris\u00e9e pour une finalit\u00e9 diff\u00e9rente .\nRemarque: Les donn\u00e9es collect\u00e9es et utilis\u00e9es pour assurer la s\u00e9curit\u00e9, pr\u00e9venir la fraude et d\u00e9boguer peuvent inclure des caract\u00e9ristiques d\u2019appareil envoy\u00e9es automatiquement \u00e0 des fins d'identification, des donn\u00e9es de g\u00e9olocalisation pr\u00e9cises et des donn\u00e9es obtenues par l\u2019analyse active des caract\u00e9ristiques de l\u2019appareil \u00e0 des fins d\u2019identification sans notification distincte et/ou opt-in distinct \n"},"2":{"id":2,"name":"Diffuser techniquement les publicit\u00e9s ou le contenu","description":"Votre terminal peut recevoir et envoyer des informations qui vous permettent de voir des publicit\u00e9s et du contenu et d\u2019interagir avec eux.","descriptionLegal":"Pour fournir des informations et r\u00e9pondre aux appels techniques, les partenaires peuvent:\n* Utiliser l\u2019adresse IP d\u2019un utilisateur pour diffuser une publicit\u00e9 sur Internet\n* R\u00e9agir \u00e0 l\u2019interaction d\u2019un utilisateur avec une publicit\u00e9 en dirigeant l\u2019utilisateur vers une page d\u2019accueil\n* Utiliser l\u2019adresse IP d\u2019un utilisateur pour diffuser du contenu sur Internet\n* R\u00e9agir \u00e0 l\u2019interaction d\u2019un utilisateur avec du contenu en dirigeant l\u2019utilisateur vers une page d\u2019accueil\n* Utiliser des informations sur le type de terminal et les capacit\u00e9s du terminal pour pr\u00e9senter des publicit\u00e9s ou du contenu, par exemple, pour pr\u00e9senter une publicit\u00e9 \u00e0 la bonne taille ou une vid\u00e9o dans un format pris en charge par le terminal \nLes partenaires ne peuvent pas:\n* Effectuer, au titre de cette finalit\u00e9, toute autre op\u00e9ration de traitement des donn\u00e9es autoris\u00e9e pour une finalit\u00e9 diff\u00e9rente \n"}},"features":{"1":{"id":1,"name":"Mettre en correspondance et combiner des sources de donn\u00e9es hors ligne","description":"Les donn\u00e9es issues de sources de donn\u00e9es hors ligne peuvent \u00eatre combin\u00e9es \u00e0 votre activit\u00e9 en ligne \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s.","descriptionLegal":"Les partenaires peuvent : \n* Combiner des donn\u00e9es obtenues hors ligne avec des donn\u00e9es collect\u00e9es en ligne \u00e0 l\u2019appui d\u2019une ou de plusieurs Finalit\u00e9s ou Finalit\u00e9s sp\u00e9ciales.\n"},"2":{"id":2,"name":"Relier diff\u00e9rents terminaux","description":"Diff\u00e9rents terminaux peuvent \u00eatre identifi\u00e9s comme vous appartenant ou appartenant \u00e0 votre foyer \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s","descriptionLegal":"Les partnenaires peuvent :\n* D\u00e9terminer, selon une approche d\u00e9terministe, que deux terminaux ou plus appartiennent au m\u00eame utilisateur ou au m\u00eame foyer\n* D\u00e9terminer, selon une approche probabiliste, que deux terminaux ou plus appartiennent au m\u00eame utilisateur ou au m\u00eame foyer\n* Analyser activement les caract\u00e9ristiques du terminal pour l\u2019identification probabiliste si les utilisateurs ont autoris\u00e9 les partenanaires \u00e0 analyser activement les caract\u00e9ristiques du terminal pour l\u2019identification (Fonctionnalit\u00e9 sp\u00e9ciale 2)\n"},"3":{"id":3,"name":"Recevoir et utiliser des caract\u00e9ristiques d\u2019identification d\u2019appareil envoy\u00e9es automatiquement","description":"Votre appareil peut \u00eatre distingu\u00e9 d\u2019autres appareils en fonction des informations qu\u2019il envoie automatiquement, telles que l\u2019adresse IP ou le type de navigateur.","descriptionLegal":"Les partenaires peuvent :\n* Cr\u00e9er un identifiant \u00e0 l\u2019aide des donn\u00e9es collect\u00e9es automatiquement \u00e0 partir d\u2019un appareil pour des caract\u00e9ristiques sp\u00e9cifiques ; par ex., adresse IP, cha\u00eene d\u2019agent utilisateur.\n* Utiliser cet identifiant pour r\u00e9identifier un appareil.\nLes partenaires ne peuvent pas :\n* Cr\u00e9er un identifiant \u00e0 l\u2019aide des donn\u00e9es collect\u00e9es via une analyse active d\u2019un terminal pour l\u2019identification de caract\u00e9ristiques sp\u00e9cifiques (par exemple, des polices install\u00e9es ou la r\u00e9solution d\u2019\u00e9cran) sans une adh\u00e9sion distincte de l\u2019utilisateur \u00e0 l\u2019analyse active des caract\u00e9ristiques de l\u2019appareil \u00e0 des fins d\u2019identification.\n* Utiliser cet identifiant pour r\u00e9-identifier un terminal.\n"}},"specialFeatures":{"1":{"id":1,"name":"Utiliser des donn\u00e9es de g\u00e9olocalisation pr\u00e9cises","description":"Vos donn\u00e9es de g\u00e9olocalisation pr\u00e9cises peuvent \u00eatre utilis\u00e9es \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s. Cela signifie que votre localisation peut \u00eatre pr\u00e9cise \u00e0 plusieurs m\u00e8tres pr\u00e8s.","descriptionLegal":"Les partnenaires peuvent :\n* Collecter et traiter des donn\u00e9es de g\u00e9olocalisation pr\u00e9cises \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s.\nN.B. Une g\u00e9olocalisation pr\u00e9cise signifie qu\u2019il n\u2019y a aucune restriction \u00e0 la pr\u00e9cision de la localisation d\u2019un utilisateur ; elle peut \u00eatre pr\u00e9cise \u00e0 quelques m\u00e8tres pr\u00e8s.\n"},"2":{"id":2,"name":"Analyser activement les caract\u00e9ristiques du terminal pour l\u2019identification","description":"Votre terminal peut \u00eatre identifi\u00e9 sur la base d\u2019une analyse de la combinaison unique de caract\u00e9ristiques de votre terminal.","descriptionLegal":"Les partenaires peuvent :\n* Cr\u00e9er un identifiant \u00e0 l\u2019aide des donn\u00e9es collect\u00e9es via une analyse active d\u2019un terminal pour l\u2019identification de caract\u00e9ristiques sp\u00e9cifiques, par exemple des polices install\u00e9es ou la r\u00e9solution d\u2019\u00e9cran. \n* Utiliser cet identifiant pour r\u00e9-identifier un terminal.\n"}},"stacks":{"1":{"id":1,"purposes":[],"specialFeatures":[1,2],"name":"Donn\u00e9es de g\u00e9olocalisation pr\u00e9cises et identification par analyse du terminal","description":"Des informations de g\u00e9olocalisation pr\u00e9cises et des informations sur les caract\u00e9ristiques de l\u2019appareil peuvent \u00eatre utilis\u00e9es."},"2":{"id":2,"purposes":[2,7],"specialFeatures":[],"name":"Publicit\u00e9s standards et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"3":{"id":3,"purposes":[2,3,4],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s."},"4":{"id":4,"purposes":[2,7,9],"specialFeatures":[],"name":"Publicit\u00e9s standards et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"5":{"id":5,"purposes":[2,3,7],"specialFeatures":[],"name":"Publicit\u00e9s standards, profil de publicit\u00e9s personnalis\u00e9es et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"6":{"id":6,"purposes":[2,4,7],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es et mesure de performance des publicit\u00e9s","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"7":{"id":7,"purposes":[2,4,7,9],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es, mesure de performance des publicit\u00e9s, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"8":{"id":8,"purposes":[2,3,4,7],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es et mesure de performance des annonces","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"9":{"id":9,"purposes":[2,3,4,7,9],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es, mesure de performance des publicit\u00e9s, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"10":{"id":10,"purposes":[3,4],"specialFeatures":[],"name":"Profil de publicit\u00e9s personnalis\u00e9es et affichage","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. "},"11":{"id":11,"purposes":[5,6],"specialFeatures":[],"name":"Contenu personnalis\u00e9","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu."},"12":{"id":12,"purposes":[6,8],"specialFeatures":[],"name":"Affichage de contenu personnalis\u00e9 et mesure de performance du contenu","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. La performance du contenu peut \u00eatre mesur\u00e9e."},"13":{"id":13,"purposes":[6,8,9],"specialFeatures":[],"name":"Affichage de contenu personnalis\u00e9, mesure de performance du contenu et donn\u00e9es d\u2019audience","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"14":{"id":14,"purposes":[5,6,8],"specialFeatures":[],"name":"Contenu personnalis\u00e9 et mesure de performance du contenu","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e."},"15":{"id":15,"purposes":[5,6,8,9],"specialFeatures":[],"name":"Contenu personnalis\u00e9, mesure de performance du contenu et donn\u00e9es d\u2019audience","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"16":{"id":16,"purposes":[5,6,8,9,10],"specialFeatures":[],"name":"Contenu personnalis\u00e9, mesure de performance du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, des syst\u00e8mes et logiciels"},"17":{"id":17,"purposes":[7,8,9],"specialFeatures":[],"name":"Mesure de performance des annonces et du contenu et donn\u00e9es d\u2019audience","description":"La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"18":{"id":18,"purposes":[7,8],"specialFeatures":[],"name":"Mesure de performance des publicit\u00e9s et du contenu","description":"La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e."},"19":{"id":19,"purposes":[7,9],"specialFeatures":[],"name":"Mesure de performance des publicit\u00e9s et donn\u00e9es d\u2019audience","description":"La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu"},"20":{"id":20,"purposes":[7,8,9,10],"specialFeatures":[],"name":"Mesure de performance des publicit\u00e9s et du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit","description":"La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"21":{"id":21,"purposes":[8,9,10],"specialFeatures":[],"name":"Mesure de performance du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit.","description":"La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"22":{"id":22,"purposes":[8,10],"specialFeatures":[],"name":"Mesure de performance du contenu, et d\u00e9veloppement produit","description":"La performance du contenu peut \u00eatre mesur\u00e9e. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"23":{"id":23,"purposes":[2,4,6,7,8],"specialFeatures":[],"name":"Affichage de publicit\u00e9s et de contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e."},"24":{"id":24,"purposes":[2,4,6,7,8,9],"specialFeatures":[],"name":"Affichage de publicit\u00e9s et de contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"25":{"id":25,"purposes":[2,3,4,5,6,7,8],"specialFeatures":[],"name":"Publicit\u00e9s et contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s et le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e."},"26":{"id":26,"purposes":[2,3,4,5,6,7,8,9],"specialFeatures":[],"name":"Publicit\u00e9s et contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s et le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"27":{"id":27,"purposes":[3,5],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es et profil de contenu","description":"Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour personnaliser les publicit\u00e9s et le contenu. "},"28":{"id":28,"purposes":[2,4,6],"specialFeatures":[],"name":"Affichage de publicit\u00e9s et de contenu personnalis\u00e9s","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. "},"29":{"id":29,"purposes":[2,7,8,9],"specialFeatures":[],"name":"Publicit\u00e9s standards, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"30":{"id":30,"purposes":[2,4,5,6,7,8,9],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"31":{"id":31,"purposes":[2,4,5,6,7,8,9,10],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, donn\u00e9es d\u2019audience et d\u00e9veloppement de produit","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"32":{"id":32,"purposes":[2,5,6,7,8,9],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"33":{"id":33,"purposes":[2,5,6,7,8,9,10],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"34":{"id":34,"purposes":[2,5,6,8,9],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance du contenu, et donn\u00e9es d\u2019audience","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"35":{"id":35,"purposes":[2,5,6,8,9,10],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance du contenu, donn\u00e9es d\u2019audience et d\u00e9veloppement de produit ","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"36":{"id":36,"purposes":[2,5,6,7],"specialFeatures":[],"name":"Publicit\u00e9s standard, contenu personnalis\u00e9 et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"37":{"id":37,"purposes":[2,5,6,7,10],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s, et d\u00e9veloppement produit","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."}}} \ No newline at end of file diff --git a/iabgpp-extras-jackson/src/test/resources/vendorlist/v3.0/purposes-fr.json b/iabgpp-extras-jackson/src/test/resources/vendorlist/v3.0/purposes-fr.json new file mode 100644 index 00000000..98cfa81b --- /dev/null +++ b/iabgpp-extras-jackson/src/test/resources/vendorlist/v3.0/purposes-fr.json @@ -0,0 +1 @@ +{"vendorListVersion":29,"lastUpdated":"2020-03-12T16:40:38Z","purposes":{"1":{"id":1,"name":"Stocker et/ou acc\u00e9der \u00e0 des informations stock\u00e9es sur un terminal","description":"Les cookies, identifiants de votre terminal ou autres informations peuvent \u00eatre stock\u00e9s ou consult\u00e9s sur votre terminal pour les finalit\u00e9s qui vous sont pr\u00e9sent\u00e9es.","descriptionLegal":"Les partenaires peuvent :\n* Stocker des informations et acc\u00e9der \u00e0 des informations stock\u00e9es sur le terminal, comme les cookies et les identifiants du terminal pr\u00e9sent\u00e9s \u00e0 un utilisateur.\n"},"2":{"id":2,"name":"S\u00e9lectionner des publicit\u00e9s standard","description":"Les publicit\u00e9s peuvent vous \u00eatre pr\u00e9sent\u00e9es en fonction du contenu \u00e9ditorial que vous consultez, de l\u2019application que vous utilisez, de votre localisation approximative, ou de votre type de terminal\n","descriptionLegal":"Pour s\u00e9lectionner des publicit\u00e9s standard, les partenaires peuvent :\n* Utiliser des informations en temps r\u00e9el sur le contexte dans lequel la publicit\u00e9 sera affich\u00e9e, pour afficher la publicit\u00e9, y compris des informations sur le contenu et le terminal, telles que : type de terminal et capacit\u00e9s, user agent, URL, adresse IP \n* Utiliser des donn\u00e9es de g\u00e9olocalisation non-pr\u00e9cises d\u2019un utilisateur\n* Contr\u00f4ler la fr\u00e9quence de diffusion des publicit\u00e9s \u00e0 un utilisateur.\n* D\u00e9finir l\u2019ordre dans lequel les publicit\u00e9s sont pr\u00e9sent\u00e9es \u00e0 un utilisateur.\n* Emp\u00eacher une publicit\u00e9 de s\u2019afficher dans un contexte \u00e9ditorial inadapt\u00e9 (dangereux pour la marque)\nLes partenaires ne peuvent pas :\n* Cr\u00e9er un profil publicitaire personnalis\u00e9 \u00e0 l\u2019aide de ces informations pour la s\u00e9lection de publicit\u00e9s futures sans base l\u00e9gale distincte. \nN.B. \u00ab Non-pr\u00e9cises \u00bb signifie qu\u2019une g\u00e9olocalisation approximative dans un rayon d\u2019au moins 500 m\u00e8tres est autoris\u00e9e.\n"},"3":{"id":3,"name":"Cr\u00e9er un profil personnalis\u00e9 de publicit\u00e9s","description":"Un profil peut \u00eatre cr\u00e9\u00e9 sur vous et sur vos centres d\u2019int\u00e9r\u00eat pour vous pr\u00e9senter des publicit\u00e9s personnalis\u00e9es susceptibles de vous int\u00e9resser.","descriptionLegal":"Pour cr\u00e9er un profil de publicit\u00e9s personnalis\u00e9es, les partenaires peuvent :\n* Collecter des informations sur un utilisateur, notamment son activit\u00e9, ses centres d\u2019int\u00e9r\u00eat, les sites ou applications consult\u00e9s, les donn\u00e9es d\u00e9mographiques ou la g\u00e9olocalisation d\u2019un utilisateur, pour cr\u00e9er ou modifier un profil utilisateur \u00e0 utiliser dans des publicit\u00e9s personnalis\u00e9es.\n"},"4":{"id":4,"name":"S\u00e9lectionner des publicit\u00e9s personnalis\u00e9es","description":"Des publicit\u00e9s personnalis\u00e9es peuvent vous \u00eatre pr\u00e9sent\u00e9es sur la base d\u2019un profil cr\u00e9\u00e9 sur vous.","descriptionLegal":"Pour s\u00e9lectionner des publicit\u00e9s personnalis\u00e9es, les partenaires peuvent :\n* S\u00e9lectionner des publicit\u00e9s personnalis\u00e9es sur la base d\u2019un profil utilisateur ou d\u2019autres donn\u00e9es d\u2019utilisateur historiques, y compris l\u2019activit\u00e9 pass\u00e9e d\u2019un utilisateur, ses centres d\u2019int\u00e9r\u00eat, les sites qu\u2019il a visit\u00e9s ou les applications qu\u2019il a utilis\u00e9es, sa localisation ou ses donn\u00e9es d\u00e9mographiques.\n"},"5":{"id":5,"name":"Cr\u00e9er un profil pour afficher un contenu personnalis\u00e9","description":"Un profil peut \u00eatre cr\u00e9\u00e9 sur vous et sur vos centres d\u2019int\u00e9r\u00eat afin de vous pr\u00e9senter du contenu personnalis\u00e9 susceptible de vous int\u00e9resser.","descriptionLegal":"Pour cr\u00e9er un profil pour afficher du contenu personnalis\u00e9, les partenaires peuvent :\n* Collecter des informations sur un utilisateur, y compris l\u2019activit\u00e9 d\u2019un utilisateur, ses centres d\u2019int\u00e9r\u00eat, les sites qu\u2019il a visit\u00e9s ou les applications qu\u2019il a utilis\u00e9es, ses donn\u00e9es d\u00e9mographiques ou sa localisation, pour cr\u00e9er ou modifier un profil utilisateur pour afficher du contenu personnalis\u00e9.\n"},"6":{"id":6,"name":"S\u00e9lectionner du contenu personnalis\u00e9","description":"Du contenu personnalis\u00e9 peut vous \u00eatre pr\u00e9sent\u00e9 sur la base de votre profil utilisateur. ","descriptionLegal":"Pour s\u00e9lectionner du contenu personnalis\u00e9, les partenaires peuvent :\n* S\u00e9lectionner du contenu personnalis\u00e9 sur la base d\u2019un profil utilisateur induit des donn\u00e9es relatives \u00e0 son activit\u00e9 en ligne, ses centres d\u2019int\u00e9r\u00eat, les sites qu\u2019il a visit\u00e9s, les applications qu\u2019il a utilis\u00e9es, sa localisation ou ses donn\u00e9es socio-d\u00e9mographiques.\n"},"7":{"id":7,"name":"Mesurer la performance des publicit\u00e9s","description":"La performance et l\u2019efficacit\u00e9 des publicit\u00e9s que vous voyez ou avec lesquelles vous interagissez peuvent \u00eatre mesur\u00e9es.","descriptionLegal":"Pour mesurer la performance des publicit\u00e9s, les partenaires peuvent:\n* Mesurer si et comment des publicit\u00e9s ont \u00e9t\u00e9 pr\u00e9sent\u00e9e \u00e0 un utilisateur et comment celui-ci a interagi avec celles-ci\n* G\u00e9n\u00e9rer des rapports sur les publicit\u00e9s, notamment sur leur performance\n* G\u00e9n\u00e9rer des rapports sur les utilisateurs ayant interagi avec des publicit\u00e9s en utilisant des donn\u00e9es issues de cette interaction \n* Fournir des rapports aux \u00e9diteurs sur les publicit\u00e9s pr\u00e9sent\u00e9es/affich\u00e9es sur leurs propri\u00e9t\u00e9s num\u00e9riques \n* \u00c9valuer si une publicit\u00e9 diffus\u00e9e dans un contexte \u00e9ditorial appropri\u00e9 (conforme \u00e0 l\u2019image de la marque) sans danger pour la marque)\n* D\u00e9terminer le pourcentage du visionnage \u00e9ventuel de la publicit\u00e9 et sa dur\u00e9e \n* Combiner ces informations avec d\u2019autres informations collect\u00e9es au pr\u00e9alable, pouvant provenir de sites internet et applications\nLes partenaires ne peuvent pas: \n* Croiser des donn\u00e9es d\u2019audience, issues ou d\u00e9riv\u00e9es d\u2019un panel, avec des donn\u00e9es de mesure de performance, sans base l\u00e9gale pour titre \"Finalit\u00e9 9\". \n"},"8":{"id":8,"name":"Mesurer la performance du contenu","description":"La performance et l\u2019efficacit\u00e9 du contenu que vous voyez ou avec lequel vous interagissez peuvent \u00eatre mesur\u00e9es.","descriptionLegal":"Pour mesurer la performance du contenu, les partenaires peuvent:\n* Mesurer comment le contenu a \u00e9t\u00e9 diffus\u00e9 et comment les utilisateurs ont interagi avec, et g\u00e9n\u00e9rer des rapports.\n* G\u00e9n\u00e9rer des rapports \u00e0 l\u2019aide d\u2019informations directement mesurables ou connues, sur les utilisateurs qui ont interagi avec le contenu\nLes partenaires ne peuvent pas:\n* Mesurer si et comment des publicit\u00e9s (y compris des publicit\u00e9s natives) ont \u00e9t\u00e9 pr\u00e9sent\u00e9es \u00e0 un utilisateur et comment celui-ci a interagi avec, sans base l\u00e9gale distincte\n* Croiser des donn\u00e9es d\u2019audience, issues ou d\u00e9riv\u00e9es d\u2019un panel, avec des donn\u00e9es de mesure de performance, sans base l\u00e9gale pour titre \"Finalit\u00e9 9\u201d. "},"9":{"id":9,"name":"Exploiter des \u00e9tudes de march\u00e9 afin de g\u00e9n\u00e9rer des donn\u00e9es d\u2019audience","description":"Les \u00e9tudes de march\u00e9 peuvent servir \u00e0 en apprendre davantage sur les audiences qui visitent des sites/utilisent des applications et voient des publicit\u00e9s.","descriptionLegal":"Pour utiliser des \u00e9tudes de march\u00e9 afin de g\u00e9n\u00e9rer des donn\u00e9es d\u2019audience, les partenaires peuvent:\n* Fournir des rapports agr\u00e9g\u00e9s aux annonceurs ou \u00e0 leurs repr\u00e9sentants sur les audiences expos\u00e9es \u00e0 leurs publicit\u00e9s, en utilisant des donn\u00e9es issues d\u2019un panel ou d\u2019un autre dispositif.\n* Fournir des rapports agr\u00e9g\u00e9s aux \u00e9diteurs sur les audiences expos\u00e9es \u00e0 des contenus et/ou des publicit\u00e9s ou qui ont interagi avec des contenus et/ou les publicit\u00e9s sur leurs sites, en utilisant des donn\u00e9es issues d\u2019un panel ou d\u2019un autre dispositif. \n* Combiner des donn\u00e9es hors ligne \u00e0 celles d\u2019un utilisateur en ligne dans le cadre d\u2019\u00e9tudes de march\u00e9 pour g\u00e9n\u00e9rer des donn\u00e9es d\u2019audience si les partenaires ont d\u00e9clar\u00e9 faire correspondre et associer des sources de donn\u00e9es hors ligne (Fonctionnalit\u00e9 1)\n* Texte dans la version anglaise : Combiner ces informations avec des donn\u00e9es d\u00e9j\u00e0 collect\u00e9es que ce soit sur le web ou via des applications. \nLes partenaires ne peuvent pas : \n* Mesurer la performance et l\u2019efficacit\u00e9 des publicit\u00e9s qui ont \u00e9t\u00e9 pr\u00e9sent\u00e9es \u00e0 un utilisateur en particulier, ou avec lesquelles il a interagi, sans s\u2019appuyer sur une base l\u00e9gale sp\u00e9cifique pour la mesure de la performance publicitaire.\n* \u00c9valuer le contenu qui a \u00e9t\u00e9 pr\u00e9sent\u00e9 \u00e0 un utilisateur en particulier et la fa\u00e7on dont ce dernier a r\u00e9agi sans s\u2019appuyer sur une base l\u00e9gale sp\u00e9cifique pour la mesure de la performance des contenus.\n"},"10":{"id":10,"name":"D\u00e9velopper et am\u00e9liorer les produits","description":"Vos donn\u00e9es peuvent \u00eatre utilis\u00e9es pour am\u00e9liorer les syst\u00e8mes et logiciels existants et pour d\u00e9velopper de nouveaux produits.","descriptionLegal":"Pour d\u00e9velopper de nouveaux produits et am\u00e9liorer des produits existants, les partenaires peuvent:\n* Utiliser des informations pour am\u00e9liorer leurs produits existants en y ajoutant de nouvelles fonctionnalit\u00e9s et pour d\u00e9velopper de nouveaux produits\n* Cr\u00e9er de nouveaux mod\u00e8les et algorithmes gr\u00e2ce au machine-learning \nLes partenaires ne peuvent pas:\n* Effectuer toute autre op\u00e9ration de traitement des donn\u00e9es autoris\u00e9e par une autre finalit\u00e9 dans le cadre de cette finalit\u00e9\n"}},"specialPurposes":{"1":{"id":1,"name":"Assurer la s\u00e9curit\u00e9, pr\u00e9venir la fraude et d\u00e9boguer","description":"Vos donn\u00e9es peuvent \u00eatre utilis\u00e9es pour surveiller et pr\u00e9venir les activit\u00e9s frauduleuses, et s\u2019assurer que les syst\u00e8mes et processus fonctionnent correctement et en toute s\u00e9curit\u00e9.","descriptionLegal":"Pour garantir la s\u00e9curit\u00e9, pr\u00e9venir la fraude et d\u00e9boguer, les partenaires peuvent:\n* Veiller \u00e0 ce que les donn\u00e9es soient transmises en toute s\u00e9curit\u00e9 \n* D\u00e9tecter et pr\u00e9venir les activit\u00e9s malveillantes, frauduleuses, inappropri\u00e9es ou ill\u00e9gales.\n* Assurer un fonctionnement correct et efficace des syst\u00e8mes et des processus, y compris surveiller et am\u00e9liorer la performance des syst\u00e8mes et processus utilis\u00e9s pour des finalit\u00e9s autoris\u00e9es\nLes partenaires ne peuvent pas:\n* Effectuer, au titre de cette finalit\u00e9, toute autre op\u00e9ration de traitement des donn\u00e9es autoris\u00e9e pour une finalit\u00e9 diff\u00e9rente .\nRemarque: Les donn\u00e9es collect\u00e9es et utilis\u00e9es pour assurer la s\u00e9curit\u00e9, pr\u00e9venir la fraude et d\u00e9boguer peuvent inclure des caract\u00e9ristiques d\u2019appareil envoy\u00e9es automatiquement \u00e0 des fins d'identification, des donn\u00e9es de g\u00e9olocalisation pr\u00e9cises et des donn\u00e9es obtenues par l\u2019analyse active des caract\u00e9ristiques de l\u2019appareil \u00e0 des fins d\u2019identification sans notification distincte et/ou opt-in distinct \n"},"2":{"id":2,"name":"Diffuser techniquement les publicit\u00e9s ou le contenu","description":"Votre terminal peut recevoir et envoyer des informations qui vous permettent de voir des publicit\u00e9s et du contenu et d\u2019interagir avec eux.","descriptionLegal":"Pour fournir des informations et r\u00e9pondre aux appels techniques, les partenaires peuvent:\n* Utiliser l\u2019adresse IP d\u2019un utilisateur pour diffuser une publicit\u00e9 sur Internet\n* R\u00e9agir \u00e0 l\u2019interaction d\u2019un utilisateur avec une publicit\u00e9 en dirigeant l\u2019utilisateur vers une page d\u2019accueil\n* Utiliser l\u2019adresse IP d\u2019un utilisateur pour diffuser du contenu sur Internet\n* R\u00e9agir \u00e0 l\u2019interaction d\u2019un utilisateur avec du contenu en dirigeant l\u2019utilisateur vers une page d\u2019accueil\n* Utiliser des informations sur le type de terminal et les capacit\u00e9s du terminal pour pr\u00e9senter des publicit\u00e9s ou du contenu, par exemple, pour pr\u00e9senter une publicit\u00e9 \u00e0 la bonne taille ou une vid\u00e9o dans un format pris en charge par le terminal \nLes partenaires ne peuvent pas:\n* Effectuer, au titre de cette finalit\u00e9, toute autre op\u00e9ration de traitement des donn\u00e9es autoris\u00e9e pour une finalit\u00e9 diff\u00e9rente \n"}},"features":{"1":{"id":1,"name":"Mettre en correspondance et combiner des sources de donn\u00e9es hors ligne","description":"Les donn\u00e9es issues de sources de donn\u00e9es hors ligne peuvent \u00eatre combin\u00e9es \u00e0 votre activit\u00e9 en ligne \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s.","descriptionLegal":"Les partenaires peuvent : \n* Combiner des donn\u00e9es obtenues hors ligne avec des donn\u00e9es collect\u00e9es en ligne \u00e0 l\u2019appui d\u2019une ou de plusieurs Finalit\u00e9s ou Finalit\u00e9s sp\u00e9ciales.\n"},"2":{"id":2,"name":"Relier diff\u00e9rents terminaux","description":"Diff\u00e9rents terminaux peuvent \u00eatre identifi\u00e9s comme vous appartenant ou appartenant \u00e0 votre foyer \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s","descriptionLegal":"Les partnenaires peuvent :\n* D\u00e9terminer, selon une approche d\u00e9terministe, que deux terminaux ou plus appartiennent au m\u00eame utilisateur ou au m\u00eame foyer\n* D\u00e9terminer, selon une approche probabiliste, que deux terminaux ou plus appartiennent au m\u00eame utilisateur ou au m\u00eame foyer\n* Analyser activement les caract\u00e9ristiques du terminal pour l\u2019identification probabiliste si les utilisateurs ont autoris\u00e9 les partenanaires \u00e0 analyser activement les caract\u00e9ristiques du terminal pour l\u2019identification (Fonctionnalit\u00e9 sp\u00e9ciale 2)\n"},"3":{"id":3,"name":"Recevoir et utiliser des caract\u00e9ristiques d\u2019identification d\u2019appareil envoy\u00e9es automatiquement","description":"Votre appareil peut \u00eatre distingu\u00e9 d\u2019autres appareils en fonction des informations qu\u2019il envoie automatiquement, telles que l\u2019adresse IP ou le type de navigateur.","descriptionLegal":"Les partenaires peuvent :\n* Cr\u00e9er un identifiant \u00e0 l\u2019aide des donn\u00e9es collect\u00e9es automatiquement \u00e0 partir d\u2019un appareil pour des caract\u00e9ristiques sp\u00e9cifiques ; par ex., adresse IP, cha\u00eene d\u2019agent utilisateur.\n* Utiliser cet identifiant pour r\u00e9identifier un appareil.\nLes partenaires ne peuvent pas :\n* Cr\u00e9er un identifiant \u00e0 l\u2019aide des donn\u00e9es collect\u00e9es via une analyse active d\u2019un terminal pour l\u2019identification de caract\u00e9ristiques sp\u00e9cifiques (par exemple, des polices install\u00e9es ou la r\u00e9solution d\u2019\u00e9cran) sans une adh\u00e9sion distincte de l\u2019utilisateur \u00e0 l\u2019analyse active des caract\u00e9ristiques de l\u2019appareil \u00e0 des fins d\u2019identification.\n* Utiliser cet identifiant pour r\u00e9-identifier un terminal.\n"}},"specialFeatures":{"1":{"id":1,"name":"Utiliser des donn\u00e9es de g\u00e9olocalisation pr\u00e9cises","description":"Vos donn\u00e9es de g\u00e9olocalisation pr\u00e9cises peuvent \u00eatre utilis\u00e9es \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s. Cela signifie que votre localisation peut \u00eatre pr\u00e9cise \u00e0 plusieurs m\u00e8tres pr\u00e8s.","descriptionLegal":"Les partnenaires peuvent :\n* Collecter et traiter des donn\u00e9es de g\u00e9olocalisation pr\u00e9cises \u00e0 l\u2019appui d\u2019une ou de plusieurs finalit\u00e9s.\nN.B. Une g\u00e9olocalisation pr\u00e9cise signifie qu\u2019il n\u2019y a aucune restriction \u00e0 la pr\u00e9cision de la localisation d\u2019un utilisateur ; elle peut \u00eatre pr\u00e9cise \u00e0 quelques m\u00e8tres pr\u00e8s.\n"},"2":{"id":2,"name":"Analyser activement les caract\u00e9ristiques du terminal pour l\u2019identification","description":"Votre terminal peut \u00eatre identifi\u00e9 sur la base d\u2019une analyse de la combinaison unique de caract\u00e9ristiques de votre terminal.","descriptionLegal":"Les partenaires peuvent :\n* Cr\u00e9er un identifiant \u00e0 l\u2019aide des donn\u00e9es collect\u00e9es via une analyse active d\u2019un terminal pour l\u2019identification de caract\u00e9ristiques sp\u00e9cifiques, par exemple des polices install\u00e9es ou la r\u00e9solution d\u2019\u00e9cran. \n* Utiliser cet identifiant pour r\u00e9-identifier un terminal.\n"}},"stacks":{"1":{"id":1,"purposes":[],"specialFeatures":[1,2],"name":"Donn\u00e9es de g\u00e9olocalisation pr\u00e9cises et identification par analyse du terminal","description":"Des informations de g\u00e9olocalisation pr\u00e9cises et des informations sur les caract\u00e9ristiques de l\u2019appareil peuvent \u00eatre utilis\u00e9es."},"2":{"id":2,"purposes":[2,7],"specialFeatures":[],"name":"Publicit\u00e9s standards et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"3":{"id":3,"purposes":[2,3,4],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s."},"4":{"id":4,"purposes":[2,7,9],"specialFeatures":[],"name":"Publicit\u00e9s standards et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"5":{"id":5,"purposes":[2,3,7],"specialFeatures":[],"name":"Publicit\u00e9s standards, profil de publicit\u00e9s personnalis\u00e9es et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"6":{"id":6,"purposes":[2,4,7],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es et mesure de performance des publicit\u00e9s","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"7":{"id":7,"purposes":[2,4,7,9],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es, mesure de performance des publicit\u00e9s, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"8":{"id":8,"purposes":[2,3,4,7],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es et mesure de performance des annonces","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"9":{"id":9,"purposes":[2,3,4,7,9],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es, mesure de performance des publicit\u00e9s, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"10":{"id":10,"purposes":[3,4],"specialFeatures":[],"name":"Profil de publicit\u00e9s personnalis\u00e9es et affichage","description":"Les publicit\u00e9s peuvent \u00eatre personnalis\u00e9es sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s. "},"11":{"id":11,"purposes":[5,6],"specialFeatures":[],"name":"Contenu personnalis\u00e9","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu."},"12":{"id":12,"purposes":[6,8],"specialFeatures":[],"name":"Affichage de contenu personnalis\u00e9 et mesure de performance du contenu","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. La performance du contenu peut \u00eatre mesur\u00e9e."},"13":{"id":13,"purposes":[6,8,9],"specialFeatures":[],"name":"Affichage de contenu personnalis\u00e9, mesure de performance du contenu et donn\u00e9es d\u2019audience","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"14":{"id":14,"purposes":[5,6,8],"specialFeatures":[],"name":"Contenu personnalis\u00e9 et mesure de performance du contenu","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e."},"15":{"id":15,"purposes":[5,6,8,9],"specialFeatures":[],"name":"Contenu personnalis\u00e9, mesure de performance du contenu et donn\u00e9es d\u2019audience","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"16":{"id":16,"purposes":[5,6,8,9,10],"specialFeatures":[],"name":"Contenu personnalis\u00e9, mesure de performance du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit","description":"Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, des syst\u00e8mes et logiciels"},"17":{"id":17,"purposes":[7,8,9],"specialFeatures":[],"name":"Mesure de performance des annonces et du contenu et donn\u00e9es d\u2019audience","description":"La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"18":{"id":18,"purposes":[7,8],"specialFeatures":[],"name":"Mesure de performance des publicit\u00e9s et du contenu","description":"La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e."},"19":{"id":19,"purposes":[7,9],"specialFeatures":[],"name":"Mesure de performance des publicit\u00e9s et donn\u00e9es d\u2019audience","description":"La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu"},"20":{"id":20,"purposes":[7,8,9,10],"specialFeatures":[],"name":"Mesure de performance des publicit\u00e9s et du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit","description":"La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"21":{"id":21,"purposes":[8,9,10],"specialFeatures":[],"name":"Mesure de performance du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit.","description":"La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"22":{"id":22,"purposes":[8,10],"specialFeatures":[],"name":"Mesure de performance du contenu, et d\u00e9veloppement produit","description":"La performance du contenu peut \u00eatre mesur\u00e9e. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"23":{"id":23,"purposes":[2,4,6,7,8],"specialFeatures":[],"name":"Affichage de publicit\u00e9s et de contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e."},"24":{"id":24,"purposes":[2,4,6,7,8,9],"specialFeatures":[],"name":"Affichage de publicit\u00e9s et de contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"25":{"id":25,"purposes":[2,3,4,5,6,7,8],"specialFeatures":[],"name":"Publicit\u00e9s et contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s et le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e."},"26":{"id":26,"purposes":[2,3,4,5,6,7,8,9],"specialFeatures":[],"name":"Publicit\u00e9s et contenu personnalis\u00e9s, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser les publicit\u00e9s et le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"27":{"id":27,"purposes":[3,5],"specialFeatures":[],"name":"Publicit\u00e9s personnalis\u00e9es et profil de contenu","description":"Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour personnaliser les publicit\u00e9s et le contenu. "},"28":{"id":28,"purposes":[2,4,6],"specialFeatures":[],"name":"Affichage de publicit\u00e9s et de contenu personnalis\u00e9s","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. "},"29":{"id":29,"purposes":[2,7,8,9],"specialFeatures":[],"name":"Publicit\u00e9s standards, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"30":{"id":30,"purposes":[2,4,5,6,7,8,9],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"31":{"id":31,"purposes":[2,4,5,6,7,8,9,10],"specialFeatures":[],"name":"Affichage de publicit\u00e9s personnalis\u00e9es, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, donn\u00e9es d\u2019audience et d\u00e9veloppement de produit","description":"Les publicit\u00e9s et le contenu peuvent \u00eatre personnalis\u00e9s sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"32":{"id":32,"purposes":[2,5,6,7,8,9],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, et donn\u00e9es d\u2019audience","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"33":{"id":33,"purposes":[2,5,6,7,8,9,10],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s et du contenu, donn\u00e9es d\u2019audience, et d\u00e9veloppement produit","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"34":{"id":34,"purposes":[2,5,6,8,9],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance du contenu, et donn\u00e9es d\u2019audience","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s et du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu."},"35":{"id":35,"purposes":[2,5,6,8,9,10],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance du contenu, donn\u00e9es d\u2019audience et d\u00e9veloppement de produit ","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance du contenu peut \u00eatre mesur\u00e9e. Des informations peuvent \u00eatre g\u00e9n\u00e9r\u00e9es sur les audiences qui ont vu les publicit\u00e9s et le contenu. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."},"36":{"id":36,"purposes":[2,5,6,7],"specialFeatures":[],"name":"Publicit\u00e9s standard, contenu personnalis\u00e9 et mesure de performance des publicit\u00e9s","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e."},"37":{"id":37,"purposes":[2,5,6,7,10],"specialFeatures":[],"name":"Publicit\u00e9s standards, contenu personnalis\u00e9, mesure de performance des publicit\u00e9s, et d\u00e9veloppement produit","description":"Des publicit\u00e9s standards peuvent \u00eatre diffus\u00e9es. Le contenu peut \u00eatre personnalis\u00e9 sur la base d\u2019un profil. Des donn\u00e9es suppl\u00e9mentaires peuvent \u00eatre ajout\u00e9es pour mieux personnaliser le contenu. La performance des publicit\u00e9s peut \u00eatre mesur\u00e9e. Les donn\u00e9es peuvent \u00eatre utilis\u00e9es pour cr\u00e9er ou am\u00e9liorer l\u2019exp\u00e9rience utilisateur, les syst\u00e8mes et les logiciels."}}} \ No newline at end of file From 1c4ae8aeeb234be2904f585714ea3f7a7e72c5c6 Mon Sep 17 00:00:00 2001 From: chad Date: Sat, 2 Sep 2023 18:54:50 -0600 Subject: [PATCH 03/36] rename missed multistate usp* methods to us* --- .../src/main/java/com/iab/gpp/encoder/GppModel.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 626fb82a..9877500a 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 @@ -160,27 +160,27 @@ public UspV1 getUspV1Section() { return (UspV1) getSection(UspV1.NAME); } - public UsNatV1 getUspNatV1Section() { + public UsNatV1 getUsNatV1Section() { return (UsNatV1) getSection(UsNatV1.NAME); } - public UsCaV1 getUspCaV1Section() { + public UsCaV1 getUsCaV1Section() { return (UsCaV1) getSection(UsCaV1.NAME); } - public UsVaV1 getUspVaV1Section() { + public UsVaV1 getUsVaV1Section() { return (UsVaV1) getSection(UsVaV1.NAME); } - public UsCoV1 getUspCoV1Section() { + public UsCoV1 getUsCoV1Section() { return (UsCoV1) getSection(UsCoV1.NAME); } - public UsUtV1 getUspUtV1Section() { + public UsUtV1 getUsUtV1Section() { return (UsUtV1) getSection(UsUtV1.NAME); } - public UsCtV1 getUspCtV1Section() { + public UsCtV1 getUsCtV1Section() { return (UsCtV1) getSection(UsCtV1.NAME); } From 2b159f4ec3322dd4ea0dc76c103aafe84d2e2b08 Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 5 Sep 2023 06:55:55 -0600 Subject: [PATCH 04/36] lazier decoding --- .../base64/AbstractBase64UrlEncoder.java | 79 ++++ .../base64/CompressedBase64UrlEncoder.java | 27 ++ .../base64/TraditionalBase64UrlEncoder.java | 23 ++ .../AbstractEncodableBitStringSection.java | 81 ++++ ...actEncodableSegmentedBitStringSection.java | 100 +++++ .../iab/gpp/encoder/sectionbk/TcfCaV1.java | 291 ++++++++++++++ .../iab/gpp/encoder/sectionbk/TcfEuV2.java | 376 ++++++++++++++++++ .../com/iab/gpp/encoder/sectionbk/UsCaV1.java | 208 ++++++++++ .../com/iab/gpp/encoder/sectionbk/UsCoV1.java | 202 ++++++++++ .../com/iab/gpp/encoder/sectionbk/UsCtV1.java | 203 ++++++++++ .../iab/gpp/encoder/sectionbk/UsNatV1.java | 233 +++++++++++ .../com/iab/gpp/encoder/sectionbk/UsUtV1.java | 141 +++++++ .../com/iab/gpp/encoder/sectionbk/UsVaV1.java | 135 +++++++ .../com/iab/gpp/encoder/sectionbk/UspV1.java | 107 +++++ .../TraditionalBase64UrlEncoderTest.java | 40 ++ 15 files changed, 2246 insertions(+) create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/AbstractBase64UrlEncoder.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/CompressedBase64UrlEncoder.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoder.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableBitStringSection.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableSegmentedBitStringSection.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfCaV1.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfEuV2.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCaV1.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCoV1.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCtV1.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsNatV1.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsUtV1.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsVaV1.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UspV1.java create mode 100644 iabgpp-encoder/src/test/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoderTest.java 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 new file mode 100644 index 00000000..a5434073 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/AbstractBase64UrlEncoder.java @@ -0,0 +1,79 @@ +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.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); + + /** + * 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 + "'"); + } + + bitString = pad(bitString); + + String str = ""; + + int index = 0; + while (index <= bitString.length() - 6) { + String s = bitString.substring(index, index + 6); + + try { + int n = FixedIntegerEncoder.decode(s); + Character c = AbstractBase64UrlEncoder.DICT.charAt(n); + str += c; + index += 6; + } catch (DecodingException e) { + throw new EncodingException("Unencodable Base64Url '" + 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++) { + char c = str.charAt(i); + Integer n = AbstractBase64UrlEncoder.REVERSE_DICT.get(c); + String s = FixedIntegerEncoder.encode(n, 6); + bitString += s; + } + + return bitString; + } +} 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 new file mode 100644 index 00000000..5cd0970a --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/CompressedBase64UrlEncoder.java @@ -0,0 +1,27 @@ +package com.iab.gpp.encoder.base64; + +public class CompressedBase64UrlEncoder extends AbstractBase64UrlEncoder { + + private static CompressedBase64UrlEncoder instance = new CompressedBase64UrlEncoder(); + + private CompressedBase64UrlEncoder() { + + } + + public static CompressedBase64UrlEncoder getInstance() { + return instance; + } + + @Override + protected String pad(String bitString) { + while (bitString.length() % 8 > 0) { + bitString += "0"; + } + while (bitString.length() % 6 > 0) { + bitString += "0"; + } + + return bitString; + } + +} 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 new file mode 100644 index 00000000..f0d2f9ea --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoder.java @@ -0,0 +1,23 @@ +package com.iab.gpp.encoder.base64; + +public class TraditionalBase64UrlEncoder extends AbstractBase64UrlEncoder { + + private static TraditionalBase64UrlEncoder instance = new TraditionalBase64UrlEncoder(); + + private TraditionalBase64UrlEncoder() { + + } + + public static TraditionalBase64UrlEncoder getInstance() { + return instance; + } + + @Override + protected String pad(String bitString) { + while (bitString.length() % 24 > 0) { + bitString += "0"; + } + return bitString; + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableBitStringSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableBitStringSection.java new file mode 100644 index 00000000..5b8f0b7c --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableBitStringSection.java @@ -0,0 +1,81 @@ +package com.iab.gpp.encoder.section; + +import java.util.Map; +import com.iab.gpp.encoder.datatype.AbstractEncodableBitStringDataType; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; +import com.iab.gpp.encoder.error.InvalidFieldException; + +public abstract class AbstractEncodableBitStringSection implements EncodableSection { + protected Map> fields; + protected String[] fieldOrder; + + @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[] getFieldOrder() { + return this.fieldOrder; + } + + public String encodeToBitString() throws EncodingException { + String bitString = ""; + for (int i = 0; i < this.fieldOrder.length; i++) { + String fieldName = this.fieldOrder[i]; + if (this.fields.containsKey(fieldName)) { + AbstractEncodableBitStringDataType field = this.fields.get(fieldName); + bitString += field.encode(); + } else { + throw new EncodingException("Field not found: '" + fieldName + "'"); + } + } + + return bitString; + } + + public void decodeFromBitString(String bitString) throws DecodingException { + int index = 0; + for (int i = 0; i < this.fieldOrder.length; i++) { + String fieldName = this.fieldOrder[i]; + if (this.fields.containsKey(fieldName)) { + AbstractEncodableBitStringDataType field = this.fields.get(fieldName); + String substring = field.substring(bitString, index); + field.decode(substring); + index += substring.length(); + } 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/sectionbk/AbstractEncodableSegmentedBitStringSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableSegmentedBitStringSection.java new file mode 100644 index 00000000..d9339189 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableSegmentedBitStringSection.java @@ -0,0 +1,100 @@ +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.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++) { + String segmentBitString = segmentBitStrings.get(i); + if (segmentBitString != null && segmentBitString.length() > 0) { + int index = 0; + 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); + String substring = field.substring(segmentBitString, index); + field.decode(substring); + index += substring.length(); + } 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/sectionbk/TcfCaV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfCaV1.java new file mode 100644 index 00000000..ec3b4891 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfCaV1.java @@ -0,0 +1,291 @@ +package com.iab.gpp.encoder.section; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.function.IntSupplier; +import java.util.stream.Collectors; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableDatetime; +import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedString; +import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; +import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; +import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.field.TcfCaV1Field; + +public class TcfCaV1 extends AbstractEncodableSegmentedBitStringSection { + public static int ID = 5; + public static int VERSION = 1; + public static String NAME = "tcfcav1"; + + private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); + + public TcfCaV1() { + initFields(); + } + + public TcfCaV1(String encodedString) throws DecodingException { + initFields(); + + if (encodedString != null && encodedString.length() > 0) { + this.decode(encodedString); + } + } + + private void initFields() { + fields = new HashMap<>(); + + ZonedDateTime date = ZonedDateTime.now(); + + // core section + fields.put(TcfCaV1Field.VERSION, new EncodableFixedInteger(6, TcfCaV1.VERSION)); + fields.put(TcfCaV1Field.CREATED, new EncodableDatetime(date)); + fields.put(TcfCaV1Field.LAST_UPDATED, new EncodableDatetime(date)); + fields.put(TcfCaV1Field.CMP_ID, new EncodableFixedInteger(12, 0)); + fields.put(TcfCaV1Field.CMP_VERSION, new EncodableFixedInteger(12, 0)); + fields.put(TcfCaV1Field.CONSENT_SCREEN, new EncodableFixedInteger(6, 0)); + fields.put(TcfCaV1Field.CONSENT_LANGUAGE, new EncodableFixedString(2, "EN")); + fields.put(TcfCaV1Field.VENDOR_LIST_VERSION, new EncodableFixedInteger(12, 0)); + fields.put(TcfCaV1Field.TCF_POLICY_VERSION, new EncodableFixedInteger(6, 2)); + fields.put(TcfCaV1Field.USE_NON_STANDARD_STACKS, new EncodableBoolean(false)); + fields.put(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT, new EncodableFixedBitfield( + Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfCaV1Field.VENDOR_EXPRESS_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); + fields.put(TcfCaV1Field.VENDOR_IMPLIED_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); + + // publisher purposes segment + fields.put(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); + fields.put(TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + + EncodableFixedInteger numCustomPurposes = new EncodableFixedInteger(6, 0); + fields.put(TcfCaV1Field.NUM_CUSTOM_PURPOSES, numCustomPurposes); + + IntSupplier getLengthSupplier = new IntSupplier() { + + @Override + public int getAsInt() { + return numCustomPurposes.getValue(); + } + + }; + + fields.put(TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT, + new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + + fields.put(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT, + new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + + //@formatter:off + String[] coreSegment = new String[] { + TcfCaV1Field.VERSION, + TcfCaV1Field.CREATED, + TcfCaV1Field.LAST_UPDATED, + TcfCaV1Field.CMP_ID, + TcfCaV1Field.CMP_VERSION, + TcfCaV1Field.CONSENT_SCREEN, + TcfCaV1Field.CONSENT_LANGUAGE, + TcfCaV1Field.VENDOR_LIST_VERSION, + TcfCaV1Field.TCF_POLICY_VERSION, + TcfCaV1Field.USE_NON_STANDARD_STACKS, + TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT, + TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, + TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, + TcfCaV1Field.VENDOR_EXPRESS_CONSENT, + TcfCaV1Field.VENDOR_IMPLIED_CONSENT + }; + + String[] publisherPurposesSegment = new String[] { + 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, + }; + + segments = new String[][] { + coreSegment, + publisherPurposesSegment + }; + //@formatter:on + } + + @Override + public String encode() throws EncodingException { + List segmentBitStrings = this.encodeSegmentsToBitStrings(); + List encodedSegments = new ArrayList<>(); + if (segmentBitStrings.size() >= 1) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); + if (segmentBitStrings.size() >= 2) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); + } + } + + return encodedSegments.stream().collect(Collectors.joining(".")); + } + + @Override + public void decode(String encodedSection) throws DecodingException { + String[] encodedSegments = encodedSection.split("\\."); + String[] segmentBitStrings = new String[4]; + for (int i = 0; i < encodedSegments.length; i++) { + /** + * first char will contain 6 bits, we only need the first 3. There is no segment type for the CORE + * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on + * a maximum of encoding version 2 the first 3 bits in the core segment will evaluate to 0. + */ + String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); + switch (segmentBitString.substring(0, 3)) { + // unfortunately, the segment ordering doesn't match the segment ids + case "000": { + segmentBitStrings[0] = segmentBitString; + break; + } + case "011": { + segmentBitStrings[1] = segmentBitString; + break; + } + default: { + throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); + } + } + } + this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); + } + + @Override + public void setFieldValue(String fieldName, Object value) throws InvalidFieldException { + super.setFieldValue(fieldName, value); + + if (!fieldName.equals(TcfCaV1Field.CREATED) && !fieldName.equals(TcfCaV1Field.LAST_UPDATED)) { + ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC")); + + super.setFieldValue(TcfCaV1Field.CREATED, utcDateTime); + super.setFieldValue(TcfCaV1Field.LAST_UPDATED, utcDateTime); + } + } + + @Override + public int getId() { + return TcfCaV1.ID; + } + + @Override + public String getName() { + return TcfCaV1.NAME; + } + + public Integer getVersion() { + return (Integer) this.fields.get(TcfCaV1Field.VERSION).getValue(); + } + + public ZonedDateTime getCreated() { + return (ZonedDateTime) this.fields.get(TcfCaV1Field.CREATED).getValue(); + } + + public ZonedDateTime getLastUpdated() { + return (ZonedDateTime) this.fields.get(TcfCaV1Field.LAST_UPDATED).getValue(); + } + + public Integer getCmpId() { + return (Integer) this.fields.get(TcfCaV1Field.CMP_ID).getValue(); + } + + public Integer getCmpVersion() { + return (Integer) this.fields.get(TcfCaV1Field.CMP_VERSION).getValue(); + } + + public Integer getConsentScreen() { + return (Integer) this.fields.get(TcfCaV1Field.CONSENT_SCREEN).getValue(); + } + + public String getConsentLanguage() { + return (String) this.fields.get(TcfCaV1Field.CONSENT_LANGUAGE).getValue(); + } + + public Integer getVendorListVersion() { + return (Integer) this.fields.get(TcfCaV1Field.VENDOR_LIST_VERSION).getValue(); + } + + public Integer getPolicyVersion() { + return (Integer) this.fields.get(TcfCaV1Field.TCF_POLICY_VERSION).getValue(); + } + + public Boolean getUseNonStandardStacks() { + return (Boolean) this.fields.get(TcfCaV1Field.USE_NON_STANDARD_STACKS).getValue(); + } + + @SuppressWarnings("unchecked") + public List getSpecialFeatureExpressConsent() { + return (List) this.fields.get(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT).getValue(); + } + + @SuppressWarnings("unchecked") + public List getPurposesExpressConsent() { + return (List) this.fields.get(TcfCaV1Field.PURPOSES_EXPRESS_CONSENT).getValue(); + } + + @SuppressWarnings("unchecked") + public List getPurposesImpliedConsent() { + return (List) this.fields.get(TcfCaV1Field.PURPOSES_IMPLIED_CONSENT).getValue(); + } + + @SuppressWarnings("unchecked") + public List getVendorExpressConsent() { + return (List) this.fields.get(TcfCaV1Field.VENDOR_EXPRESS_CONSENT).getValue(); + } + + @SuppressWarnings("unchecked") + public List getVendorImpliedConsent() { + return (List) this.fields.get(TcfCaV1Field.VENDOR_IMPLIED_CONSENT).getValue(); + } + + public Integer getPubPurposesSegmentType() { + return (Integer) this.fields.get(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE).getValue(); + } + + @SuppressWarnings("unchecked") + public List getPubPurposesExpressConsent() { + return (List) this.fields.get(TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT).getValue(); + } + + @SuppressWarnings("unchecked") + public List getPubPurposesImpliedConsent() { + return (List) this.fields.get(TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT).getValue(); + } + + public Integer getNumCustomPurposes() { + return (Integer) this.fields.get(TcfCaV1Field.NUM_CUSTOM_PURPOSES).getValue(); + } + + @SuppressWarnings("unchecked") + public List getCustomPurposesExpressConsent() { + return (List) this.fields.get(TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT).getValue(); + } + + @SuppressWarnings("unchecked") + public List getCustomPurposesImpliedConsent() { + return (List) this.fields.get(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT).getValue(); + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfEuV2.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfEuV2.java new file mode 100644 index 00000000..625121bd --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfEuV2.java @@ -0,0 +1,376 @@ +package com.iab.gpp.encoder.section; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.function.IntSupplier; +import java.util.stream.Collectors; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableDatetime; +import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerRange; +import com.iab.gpp.encoder.datatype.EncodableFixedString; +import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; +import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.datatype.encoder.TraditionalBase64UrlEncoder; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; +import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.field.TcfEuV2Field; + +public class TcfEuV2 extends AbstractEncodableSegmentedBitStringSection { + public static int ID = 2; + public static int VERSION = 2; + public static String NAME = "tcfeuv2"; + + private AbstractBase64UrlEncoder base64UrlEncoder = new TraditionalBase64UrlEncoder(); + + public TcfEuV2() { + initFields(); + } + + public TcfEuV2(String encodedString) throws DecodingException { + initFields(); + + if (encodedString != null && encodedString.length() > 0) { + this.decode(encodedString); + } + } + + private void initFields() { + fields = new HashMap<>(); + + ZonedDateTime date = ZonedDateTime.now(); + + // core section + fields.put(TcfEuV2Field.VERSION, new EncodableFixedInteger(6, TcfEuV2.VERSION)); + fields.put(TcfEuV2Field.CREATED, new EncodableDatetime(date)); + fields.put(TcfEuV2Field.LAST_UPDATED, new EncodableDatetime(date)); + fields.put(TcfEuV2Field.CMP_ID, new EncodableFixedInteger(12, 0)); + fields.put(TcfEuV2Field.CMP_VERSION, new EncodableFixedInteger(12, 0)); + fields.put(TcfEuV2Field.CONSENT_SCREEN, new EncodableFixedInteger(6, 0)); + fields.put(TcfEuV2Field.CONSENT_LANGUAGE, new EncodableFixedString(2, "EN")); + fields.put(TcfEuV2Field.VENDOR_LIST_VERSION, new EncodableFixedInteger(12, 0)); + fields.put(TcfEuV2Field.POLICY_VERSION, new EncodableFixedInteger(6, 2)); + fields.put(TcfEuV2Field.IS_SERVICE_SPECIFIC, new EncodableBoolean(false)); + fields.put(TcfEuV2Field.USE_NON_STANDARD_STACKS, new EncodableBoolean(false)); + fields.put(TcfEuV2Field.SPECIAL_FEATURE_OPTINS, new EncodableFixedBitfield( + Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfEuV2Field.PURPOSE_CONSENTS, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfEuV2Field.PURPOSE_ONE_TREATMENT, new EncodableBoolean(false)); + fields.put(TcfEuV2Field.PUBLISHER_COUNTRY_CODE, new EncodableFixedString(2, "AA")); + fields.put(TcfEuV2Field.VENDOR_CONSENTS, new EncodableOptimizedFixedRange(new ArrayList<>())); + fields.put(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, new EncodableOptimizedFixedRange(new ArrayList<>())); + + fields.put(TcfEuV2Field.PUBLISHER_RESTRICTIONS, new EncodableFixedIntegerRange(new ArrayList<>())); + + // publisher purposes segment + fields.put(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); + fields.put(TcfEuV2Field.PUBLISHER_CONSENTS, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + + EncodableFixedInteger numCustomPurposes = new EncodableFixedInteger(6, 0); + fields.put(TcfEuV2Field.NUM_CUSTOM_PURPOSES, numCustomPurposes); + + IntSupplier getLengthSupplier = new IntSupplier() { + + @Override + public int getAsInt() { + return numCustomPurposes.getValue(); + } + + }; + + fields.put(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS, + new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + + fields.put(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS, + new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + + fields.put(TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE, new EncodableFixedInteger(3, 2)); + fields.put(TcfEuV2Field.VENDORS_ALLOWED, new EncodableOptimizedFixedRange(new ArrayList<>())); + + fields.put(TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE, new EncodableFixedInteger(3, 1)); + fields.put(TcfEuV2Field.VENDORS_DISCLOSED, new EncodableOptimizedFixedRange(new ArrayList<>())); + + //@formatter:off + String[] coreSegment = new String[] { + TcfEuV2Field.VERSION, + TcfEuV2Field.CREATED, + TcfEuV2Field.LAST_UPDATED, + TcfEuV2Field.CMP_ID, + TcfEuV2Field.CMP_VERSION, + TcfEuV2Field.CONSENT_SCREEN, + TcfEuV2Field.CONSENT_LANGUAGE, + TcfEuV2Field.VENDOR_LIST_VERSION, + TcfEuV2Field.POLICY_VERSION, + TcfEuV2Field.IS_SERVICE_SPECIFIC, + TcfEuV2Field.USE_NON_STANDARD_STACKS, + TcfEuV2Field.SPECIAL_FEATURE_OPTINS, + TcfEuV2Field.PURPOSE_CONSENTS, + TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS, + TcfEuV2Field.PURPOSE_ONE_TREATMENT, + TcfEuV2Field.PUBLISHER_COUNTRY_CODE, + TcfEuV2Field.VENDOR_CONSENTS, + TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, + TcfEuV2Field.PUBLISHER_RESTRICTIONS + }; + + String[] publisherPurposesSegment = new String[] { + 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, + }; + + String[] vendorsAllowedSegment = new String[] { + TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE, + TcfEuV2Field.VENDORS_ALLOWED, + }; + + String[] vendorsDisclosedSegment = new String[] { + TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE, + TcfEuV2Field.VENDORS_DISCLOSED, + }; + + segments = new String[][] { + coreSegment, + publisherPurposesSegment, + vendorsAllowedSegment, + vendorsDisclosedSegment + }; + //@formatter:on + } + + @Override + public String encode() throws EncodingException { + List segmentBitStrings = this.encodeSegmentsToBitStrings(); + List encodedSegments = new ArrayList<>(); + if (segmentBitStrings.size() >= 1) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); + + Boolean isServiceSpecific = (Boolean) this.getFieldValue(TcfEuV2Field.IS_SERVICE_SPECIFIC); + if (isServiceSpecific) { + if (segmentBitStrings.size() >= 2) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); + } + } else { + if (segmentBitStrings.size() >= 2) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(2))); + + if (segmentBitStrings.size() >= 3) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(3))); + } + } + } + } + + return encodedSegments.stream().collect(Collectors.joining(".")); + } + + @Override + public void decode(String encodedSection) throws DecodingException { + String[] encodedSegments = encodedSection.split("\\."); + String[] segmentBitStrings = new String[4]; + for (int i = 0; i < encodedSegments.length; i++) { + /** + * first char will contain 6 bits, we only need the first 3. There is no segment type for the CORE + * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on + * a maximum of encoding version 2 the first 3 bits in the core segment will evaluate to 0. + */ + String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); + switch (segmentBitString.substring(0, 3)) { + // unfortunately, the segment ordering doesn't match the segment ids + case "000": { + segmentBitStrings[0] = segmentBitString; + break; + } + case "001": { + segmentBitStrings[3] = segmentBitString; + break; + } + case "010": { + segmentBitStrings[2] = segmentBitString; + break; + } + case "011": { + segmentBitStrings[1] = segmentBitString; + break; + } + default: { + throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); + } + } + } + this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); + } + + @Override + public void setFieldValue(String fieldName, Object value) throws InvalidFieldException { + super.setFieldValue(fieldName, value); + + if (!fieldName.equals(TcfEuV2Field.CREATED) && !fieldName.equals(TcfEuV2Field.LAST_UPDATED)) { + ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC")); + + super.setFieldValue(TcfEuV2Field.CREATED, utcDateTime); + super.setFieldValue(TcfEuV2Field.LAST_UPDATED, utcDateTime); + } + } + + @Override + public int getId() { + return TcfEuV2.ID; + } + + @Override + public String getName() { + return TcfEuV2.NAME; + } + + public Integer getVersion() { + return (Integer) this.fields.get(TcfEuV2Field.VERSION).getValue(); + } + + public ZonedDateTime getCreated() { + return (ZonedDateTime) this.fields.get(TcfEuV2Field.CREATED).getValue(); + } + + public ZonedDateTime getLastUpdated() { + return (ZonedDateTime) this.fields.get(TcfEuV2Field.LAST_UPDATED).getValue(); + } + + public Integer getCmpId() { + return (Integer) this.fields.get(TcfEuV2Field.CMP_ID).getValue(); + } + + public Integer getCmpVersion() { + return (Integer) this.fields.get(TcfEuV2Field.CMP_VERSION).getValue(); + } + + public Integer getConsentScreen() { + return (Integer) this.fields.get(TcfEuV2Field.CONSENT_SCREEN).getValue(); + } + + public String getConsentLanguage() { + return (String) this.fields.get(TcfEuV2Field.CONSENT_LANGUAGE).getValue(); + } + + public Integer getVendorListVersion() { + return (Integer) this.fields.get(TcfEuV2Field.VENDOR_LIST_VERSION).getValue(); + } + + public Integer getPolicyVersion() { + return (Integer) this.fields.get(TcfEuV2Field.POLICY_VERSION).getValue(); + } + + public Boolean getIsServiceSpecific() { + return (Boolean) this.fields.get(TcfEuV2Field.IS_SERVICE_SPECIFIC).getValue(); + } + + public Boolean getUseNonStandardStacks() { + return (Boolean) this.fields.get(TcfEuV2Field.USE_NON_STANDARD_STACKS).getValue(); + } + + @SuppressWarnings("unchecked") + public List getSpecialFeatureOptins() { + return (List) this.fields.get(TcfEuV2Field.SPECIAL_FEATURE_OPTINS).getValue(); + } + + @SuppressWarnings("unchecked") + public List getPurposeConsents() { + return (List) this.fields.get(TcfEuV2Field.PURPOSE_CONSENTS).getValue(); + } + + @SuppressWarnings("unchecked") + public List getPurposeLegitimateInterests() { + return (List) this.fields.get(TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS).getValue(); + } + + public Boolean getPurposeOneTreatment() { + return (Boolean) this.fields.get(TcfEuV2Field.PURPOSE_ONE_TREATMENT).getValue(); + } + + public String getPublisherCountryCode() { + return (String) this.fields.get(TcfEuV2Field.PUBLISHER_COUNTRY_CODE).getValue(); + } + + @SuppressWarnings("unchecked") + public List getVendorConsents() { + return (List) this.fields.get(TcfEuV2Field.VENDOR_CONSENTS).getValue(); + } + + @SuppressWarnings("unchecked") + public List getVendorLegitimateInterests() { + return (List) this.fields.get(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS).getValue(); + } + + @SuppressWarnings("unchecked") + public List getPublisherRestrictions() { + return (List) this.fields.get(TcfEuV2Field.PUBLISHER_RESTRICTIONS).getValue(); + } + + public Integer getPublisherPurposesSegmentType() { + return (Integer) this.fields.get(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE).getValue(); + } + + @SuppressWarnings("unchecked") + public List getPublisherConsents() { + return (List) this.fields.get(TcfEuV2Field.PUBLISHER_CONSENTS).getValue(); + } + + @SuppressWarnings("unchecked") + public List getPublisherLegitimateInterests() { + return (List) this.fields.get(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS).getValue(); + } + + public Integer getNumCustomPurposes() { + return (Integer) this.fields.get(TcfEuV2Field.NUM_CUSTOM_PURPOSES).getValue(); + } + + @SuppressWarnings("unchecked") + public List getPublisherCustomConsents() { + return (List) this.fields.get(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS).getValue(); + } + + @SuppressWarnings("unchecked") + public List getPublisherCustomLegitimateInterests() { + return (List) this.fields.get(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS).getValue(); + } + + public Integer getVendorsAllowedSegmentType() { + return (Integer) this.fields.get(TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE).getValue(); + } + + @SuppressWarnings("unchecked") + public List getVendorsAllowed() { + return (List) this.fields.get(TcfEuV2Field.VENDORS_ALLOWED).getValue(); + } + + public Integer getVendorsDisclosedSegmentType() { + return (Integer) this.fields.get(TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE).getValue(); + } + + @SuppressWarnings("unchecked") + public List getVendorsDisclosed() { + return (List) this.fields.get(TcfEuV2Field.VENDORS_DISCLOSED).getValue(); + } + + + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCaV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCaV1.java new file mode 100644 index 00000000..de88746f --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCaV1.java @@ -0,0 +1,208 @@ +package com.iab.gpp.encoder.section; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; +import com.iab.gpp.encoder.field.UsCaV1Field; +import com.iab.gpp.encoder.field.UspV1Field; + +public class UsCaV1 extends AbstractEncodableSegmentedBitStringSection { + public static int ID = 8; + public static int VERSION = 1; + public static String NAME = "uscav1"; + + private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); + + public UsCaV1() { + initFields(); + } + + public UsCaV1(String encodedString) throws DecodingException { + initFields(); + + if (encodedString != null && encodedString.length() > 0) { + this.decode(encodedString); + } + } + + private void initFields() { + fields = new HashMap<>(); + + fields.put(UsCaV1Field.VERSION, new EncodableFixedInteger(6, UsCaV1.VERSION)); + fields.put(UsCaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0))); + fields.put(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0))); + fields.put(UsCaV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + + // gpc segment + fields.put(UsCaV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsCaV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsCaV1Field.GPC, new EncodableBoolean(false)); + + //@formatter:off + String[] coreSegment = new String[] { + UsCaV1Field.VERSION, + UsCaV1Field.SALE_OPT_OUT_NOTICE, + UsCaV1Field.SHARING_OPT_OUT_NOTICE, + UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, + UsCaV1Field.SALE_OPT_OUT, + UsCaV1Field.SHARING_OPT_OUT, + UsCaV1Field.SENSITIVE_DATA_PROCESSING, + UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsCaV1Field.PERSONAL_DATA_CONSENTS, + UsCaV1Field.MSPA_COVERED_TRANSACTION, + UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE + }; + + String[] gpcSegment = new String[] { + UsCaV1Field.GPC_SEGMENT_TYPE, + UsCaV1Field.GPC + }; + + segments = new String[][] { + coreSegment, + gpcSegment + }; + //@formatter:on + } + + @Override + public String encode() throws EncodingException { + List segmentBitStrings = this.encodeSegmentsToBitStrings(); + List encodedSegments = new ArrayList<>(); + if (segmentBitStrings.size() >= 1) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); + + if (segmentBitStrings.size() >= 2) { + Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).getValue(); + if (gpcSegmentIncluded) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); + } + + } + } + + return encodedSegments.stream().collect(Collectors.joining(".")); + } + + @Override + public void decode(String encodedSection) throws DecodingException { + String[] encodedSegments = encodedSection.split("\\."); + String[] segmentBitStrings = new String[2]; + boolean gpcSegmentIncluded = false; + for (int i = 0; i < encodedSegments.length; i++) { + /** + * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE + * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on + * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. + */ + String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); + switch (segmentBitString.substring(0, 2)) { + case "00": { + segmentBitStrings[0] = segmentBitString; + break; + } + case "01": { + gpcSegmentIncluded = true; + segmentBitStrings[1] = segmentBitString; + break; + } + default: { + throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); + } + } + } + this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); + this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); + } + + @Override + public int getId() { + return UsCaV1.ID; + } + + @Override + public String getName() { + return UsCaV1.NAME; + } + + public Integer getVersion() { + return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + } + + public Integer getSaleOptOutNotice() { + return (Integer) this.fields.get(UsCaV1Field.SALE_OPT_OUT_NOTICE).getValue(); + } + + public Integer getSensitiveDataLimitUseNotice() { + return (Integer) this.fields.get(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE).getValue(); + } + + public Integer getSharingOptOutNotice() { + return (Integer) this.fields.get(UsCaV1Field.SHARING_OPT_OUT_NOTICE).getValue(); + } + + public Integer getSaleOptOut() { + return (Integer) this.fields.get(UsCaV1Field.SALE_OPT_OUT).getValue(); + } + + public Integer getSharingOptOut() { + return (Integer) this.fields.get(UsCaV1Field.SHARING_OPT_OUT).getValue(); + } + + @SuppressWarnings("unchecked") + public List getSensitiveDataProcessing() { + return (List) this.fields.get(UsCaV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + } + + @SuppressWarnings("unchecked") + public List getKnownChildSensitiveDataConsents() { + return (List) this.fields.get(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + } + + public Integer getPersonalDataConsents() { + return (Integer) this.fields.get(UsCaV1Field.PERSONAL_DATA_CONSENTS).getValue(); + } + + public Integer getMspaCoveredTransaction() { + return (Integer) this.fields.get(UsCaV1Field.MSPA_COVERED_TRANSACTION).getValue(); + } + + public Integer getMspaOptOutOptionMode() { + return (Integer) this.fields.get(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + } + + public Integer getMspaServiceProviderMode() { + return (Integer) this.fields.get(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + } + + public Integer getGpcSegmentType() { + return (Integer) this.fields.get(UsCaV1Field.GPC_SEGMENT_TYPE).getValue(); + } + + public Boolean getGpcSegmentIncluded() { + return (Boolean) this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).getValue(); + } + + public Boolean getGpc() { + return (Boolean) this.fields.get(UsCaV1Field.GPC).getValue(); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCoV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCoV1.java new file mode 100644 index 00000000..05b2f9d6 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCoV1.java @@ -0,0 +1,202 @@ +package com.iab.gpp.encoder.section; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; +import com.iab.gpp.encoder.field.UsCaV1Field; +import com.iab.gpp.encoder.field.UsCoV1Field; +import com.iab.gpp.encoder.field.UspV1Field; + +public class UsCoV1 extends AbstractEncodableSegmentedBitStringSection { + public static int ID = 10; + public static int VERSION = 1; + public static String NAME = "uscov1"; + + private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); + + public UsCoV1() { + initFields(); + } + + public UsCoV1(String encodedString) throws DecodingException { + initFields(); + + if (encodedString != null && encodedString.length() > 0) { + this.decode(encodedString); + } + } + + private void initFields() { + fields = new HashMap<>(); + + fields.put(UsCoV1Field.VERSION, new EncodableFixedInteger(6, UsCoV1.VERSION)); + fields.put(UsCoV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0))); + fields.put(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + + // gpc segment + fields.put(UsCoV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsCoV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsCoV1Field.GPC, new EncodableBoolean(false)); + + + //@formatter:off + String[] coreSegment = new String[] { + UsCoV1Field.VERSION, + UsCoV1Field.SHARING_NOTICE, + UsCoV1Field.SALE_OPT_OUT_NOTICE, + UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsCoV1Field.SALE_OPT_OUT, + UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsCoV1Field.SENSITIVE_DATA_PROCESSING, + UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsCoV1Field.MSPA_COVERED_TRANSACTION, + UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE + }; + + String[] gpcSegment = new String[] { + UsCoV1Field.GPC_SEGMENT_TYPE, + UsCoV1Field.GPC + }; + + segments = new String[][] { + coreSegment, + gpcSegment + }; + //@formatter:on + } + + @Override + public String encode() throws EncodingException { + List segmentBitStrings = this.encodeSegmentsToBitStrings(); + List encodedSegments = new ArrayList<>(); + if (segmentBitStrings.size() >= 1) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); + + if (segmentBitStrings.size() >= 2) { + Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsCoV1Field.GPC_SEGMENT_INCLUDED).getValue(); + if (gpcSegmentIncluded) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); + } + } + } + + return encodedSegments.stream().collect(Collectors.joining(".")); + } + + @Override + public void decode(String encodedSection) throws DecodingException { + String[] encodedSegments = encodedSection.split("\\."); + String[] segmentBitStrings = new String[2]; + boolean gpcSegmentIncluded = false; + for (int i = 0; i < encodedSegments.length; i++) { + /** + * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE + * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on + * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. + */ + String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); + switch (segmentBitString.substring(0, 2)) { + case "00": { + segmentBitStrings[0] = segmentBitString; + break; + } + case "01": { + gpcSegmentIncluded = true; + segmentBitStrings[1] = segmentBitString; + break; + } + default: { + throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); + } + } + } + this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); + this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); + } + + @Override + public int getId() { + return UsCoV1.ID; + } + + @Override + public String getName() { + return UsCoV1.NAME; + } + + public Integer getVersion() { + return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + } + + public Integer getSharingNotice() { + return (Integer) this.fields.get(UsCoV1Field.SHARING_NOTICE).getValue(); + } + + public Integer getSaleOptOutNotice() { + return (Integer) this.fields.get(UsCoV1Field.SALE_OPT_OUT_NOTICE).getValue(); + } + + public Integer getTargetedAdvertisingOptOutNotice() { + return (Integer) this.fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + } + + public Integer getSaleOptOut() { + return (Integer) this.fields.get(UsCoV1Field.SALE_OPT_OUT).getValue(); + } + + public Integer getTargetedAdvertisingOptOut() { + return (Integer) this.fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + } + + @SuppressWarnings("unchecked") + public List getSensitiveDataProcessing() { + return (List) this.fields.get(UsCoV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + } + + public Integer getKnownChildSensitiveDataConsents() { + return (Integer) this.fields.get(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + } + + public Integer getMspaCoveredTransaction() { + return (Integer) this.fields.get(UsCoV1Field.MSPA_COVERED_TRANSACTION).getValue(); + } + + public Integer getMspaOptOutOptionMode() { + return (Integer) this.fields.get(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + } + + public Integer getMspaServiceProviderMode() { + return (Integer) this.fields.get(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + } + + public Integer getGpcSegmentType() { + return (Integer) this.fields.get(UsCoV1Field.GPC_SEGMENT_TYPE).getValue(); + } + + public Boolean getGpcSegmentIncluded() { + return (Boolean) this.fields.get(UsCoV1Field.GPC_SEGMENT_INCLUDED).getValue(); + } + + public Boolean getGpc() { + return (Boolean) this.fields.get(UsCoV1Field.GPC).getValue(); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCtV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCtV1.java new file mode 100644 index 00000000..9df3e780 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCtV1.java @@ -0,0 +1,203 @@ +package com.iab.gpp.encoder.section; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; +import com.iab.gpp.encoder.field.UsCaV1Field; +import com.iab.gpp.encoder.field.UsCtV1Field; +import com.iab.gpp.encoder.field.UspV1Field; + +public class UsCtV1 extends AbstractEncodableSegmentedBitStringSection { + public static int ID = 12; + public static int VERSION = 1; + public static String NAME = "usctv1"; + + private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); + + public UsCtV1() { + initFields(); + } + + public UsCtV1(String encodedString) throws DecodingException { + initFields(); + + if (encodedString != null && encodedString.length() > 0) { + this.decode(encodedString); + } + } + + private void initFields() { + fields = new HashMap<>(); + + fields.put(UsCtV1Field.VERSION, new EncodableFixedInteger(6, UsCtV1.VERSION)); + fields.put(UsCtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); + fields.put(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0))); + fields.put(UsCtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + + // gpc segment + fields.put(UsCtV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsCtV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsCtV1Field.GPC, new EncodableBoolean(false)); + + //@formatter:off + String[] coreSegment = new String[] { + UsCtV1Field.VERSION, + UsCtV1Field.SHARING_NOTICE, + UsCtV1Field.SALE_OPT_OUT_NOTICE, + UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsCtV1Field.SALE_OPT_OUT, + UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsCtV1Field.SENSITIVE_DATA_PROCESSING, + UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsCtV1Field.MSPA_COVERED_TRANSACTION, + UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE + }; + + String[] gpcSegment = new String[] { + UsCtV1Field.GPC_SEGMENT_TYPE, + UsCtV1Field.GPC + }; + + segments = new String[][] { + coreSegment, + gpcSegment + }; + //@formatter:on + } + + @Override + public String encode() throws EncodingException { + List segmentBitStrings = this.encodeSegmentsToBitStrings(); + List encodedSegments = new ArrayList<>(); + if (segmentBitStrings.size() >= 1) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); + + if (segmentBitStrings.size() >= 2) { + Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsCtV1Field.GPC_SEGMENT_INCLUDED).getValue(); + if (gpcSegmentIncluded) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); + } + } + } + + return encodedSegments.stream().collect(Collectors.joining(".")); + } + + @Override + public void decode(String encodedSection) throws DecodingException { + String[] encodedSegments = encodedSection.split("\\."); + String[] segmentBitStrings = new String[2]; + boolean gpcSegmentIncluded = false; + for (int i = 0; i < encodedSegments.length; i++) { + /** + * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE + * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on + * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. + */ + String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); + switch (segmentBitString.substring(0, 2)) { + case "00": { + segmentBitStrings[0] = segmentBitString; + break; + } + case "01": { + gpcSegmentIncluded = true; + segmentBitStrings[1] = segmentBitString; + break; + } + default: { + throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); + } + } + } + this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); + this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); + } + + @Override + public int getId() { + return UsCtV1.ID; + } + + @Override + public String getName() { + return UsCtV1.NAME; + } + + public Integer getVersion() { + return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + } + + public Integer getSharingNotice() { + return (Integer) this.fields.get(UsCtV1Field.SHARING_NOTICE).getValue(); + } + + public Integer getSaleOptOutNotice() { + return (Integer) this.fields.get(UsCtV1Field.SALE_OPT_OUT_NOTICE).getValue(); + } + + public Integer getTargetedAdvertisingOptOutNotice() { + return (Integer) this.fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + } + + public Integer getSaleOptOut() { + return (Integer) this.fields.get(UsCtV1Field.SALE_OPT_OUT).getValue(); + } + + public Integer getTargetedAdvertisingOptOut() { + return (Integer) this.fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + } + + @SuppressWarnings("unchecked") + public List getSensitiveDataProcessing() { + return (List) this.fields.get(UsCtV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + } + + @SuppressWarnings("unchecked") + public List getKnownChildSensitiveDataConsents() { + return (List) this.fields.get(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + } + + public Integer getMspaCoveredTransaction() { + return (Integer) this.fields.get(UsCtV1Field.MSPA_COVERED_TRANSACTION).getValue(); + } + + public Integer getMspaOptOutOptionMode() { + return (Integer) this.fields.get(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + } + + public Integer getMspaServiceProviderMode() { + return (Integer) this.fields.get(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + } + + public Integer getGpcSegmentType() { + return (Integer) this.fields.get(UsCtV1Field.GPC_SEGMENT_TYPE).getValue(); + } + + public Boolean getGpcSegmentIncluded() { + return (Boolean) this.fields.get(UsCtV1Field.GPC_SEGMENT_INCLUDED).getValue(); + } + + public Boolean getGpc() { + return (Boolean) this.fields.get(UsCtV1Field.GPC).getValue(); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsNatV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsNatV1.java new file mode 100644 index 00000000..6cd943d9 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsNatV1.java @@ -0,0 +1,233 @@ +package com.iab.gpp.encoder.section; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; +import com.iab.gpp.encoder.field.UsCaV1Field; +import com.iab.gpp.encoder.field.UsNatV1Field; +import com.iab.gpp.encoder.field.UspV1Field; + +public class UsNatV1 extends AbstractEncodableSegmentedBitStringSection { + public static int ID = 7; + public static int VERSION = 1; + public static String NAME = "usnatv1"; + + private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); + + public UsNatV1() { + initFields(); + } + + public UsNatV1(String encodedString) throws DecodingException { + initFields(); + + if (encodedString != null && encodedString.length() > 0) { + this.decode(encodedString); + } + } + + private void initFields() { + fields = new HashMap<>(); + + fields.put(UsNatV1Field.VERSION, new EncodableFixedInteger(6, UsNatV1.VERSION)); + fields.put(UsNatV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); + fields.put(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0))); + fields.put(UsNatV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + + // gpc segment + fields.put(UsNatV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsNatV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsNatV1Field.GPC, new EncodableBoolean(false)); + + + //@formatter:off + String[] coreSegment = new String[] { + UsNatV1Field.VERSION, + UsNatV1Field.SHARING_NOTICE, + UsNatV1Field.SALE_OPT_OUT_NOTICE, + UsNatV1Field.SHARING_OPT_OUT_NOTICE, + UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, + UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, + UsNatV1Field.SALE_OPT_OUT, + UsNatV1Field.SHARING_OPT_OUT, + UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsNatV1Field.SENSITIVE_DATA_PROCESSING, + UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsNatV1Field.PERSONAL_DATA_CONSENTS, + UsNatV1Field.MSPA_COVERED_TRANSACTION, + UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE + }; + + String[] gpcSegment = new String[] { + UsNatV1Field.GPC_SEGMENT_TYPE, + UsNatV1Field.GPC + }; + + segments = new String[][] { + coreSegment, + gpcSegment + }; + //@formatter:on + } + + @Override + public String encode() throws EncodingException { + List segmentBitStrings = this.encodeSegmentsToBitStrings(); + List encodedSegments = new ArrayList<>(); + if (segmentBitStrings.size() >= 1) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); + + if (segmentBitStrings.size() >= 2) { + Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsNatV1Field.GPC_SEGMENT_INCLUDED).getValue(); + if (gpcSegmentIncluded) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); + } + } + } + + return encodedSegments.stream().collect(Collectors.joining(".")); + } + + @Override + public void decode(String encodedSection) throws DecodingException { + String[] encodedSegments = encodedSection.split("\\."); + String[] segmentBitStrings = new String[2]; + boolean gpcSegmentIncluded = false; + for (int i = 0; i < encodedSegments.length; i++) { + /** + * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE + * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on + * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. + */ + String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); + switch (segmentBitString.substring(0, 2)) { + case "00": { + segmentBitStrings[0] = segmentBitString; + break; + } + case "01": { + gpcSegmentIncluded = true; + segmentBitStrings[1] = segmentBitString; + break; + } + default: { + throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); + } + } + } + this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); + this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); + } + + @Override + public int getId() { + return UsNatV1.ID; + } + + @Override + public String getName() { + return UsNatV1.NAME; + } + + public Integer getVersion() { + return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + } + + public Integer getSharingNotice() { + return (Integer) this.fields.get(UsNatV1Field.SHARING_NOTICE).getValue(); + } + + public Integer getSaleOptOutNotice() { + return (Integer) this.fields.get(UsNatV1Field.SALE_OPT_OUT_NOTICE).getValue(); + } + + public Integer getSharingOptOutNotice() { + return (Integer) this.fields.get(UsNatV1Field.SHARING_OPT_OUT_NOTICE).getValue(); + } + + public Integer getTargetedAdvertisingOptOutNotice() { + return (Integer) this.fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + } + + public Integer getSensitiveDataProcessingOptOutNotice() { + return (Integer) this.fields.get(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE).getValue(); + } + + public Integer getSensitiveDataLimitUseNotice() { + return (Integer) this.fields.get(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE).getValue(); + } + + public Integer getSaleOptOut() { + return (Integer) this.fields.get(UsNatV1Field.SALE_OPT_OUT).getValue(); + } + + public Integer getSharingOptOut() { + return (Integer) this.fields.get(UsNatV1Field.SHARING_OPT_OUT).getValue(); + } + + public Integer getTargetedAdvertisingOptOut() { + return (Integer) this.fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + } + + @SuppressWarnings("unchecked") + public List getSensitiveDataProcessing() { + return (List) this.fields.get(UsNatV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + } + + @SuppressWarnings("unchecked") + public List getKnownChildSensitiveDataConsents() { + return (List) this.fields.get(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + } + + public Integer getPersonalDataConsents() { + return (Integer) this.fields.get(UsNatV1Field.PERSONAL_DATA_CONSENTS).getValue(); + } + + public Integer getMspaCoveredTransaction() { + return (Integer) this.fields.get(UsNatV1Field.MSPA_COVERED_TRANSACTION).getValue(); + } + + public Integer getMspaOptOutOptionMode() { + return (Integer) this.fields.get(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + } + + public Integer getMspaServiceProviderMode() { + return (Integer) this.fields.get(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + } + + public Integer getGpcSegmentType() { + return (Integer) this.fields.get(UsNatV1Field.GPC_SEGMENT_TYPE).getValue(); + } + + public Boolean getGpcSegmentIncluded() { + return (Boolean) this.fields.get(UsNatV1Field.GPC_SEGMENT_INCLUDED).getValue(); + } + + public Boolean getGpc() { + return (Boolean) this.fields.get(UsNatV1Field.GPC).getValue(); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsUtV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsUtV1.java new file mode 100644 index 00000000..9bd56c35 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsUtV1.java @@ -0,0 +1,141 @@ +package com.iab.gpp.encoder.section; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; +import com.iab.gpp.encoder.field.UsUtV1Field; +import com.iab.gpp.encoder.field.UspV1Field; + +public class UsUtV1 extends AbstractEncodableBitStringSection { + public static int ID = 11; + public static int VERSION = 1; + public static String NAME = "usutv1"; + + private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); + + public UsUtV1() { + initFields(); + } + + public UsUtV1(String encodedString) throws DecodingException { + initFields(); + + if (encodedString != null && encodedString.length() > 0) { + this.decode(encodedString); + } + } + + private void initFields() { + fields = new HashMap<>(); + + fields.put(UsUtV1Field.VERSION, new EncodableFixedInteger(6, UsUtV1.VERSION)); + fields.put(UsUtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); + fields.put(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + + //@formatter:off + fieldOrder = new String[] { + UsUtV1Field.VERSION, + UsUtV1Field.SHARING_NOTICE, + UsUtV1Field.SALE_OPT_OUT_NOTICE, + UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, + UsUtV1Field.SALE_OPT_OUT, + UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsUtV1Field.SENSITIVE_DATA_PROCESSING, + UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsUtV1Field.MSPA_COVERED_TRANSACTION, + UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE + }; + //@formatter:on + } + + @Override + public String encode() throws EncodingException { + String bitString = this.encodeToBitString(); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + public void decode(String encodedString) throws DecodingException { + String bitString = base64UrlEncoder.decode(encodedString); + this.decodeFromBitString(bitString); + } + + @Override + public int getId() { + return UsUtV1.ID; + } + + @Override + public String getName() { + return UsUtV1.NAME; + } + + public Integer getVersion() { + return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + } + + public Integer getSharingNotice() { + return (Integer) this.fields.get(UsUtV1Field.SHARING_NOTICE).getValue(); + } + + public Integer getSaleOptOutNotice() { + return (Integer) this.fields.get(UsUtV1Field.SALE_OPT_OUT_NOTICE).getValue(); + } + + public Integer getTargetedAdvertisingOptOutNotice() { + return (Integer) this.fields.get(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + } + + public Integer getSensitiveDataProcessingOptOutNotice() { + return (Integer) this.fields.get(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE).getValue(); + } + + public Integer getSaleOptOut() { + return (Integer) this.fields.get(UsUtV1Field.SALE_OPT_OUT).getValue(); + } + + public Integer getTargetedAdvertisingOptOut() { + return (Integer) this.fields.get(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + } + + @SuppressWarnings("unchecked") + public List getSensitiveDataProcessing() { + return (List) this.fields.get(UsUtV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + } + + public Integer getKnownChildSensitiveDataConsents() { + return (Integer) this.fields.get(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + } + + public Integer getMspaCoveredTransaction() { + return (Integer) this.fields.get(UsUtV1Field.MSPA_COVERED_TRANSACTION).getValue(); + } + + public Integer getMspaOptOutOptionMode() { + return (Integer) this.fields.get(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + } + + public Integer getMspaServiceProviderMode() { + return (Integer) this.fields.get(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsVaV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsVaV1.java new file mode 100644 index 00000000..fdd48f49 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsVaV1.java @@ -0,0 +1,135 @@ +package com.iab.gpp.encoder.section; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; +import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.field.UsVaV1Field; + +public class UsVaV1 extends AbstractEncodableBitStringSection { + public static int ID = 9; + public static int VERSION = 1; + public static String NAME = "usvav1"; + + private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); + + public UsVaV1() { + initFields(); + } + + public UsVaV1(String encodedString) throws DecodingException { + initFields(); + + if (encodedString != null && encodedString.length() > 0) { + this.decode(encodedString); + } + } + + private void initFields() { + fields = new HashMap<>(); + + fields.put(UsVaV1Field.VERSION, new EncodableFixedInteger(6, UsVaV1.VERSION)); + fields.put(UsVaV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); + fields.put(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + + //@formatter:off + fieldOrder = new String[] { + UsVaV1Field.VERSION, + UsVaV1Field.SHARING_NOTICE, + UsVaV1Field.SALE_OPT_OUT_NOTICE, + UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsVaV1Field.SALE_OPT_OUT, + UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsVaV1Field.SENSITIVE_DATA_PROCESSING, + UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsVaV1Field.MSPA_COVERED_TRANSACTION, + UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE + }; + //@formatter:on + } + + @Override + public String encode() throws EncodingException { + String bitString = this.encodeToBitString(); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + public void decode(String encodedString) throws DecodingException { + String bitString = base64UrlEncoder.decode(encodedString); + this.decodeFromBitString(bitString); + } + + @Override + public int getId() { + return UsVaV1.ID; + } + + @Override + public String getName() { + return UsVaV1.NAME; + } + + public Integer getVersion() { + return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + } + + public Integer getSharingNotice() { + return (Integer) this.fields.get(UsVaV1Field.SHARING_NOTICE).getValue(); + } + + public Integer getSaleOptOutNotice() { + return (Integer) this.fields.get(UsVaV1Field.SALE_OPT_OUT_NOTICE).getValue(); + } + + public Integer getTargetedAdvertisingOptOutNotice() { + return (Integer) this.fields.get(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + } + + public Integer getSaleOptOut() { + return (Integer) this.fields.get(UsVaV1Field.SALE_OPT_OUT).getValue(); + } + + public Integer getTargetedAdvertisingOptOut() { + return (Integer) this.fields.get(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + } + + @SuppressWarnings("unchecked") + public List getSensitiveDataProcessing() { + return (List) this.fields.get(UsVaV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + } + + public Integer getKnownChildSensitiveDataConsents() { + return (Integer) this.fields.get(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + } + + public Integer getMspaCoveredTransaction() { + return (Integer) this.fields.get(UsVaV1Field.MSPA_COVERED_TRANSACTION).getValue(); + } + + public Integer getMspaOptOutOptionMode() { + return (Integer) this.fields.get(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + } + + public Integer getMspaServiceProviderMode() { + return (Integer) this.fields.get(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UspV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UspV1.java new file mode 100644 index 00000000..cdb20122 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UspV1.java @@ -0,0 +1,107 @@ +package com.iab.gpp.encoder.section; + +import java.util.HashMap; +import java.util.Map; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; +import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.field.UspV1LegacyField; + +public class UspV1 implements EncodableSection { + public static int ID = 6; + public static int VERSION = 1; + public static String NAME = "uspv1"; + + protected Map fields; + + public UspV1() { + initFields(); + } + + public UspV1(String encodedString) throws DecodingException { + initFields(); + + if (encodedString != null && encodedString.length() > 0) { + this.decode(encodedString); + } + } + + private void initFields() { + fields = new HashMap<>(); + fields.put(UspV1LegacyField.VERSION, UspV1.VERSION); + fields.put(UspV1LegacyField.NOTICE, "-"); + fields.put(UspV1LegacyField.OPT_OUT_SALE, "-"); + fields.put(UspV1LegacyField.LSPA_COVERED, "-"); + } + + @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); + } else { + return null; + } + } + + @Override + public void setFieldValue(String fieldName, Object value) throws InvalidFieldException { + if (this.fields.containsKey(fieldName)) { + this.fields.put(fieldName, value); + } else { + throw new InvalidFieldException(fieldName + " not found"); + } + } + + @Override + public String encode() throws EncodingException { + String str = ""; + str += this.getFieldValue(UspV1LegacyField.VERSION); + str += this.getFieldValue(UspV1LegacyField.NOTICE); + str += this.getFieldValue(UspV1LegacyField.OPT_OUT_SALE); + str += this.getFieldValue(UspV1LegacyField.LSPA_COVERED); + return str; + } + + @Override + public void decode(String encodedString) throws DecodingException { + try { + this.setFieldValue(UspV1LegacyField.VERSION, Integer.parseInt(String.valueOf(encodedString.charAt(0)))); + this.setFieldValue(UspV1LegacyField.NOTICE, String.valueOf(encodedString.charAt(1))); + this.setFieldValue(UspV1LegacyField.OPT_OUT_SALE, String.valueOf(encodedString.charAt(2))); + this.setFieldValue(UspV1LegacyField.LSPA_COVERED, String.valueOf(encodedString.charAt(3))); + } catch (InvalidFieldException e) { + throw new DecodingException(e); + } + } + + @Override + public int getId() { + return UspV1.ID; + } + + @Override + public String getName() { + return UspV1.NAME; + } + + public Integer getVersion() { + return (Integer) this.fields.get(UspV1LegacyField.VERSION); + } + + public String getNotice() { + return (String) fields.get(UspV1LegacyField.NOTICE); + } + + public String getOptOutSale() { + return (String) fields.get(UspV1LegacyField.OPT_OUT_SALE); + } + + public String getLspaCovered() { + return (String) fields.get(UspV1LegacyField.LSPA_COVERED); + } +} diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoderTest.java new file mode 100644 index 00000000..bd154790 --- /dev/null +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/base64/TraditionalBase64UrlEncoderTest.java @@ -0,0 +1,40 @@ +package com.iab.gpp.encoder.base64; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class TraditionalBase64UrlEncoderTest { + + private TraditionalBase64UrlEncoder base64UrlEncoder = TraditionalBase64UrlEncoder.getInstance(); + + @Test + public void testEncode1() { + Assertions.assertEquals("DBABMAAA", base64UrlEncoder.encode("0000110000010000000000010011")); + } + + @Test + public void testEncode2() { + Assertions.assertEquals("DBACNYAA", base64UrlEncoder.encode("000011000001000000000010001101011")); + } + + @Test + public void testEncode3() { + Assertions.assertEquals("DBABjwAA", base64UrlEncoder.encode("00001100000100000000000110001111")); + } + + @Test + public void testDecode1() { + Assertions.assertEquals("000011000001000000000001001100000000000000000000", base64UrlEncoder.decode("DBABMAAA")); + } + + @Test + public void testDecode2() { + Assertions.assertEquals("000011000001000000000010001101011000000000000000", base64UrlEncoder.decode("DBACNYAA")); + } + + @Test + public void testDecode3() { + Assertions.assertEquals("000011000001000000000001100011110000000000000000", base64UrlEncoder.decode("DBABjwAA")); + } + +} From 4a516b9b910038cf627749fb1994e4e39e1cf9b5 Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 6 Sep 2023 05:30:38 -0600 Subject: [PATCH 05/36] lazier decoding --- .../java/com/iab/gpp/encoder/GppModel.java | 327 +++++++-------- .../encoder/bitstring/BitStringEncoder.java | 50 +++ .../AbstractEncodableBitStringDataType.java | 11 +- .../iab/gpp/encoder/datatype/DataType.java | 7 + .../encoder/datatype/EncodableBoolean.java | 6 +- .../encoder/datatype/EncodableDataType.java | 7 + .../encoder/datatype/EncodableDatetime.java | 3 +- .../datatype/EncodableFibonacciInteger.java | 3 +- .../EncodableFibonacciIntegerRange.java | 2 +- .../datatype/EncodableFixedBitfield.java | 6 +- .../datatype/EncodableFixedInteger.java | 3 +- .../datatype/EncodableFixedIntegerList.java | 6 +- .../datatype/EncodableFixedIntegerRange.java | 5 +- .../datatype/EncodableFixedString.java | 6 +- .../datatype/EncodableFlexibleBitfield.java | 6 +- .../EncodableOptimizedFibonacciRange.java | 5 +- .../EncodableOptimizedFixedRange.java | 8 +- .../datatype/UnencodableCharacter.java | 26 ++ .../encoder/datatype/UnencodableInteger.java | 26 ++ .../encoder/AbstractBase64UrlEncoder.java | 78 ---- .../datatype/encoder/BooleanEncoder.java | 4 +- .../encoder/CompressedBase64UrlEncoder.java | 17 - .../encoder/FixedBitfieldEncoder.java | 5 +- .../encoder/FixedIntegerListEncoder.java | 4 +- .../datatype/encoder/FixedStringEncoder.java | 4 +- .../encoder/TraditionalBase64UrlEncoder.java | 13 - .../gpp/encoder/error/DecodingException.java | 2 +- .../gpp/encoder/error/EncodingException.java | 2 +- .../encoder/error/InvalidFieldException.java | 2 +- .../encoder/error/LazyDecodingException.java | 18 - .../field/EncodableBitStringFields.java | 31 ++ .../com/iab/gpp/encoder/field/Fields.java | 14 + .../iab/gpp/encoder/field/GenericFields.java | 31 ++ .../iab/gpp/encoder/field/HeaderV1Field.java | 12 + .../iab/gpp/encoder/field/TcfCaV1Field.java | 33 ++ .../iab/gpp/encoder/field/TcfEuV2Field.java | 51 +++ .../iab/gpp/encoder/field/UsCaV1Field.java | 26 ++ .../iab/gpp/encoder/field/UsCoV1Field.java | 26 ++ .../iab/gpp/encoder/field/UsCtV1Field.java | 26 ++ .../iab/gpp/encoder/field/UsNatV1Field.java | 30 ++ .../iab/gpp/encoder/field/UsUtV1Field.java | 20 + .../iab/gpp/encoder/field/UsVaV1Field.java | 18 + .../com/iab/gpp/encoder/field/UspV1Field.java | 11 + .../gpp/encoder/field/UspV1LegacyField.java | 10 - .../AbstractEncodableBitStringSection.java | 81 ---- ...actEncodableSegmentedBitStringSection.java | 100 ----- .../AbstractLazilyEncodableSection.java | 91 +++++ .../gpp/encoder/section/EncodableSection.java | 12 +- .../com/iab/gpp/encoder/section/HeaderV1.java | 90 ++--- .../com/iab/gpp/encoder/section/TcfCaV1.java | 262 ++++-------- .../com/iab/gpp/encoder/section/TcfEuV2.java | 347 ++++++---------- .../com/iab/gpp/encoder/section/UsCaV1.java | 202 ++++------ .../com/iab/gpp/encoder/section/UsCoV1.java | 199 ++++----- .../com/iab/gpp/encoder/section/UsCtV1.java | 195 +++------ .../com/iab/gpp/encoder/section/UsNatV1.java | 215 ++++------ .../com/iab/gpp/encoder/section/UsUtV1.java | 134 +++---- .../com/iab/gpp/encoder/section/UsVaV1.java | 126 +++--- .../com/iab/gpp/encoder/section/UspV1.java | 121 +++--- .../AbstractEncodableBitStringSection.java | 81 ---- ...actEncodableSegmentedBitStringSection.java | 100 ----- .../iab/gpp/encoder/sectionbk/TcfCaV1.java | 291 -------------- .../iab/gpp/encoder/sectionbk/TcfEuV2.java | 376 ------------------ .../com/iab/gpp/encoder/sectionbk/UsCaV1.java | 208 ---------- .../com/iab/gpp/encoder/sectionbk/UsCoV1.java | 202 ---------- .../com/iab/gpp/encoder/sectionbk/UsCtV1.java | 203 ---------- .../iab/gpp/encoder/sectionbk/UsNatV1.java | 233 ----------- .../com/iab/gpp/encoder/sectionbk/UsUtV1.java | 141 ------- .../com/iab/gpp/encoder/sectionbk/UsVaV1.java | 135 ------- .../com/iab/gpp/encoder/sectionbk/UspV1.java | 107 ----- .../AbstractLazilyEncodableSegment.java | 75 ++++ .../gpp/encoder/segment/EncodableSegment.java | 18 + .../encoder/segment/HeaderV1CoreSegment.java | 57 +++ .../encoder/segment/TcfCaV1CoreSegment.java | 82 ++++ .../TcfCaV1PublisherPurposesSegment.java | 81 ++++ .../encoder/segment/TcfEuV2CoreSegment.java | 88 ++++ .../TcfEuV2PublisherPurposesSegment.java | 81 ++++ .../segment/TcfEuV2VendorsAllowedSegment.java | 55 +++ .../TcfEuV2VendorsDisclosedSegment.java | 55 +++ .../encoder/segment/UsCaV1CoreSegment.java | 67 ++++ .../gpp/encoder/segment/UsCaV1GpcSegment.java | 55 +++ .../encoder/segment/UsCoV1CoreSegment.java | 66 +++ .../gpp/encoder/segment/UsCoV1GpcSegment.java | 55 +++ .../encoder/segment/UsCtV1CoreSegment.java | 67 ++++ .../gpp/encoder/segment/UsCtV1GpcSegment.java | 55 +++ .../encoder/segment/UsNatV1CoreSegment.java | 71 ++++ .../encoder/segment/UsNatV1GpcSegment.java | 55 +++ .../encoder/segment/UsUtV1CoreSegment.java | 67 ++++ .../encoder/segment/UsVaV1CoreSegment.java | 66 +++ .../gpp/encoder/segment/UspV1CoreSegment.java | 60 +++ .../com/iab/gpp/encoder/GppModelTest.java | 125 +++--- .../EncodableOptimizedFixedRangeTest.java | 22 +- .../datatype/encoder/BooleanEncoderTest.java | 9 +- .../encoder/FixedBitfieldEncoderTest.java | 29 +- .../encoder/FixedIntegerListEncoderTest.java | 71 ++-- .../encoder/FixedStringEncoderTest.java | 8 +- .../TraditionalBase64UrlEncoderTest.java | 42 -- .../iab/gpp/encoder/section/HeaderV1Test.java | 60 +-- .../iab/gpp/encoder/section/TcfCaV1Test.java | 11 +- .../iab/gpp/encoder/section/TcfEuV2Test.java | 33 +- .../iab/gpp/encoder/section/UsCaV1Test.java | 15 +- .../iab/gpp/encoder/section/UsCoV1Test.java | 13 +- .../iab/gpp/encoder/section/UsCtV1Test.java | 8 +- .../iab/gpp/encoder/section/UsNatV1Test.java | 10 +- .../iab/gpp/encoder/section/UsUtV1Test.java | 6 +- .../iab/gpp/encoder/section/UsVaV1Test.java | 4 +- .../iab/gpp/encoder/section/UspV1Test.java | 35 +- 106 files changed, 2871 insertions(+), 4159 deletions(-) create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringEncoder.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/DataType.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDataType.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableCharacter.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableInteger.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/AbstractBase64UrlEncoder.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/CompressedBase64UrlEncoder.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoder.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/LazyDecodingException.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/EncodableBitStringFields.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/Fields.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/GenericFields.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1LegacyField.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableSegmentedBitStringSection.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractLazilyEncodableSection.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableBitStringSection.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableSegmentedBitStringSection.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfCaV1.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfEuV2.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCaV1.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCoV1.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCtV1.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsNatV1.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsUtV1.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsVaV1.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UspV1.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1CoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1PublisherPurposesSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2CoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2PublisherPurposesSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsAllowedSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsDisclosedSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1GpcSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1GpcSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1GpcSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1GpcSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java delete mode 100644 iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoderTest.java 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 501ec737..c51d8985 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,10 +5,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; -import com.iab.gpp.encoder.error.LazyDecodingException; import com.iab.gpp.encoder.section.EncodableSection; import com.iab.gpp.encoder.section.HeaderV1; import com.iab.gpp.encoder.section.Sections; @@ -26,38 +24,29 @@ public class GppModel { private Map sections = new HashMap<>(); private String encodedString; - private boolean decoded; - private boolean dirty; - + + private boolean dirty = false; + private boolean decoded = true; + public GppModel() { - this.encodedString = "DBAA"; - this.decoded = false; - this.dirty = false; + } public GppModel(String encodedString) { - this.encodedString = encodedString; - this.decoded = false; - this.dirty = false; + decode(encodedString); } - public void setFieldValue(int sectionId, String fieldName, Object value) - throws InvalidFieldException, LazyDecodingException { + public void setFieldValue(int sectionId, String fieldName, Object value) { setFieldValue(Sections.SECTION_ID_NAME_MAP.get(sectionId), fieldName, value); - this.dirty = true; } - public void setFieldValue(String sectionName, String fieldName, Object value) - throws InvalidFieldException, LazyDecodingException { - // lazily decode - if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { - try { - this.decode(this.encodedString); - } catch (DecodingException e) { - throw new LazyDecodingException(e); - } + 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)) { @@ -100,20 +89,17 @@ public void setFieldValue(String sectionName, String fieldName, Object value) } } - public Object getFieldValue(int sectionId, String fieldName) throws LazyDecodingException { + public Object getFieldValue(int sectionId, String fieldName) { return getFieldValue(Sections.SECTION_ID_NAME_MAP.get(sectionId), fieldName); } - public Object getFieldValue(String sectionName, String fieldName) throws LazyDecodingException { - // lazily decode - if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { - try { - this.decode(this.encodedString); - } catch (DecodingException e) { - throw new LazyDecodingException(e); - } + public Object getFieldValue(String sectionName, String fieldName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; } - + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName).getFieldValue(fieldName); } else { @@ -121,20 +107,17 @@ public Object getFieldValue(String sectionName, String fieldName) throws LazyDec } } - public boolean hasField(int sectionId, String fieldName) throws LazyDecodingException { + public boolean hasField(int sectionId, String fieldName) { return hasField(Sections.SECTION_ID_NAME_MAP.get(sectionId), fieldName); } - public boolean hasField(String sectionName, String fieldName) throws LazyDecodingException { - // lazily decode - if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { - try { - this.decode(this.encodedString); - } catch (DecodingException e) { - throw new LazyDecodingException(e); - } + public boolean hasField(String sectionName, String fieldName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; } - + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName).hasField(fieldName); } else { @@ -142,33 +125,27 @@ public boolean hasField(String sectionName, String fieldName) throws LazyDecodin } } - public boolean hasSection(int sectionId) throws LazyDecodingException { + public boolean hasSection(int sectionId) { return hasSection(Sections.SECTION_ID_NAME_MAP.get(sectionId)); } - public boolean hasSection(String sectionName) throws LazyDecodingException { - // lazily decode - if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { - try { - this.decode(this.encodedString); - } catch (DecodingException e) { - throw new LazyDecodingException(e); - } + public boolean hasSection(String sectionName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; } - + return this.sections.containsKey(sectionName); } - public HeaderV1 getHeader() throws LazyDecodingException { - // lazily decode - if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { - try { - this.decode(this.encodedString); - } catch (DecodingException e) { - throw new LazyDecodingException(e); - } + public HeaderV1 getHeader() { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; } - + HeaderV1 header = new HeaderV1(); try { header.setFieldValue("SectionIds", this.getSectionIds()); @@ -178,20 +155,17 @@ public HeaderV1 getHeader() throws LazyDecodingException { return header; } - public EncodableSection getSection(int sectionId) throws LazyDecodingException { + public EncodableSection getSection(int sectionId) { return getSection(Sections.SECTION_ID_NAME_MAP.get(sectionId)); } - public EncodableSection getSection(String sectionName) throws LazyDecodingException { - // lazily decode - if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { - try { - this.decode(this.encodedString); - } catch (DecodingException e) { - throw new LazyDecodingException(e); - } + public EncodableSection getSection(String sectionName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; } - + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName); } else { @@ -199,20 +173,17 @@ public EncodableSection getSection(String sectionName) throws LazyDecodingExcept } } - public void deleteSection(int sectionId) throws LazyDecodingException { + public void deleteSection(int sectionId) { deleteSection(Sections.SECTION_ID_NAME_MAP.get(sectionId)); } - public void deleteSection(String sectionName) throws LazyDecodingException { - // lazily decode - if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { - try { - this.decode(this.encodedString); - } catch (DecodingException e) { - throw new LazyDecodingException(e); - } + public void deleteSection(String sectionName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; } - + if (this.sections.containsKey(sectionName)) { this.sections.remove(sectionName); this.dirty = true; @@ -221,57 +192,54 @@ public void deleteSection(String sectionName) throws LazyDecodingException { public void clear() { this.sections.clear(); - this.encodedString = "DBAA"; - this.decoded = false; + this.encodedString = null; this.dirty = false; + this.decoded = true; } - public TcfCaV1 getTcfCaV1Section() throws LazyDecodingException { + public TcfCaV1 getTcfCaV1Section() { return (TcfCaV1) getSection(TcfCaV1.NAME); } - public TcfEuV2 getTcfEuV2Section() throws LazyDecodingException { + public TcfEuV2 getTcfEuV2Section() { return (TcfEuV2) getSection(TcfEuV2.NAME); } - public UspV1 getUspV1Section() throws LazyDecodingException { + public UspV1 getUspV1Section() { return (UspV1) getSection(UspV1.NAME); } - public UsNatV1 getUsNatV1Section() throws LazyDecodingException { + public UsNatV1 getUspNatV1Section() { return (UsNatV1) getSection(UsNatV1.NAME); } - public UsCaV1 getUsCaV1Section() throws LazyDecodingException { + public UsCaV1 getUspCaV1Section() { return (UsCaV1) getSection(UsCaV1.NAME); } - public UsVaV1 getUsVaV1Section() throws LazyDecodingException { + public UsVaV1 getUspVaV1Section() { return (UsVaV1) getSection(UsVaV1.NAME); } - public UsCoV1 getUsCoV1Section() throws LazyDecodingException { + public UsCoV1 getUspCoV1Section() { return (UsCoV1) getSection(UsCoV1.NAME); } - public UsUtV1 getUsUtV1Section() throws LazyDecodingException { + public UsUtV1 getUspUtV1Section() { return (UsUtV1) getSection(UsUtV1.NAME); } - public UsCtV1 getUsCtV1Section() throws LazyDecodingException { + public UsCtV1 getUspCtV1Section() { return (UsCtV1) getSection(UsCtV1.NAME); } - public List getSectionIds() throws LazyDecodingException { - // lazily decode - if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { - try { - this.decode(this.encodedString); - } catch (DecodingException e) { - throw new LazyDecodingException(e); - } + public List getSectionIds() { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; } - + List sectionIds = new ArrayList<>(); for (int i = 0; i < Sections.SECTION_ORDER.size(); i++) { String sectionName = Sections.SECTION_ORDER.get(i); @@ -283,26 +251,13 @@ public List getSectionIds() throws LazyDecodingException { return sectionIds; } - public String encode() throws EncodingException, LazyDecodingException { - if (!this.dirty) { - return this.encodedString; - } - - // lazily decode - if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { - try { - this.decode(this.encodedString); - } catch (DecodingException e) { - throw new LazyDecodingException(e); - } - } - + protected String encodeModel(Map sections) { List encodedSections = new ArrayList<>(); List sectionIds = new ArrayList<>(); for (int i = 0; i < Sections.SECTION_ORDER.size(); i++) { String sectionName = Sections.SECTION_ORDER.get(i); - if (this.sections.containsKey(sectionName)) { - EncodableSection section = this.sections.get(sectionName); + if (sections.containsKey(sectionName)) { + EncodableSection section = sections.get(sectionName); encodedSections.add(section.encode()); sectionIds.add(section.getId()); } @@ -310,76 +265,66 @@ public String encode() throws EncodingException, LazyDecodingException { HeaderV1 header = new HeaderV1(); try { - header.setFieldValue("SectionIds", this.getSectionIds()); + header.setFieldValue("SectionIds", getSectionIds()); } catch (InvalidFieldException e) { throw new EncodingException(e); } encodedSections.add(0, header.encode()); - this.encodedString = encodedSections.stream().collect(Collectors.joining("~")); - this.dirty = false; + String encodedString = encodedSections.stream().collect(Collectors.joining("~")); return encodedString; } - public void decode(String str) throws DecodingException { - this.encodedString = str; - this.sections.clear(); - - String[] encodedSections = str.split("~"); - HeaderV1 header = new HeaderV1(encodedSections[0]); - this.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]); - this.sections.put(TcfEuV2.NAME, section); - } else if (sectionIds.get(i).equals(TcfCaV1.ID)) { - TcfCaV1 section = new TcfCaV1(encodedSections[i + 1]); - this.sections.put(TcfCaV1.NAME, section); - } else if (sectionIds.get(i).equals(UspV1.ID)) { - UspV1 section = new UspV1(encodedSections[i + 1]); - this.sections.put(UspV1.NAME, section); - } else if (sectionIds.get(i).equals(UsCaV1.ID)) { - UsCaV1 section = new UsCaV1(encodedSections[i + 1]); - this.sections.put(UsCaV1.NAME, section); - } else if (sectionIds.get(i).equals(UsNatV1.ID)) { - UsNatV1 section = new UsNatV1(encodedSections[i + 1]); - this.sections.put(UsNatV1.NAME, section); - } else if (sectionIds.get(i).equals(UsVaV1.ID)) { - UsVaV1 section = new UsVaV1(encodedSections[i + 1]); - this.sections.put(UsVaV1.NAME, section); - } else if (sectionIds.get(i).equals(UsCoV1.ID)) { - UsCoV1 section = new UsCoV1(encodedSections[i + 1]); - this.sections.put(UsCoV1.NAME, section); - } else if (sectionIds.get(i).equals(UsUtV1.ID)) { - UsUtV1 section = new UsUtV1(encodedSections[i + 1]); - this.sections.put(UsUtV1.NAME, section); - } else if (sectionIds.get(i).equals(UsCtV1.ID)) { - UsCtV1 section = new UsCtV1(encodedSections[i + 1]); - this.sections.put(UsCtV1.NAME, section); + protected Map decodeModel(String str) { + Map sections = new HashMap<>(); + + if(str != null && !str.isEmpty()) { + String[] encodedSections = str.split("~"); + HeaderV1 header = new HeaderV1(encodedSections[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(UsCaV1.ID)) { + UsCaV1 section = new UsCaV1(encodedSections[i + 1]); + sections.put(UsCaV1.NAME, section); + } else if (sectionIds.get(i).equals(UsNatV1.ID)) { + UsNatV1 section = new UsNatV1(encodedSections[i + 1]); + sections.put(UsNatV1.NAME, section); + } else if (sectionIds.get(i).equals(UsVaV1.ID)) { + UsVaV1 section = new UsVaV1(encodedSections[i + 1]); + sections.put(UsVaV1.NAME, section); + } else if (sectionIds.get(i).equals(UsCoV1.ID)) { + UsCoV1 section = new UsCoV1(encodedSections[i + 1]); + sections.put(UsCoV1.NAME, section); + } else if (sectionIds.get(i).equals(UsUtV1.ID)) { + UsUtV1 section = new UsUtV1(encodedSections[i + 1]); + sections.put(UsUtV1.NAME, section); + } else if (sectionIds.get(i).equals(UsCtV1.ID)) { + UsCtV1 section = new UsCtV1(encodedSections[i + 1]); + sections.put(UsCtV1.NAME, section); + } } } - - this.decoded = true; - this.dirty = false; + + return sections; } - public String encodeSection(int sectionId) throws EncodingException, LazyDecodingException { + public String encodeSection(int sectionId) { return encodeSection(Sections.SECTION_ID_NAME_MAP.get(sectionId)); } - public String encodeSection(String sectionName) throws EncodingException, LazyDecodingException { - // lazily decode - if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { - try { - this.decode(this.encodedString); - } catch (DecodingException e) { - throw new LazyDecodingException(e); - } - } - + public String encodeSection(String sectionName) { if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName).encode(); } else { @@ -387,20 +332,11 @@ public String encodeSection(String sectionName) throws EncodingException, LazyDe } } - public void decodeSection(int sectionId, String encodedString) throws DecodingException { + public void decodeSection(int sectionId, String encodedString) { decodeSection(Sections.SECTION_ID_NAME_MAP.get(sectionId), encodedString); } - public void decodeSection(String sectionName, String encodedString) throws DecodingException { - // lazily decode - if (!this.decoded && this.encodedString != null && this.encodedString.length() > 0) { - try { - this.decode(this.encodedString); - } catch (DecodingException e) { - throw new LazyDecodingException(e); - } - } - + public void decodeSection(String sectionName, String encodedString) { EncodableSection section = null; if (!this.sections.containsKey(sectionName)) { if (sectionName.equals(TcfEuV2.NAME)) { @@ -437,7 +373,24 @@ public void decodeSection(String sectionName, String encodedString) throws Decod if (section != null) { section.decode(encodedString); - this.dirty = true; } } -} + + public String encode() { + if (this.encodedString == null || this.encodedString.isEmpty() || this.dirty) { + this.encodedString = encodeModel(this.sections); + this.dirty = false; + this.decoded = true; + } + + return this.encodedString; + } + + public void decode(String encodedString) { + this.encodedString = encodedString; + this.dirty = false; + this.decoded = false; + } + + +} \ No newline at end of file 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 new file mode 100644 index 00000000..20ef6fdd --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/bitstring/BitStringEncoder.java @@ -0,0 +1,50 @@ +package com.iab.gpp.encoder.bitstring; + +import java.util.List; +import com.iab.gpp.encoder.datatype.AbstractEncodableBitStringDataType; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; +import com.iab.gpp.encoder.field.EncodableBitStringFields; + +public class BitStringEncoder { + + private static BitStringEncoder instance = new BitStringEncoder(); + + private BitStringEncoder() { + + } + + public static BitStringEncoder getInstance() { + return instance; + } + + public String encode(EncodableBitStringFields fields, List fieldNames) { + String bitString = ""; + 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(); + } else { + throw new EncodingException("Field not found: '" + fieldName + "'"); + } + } + + return bitString; + } + + public void decode(String bitString, List fieldNames, EncodableBitStringFields fields) { + int index = 0; + for (int i = 0; i < fieldNames.size(); i++) { + String fieldName = fieldNames.get(i); + if (fields.containsKey(fieldName)) { + AbstractEncodableBitStringDataType field = fields.get(fieldName); + String substring = field.substring(bitString, index); + field.decode(substring); + index += substring.length(); + } else { + throw new DecodingException("Field not found: '" + fieldName + "'"); + } + } + } +} 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 27359760..12a6011b 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 @@ -1,9 +1,6 @@ package com.iab.gpp.encoder.datatype; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; - -public abstract class AbstractEncodableBitStringDataType { +public abstract class AbstractEncodableBitStringDataType implements EncodableDataType { protected T value; protected AbstractEncodableBitStringDataType() { @@ -23,9 +20,5 @@ public void setValue(Object value) { this.value = (T) value; } - public abstract String encode() throws EncodingException; - - public abstract void decode(String bitString) throws DecodingException; - - public abstract String substring(String bitString, int fromIndex) throws DecodingException; + public abstract String substring(String str, int fromIndex); } 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 new file mode 100644 index 00000000..8a0d2c07 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/DataType.java @@ -0,0 +1,7 @@ +package com.iab.gpp.encoder.datatype; + +public interface DataType { + boolean hasValue(); + T getValue(); + void setValue(Object value); +} 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 09d47ac7..a8f0b601 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,8 +1,6 @@ package com.iab.gpp.encoder.datatype; 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 { @@ -15,11 +13,11 @@ public EncodableBoolean(Boolean value) { setValue(value); } - public String encode() throws EncodingException { + public String encode() { return BooleanEncoder.encode(this.value); } - public void decode(String bitString) throws DecodingException { + public void decode(String bitString) { this.value = BooleanEncoder.decode(bitString); } 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 new file mode 100644 index 00000000..94d416a6 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableDataType.java @@ -0,0 +1,7 @@ +package com.iab.gpp.encoder.datatype; + +public interface EncodableDataType extends DataType { + String encode(); + + void decode(String 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 f146d0aa..4fdfd447 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 @@ -2,7 +2,6 @@ import java.time.ZonedDateTime; import com.iab.gpp.encoder.datatype.encoder.DatetimeEncoder; -import com.iab.gpp.encoder.error.DecodingException; public class EncodableDatetime extends AbstractEncodableBitStringDataType { @@ -19,7 +18,7 @@ public String encode() { return DatetimeEncoder.encode(this.value); } - public void decode(String bitString) throws DecodingException { + public void decode(String bitString) { this.value = DatetimeEncoder.decode(bitString); } 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 5d4e1783..dc413368 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,7 +1,6 @@ package com.iab.gpp.encoder.datatype; import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerEncoder; -import com.iab.gpp.encoder.error.DecodingException; public class EncodableFibonacciInteger extends AbstractEncodableBitStringDataType { @@ -18,7 +17,7 @@ public String encode() { return FibonacciIntegerEncoder.encode(this.value); } - public void decode(String bitString) throws DecodingException { + public void decode(String bitString) { this.value = FibonacciIntegerEncoder.decode(bitString); } 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 eaff0382..48d69559 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 @@ -22,7 +22,7 @@ public String encode() { return FibonacciIntegerRangeEncoder.encode(this.value); } - public void decode(String bitString) throws DecodingException { + public void decode(String bitString) { this.value = FibonacciIntegerRangeEncoder.decode(bitString); } 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 e0ae9b8e..5f4cd5e4 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 @@ -3,8 +3,6 @@ import java.util.ArrayList; import java.util.List; import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class EncodableFixedBitfield extends AbstractEncodableBitStringDataType> { @@ -21,11 +19,11 @@ public EncodableFixedBitfield(List value) { setValue(value); } - public String encode() throws EncodingException { + public String encode() { return FixedBitfieldEncoder.encode(this.value, this.numElements); } - public void decode(String bitString) throws DecodingException { + public void decode(String bitString) { this.value = FixedBitfieldEncoder.decode(bitString); } 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 8b0fcb7e..05802f65 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,7 +1,6 @@ package com.iab.gpp.encoder.datatype; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; -import com.iab.gpp.encoder.error.DecodingException; public class EncodableFixedInteger extends AbstractEncodableBitStringDataType { @@ -22,7 +21,7 @@ public String encode() { return FixedIntegerEncoder.encode(this.value, this.bitStringLength); } - public void decode(String bitString) throws DecodingException { + public void decode(String bitString) { this.value = FixedIntegerEncoder.decode(bitString); } 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 ccaca886..9ac06346 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 @@ -3,8 +3,6 @@ import java.util.ArrayList; import java.util.List; 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> { @@ -24,11 +22,11 @@ public EncodableFixedIntegerList(int elementBitStringLength, List value setValue(value); } - public String encode() throws EncodingException { + public String encode() { return FixedIntegerListEncoder.encode(this.value, this.elementBitStringLength, this.numElements); } - public void decode(String bitString) throws DecodingException { + public void decode(String bitString) { this.value = FixedIntegerListEncoder.decode(bitString, this.elementBitStringLength, this.numElements); } 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 e43751af..d78f5186 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 @@ -5,7 +5,6 @@ import java.util.TreeSet; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; -import com.iab.gpp.encoder.error.DecodingException; public class EncodableFixedIntegerRange extends AbstractEncodableBitStringDataType> { @@ -22,11 +21,11 @@ public String encode() { return FixedIntegerRangeEncoder.encode(this.value); } - public void decode(String bitString) throws DecodingException { + public void decode(String bitString) { this.value = FixedIntegerRangeEncoder.decode(bitString); } - public String substring(String bitString, int fromIndex) throws DecodingException { + public String substring(String bitString, int fromIndex) { // TODO: add some validation int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 12)); int index = fromIndex + 12; 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 ed736fc2..f7c92665 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,8 +1,6 @@ package com.iab.gpp.encoder.datatype; 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 { @@ -19,11 +17,11 @@ public EncodableFixedString(int stringLength, String value) { setValue(value); } - public String encode() throws EncodingException { + public String encode() { return FixedStringEncoder.encode(this.value, this.stringLength); } - public void decode(String bitString) throws DecodingException { + public void decode(String bitString) { this.value = FixedStringEncoder.decode(bitString); } 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 93c3c26b..b38235ac 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 @@ -4,8 +4,6 @@ import java.util.List; import java.util.function.IntSupplier; import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class EncodableFlexibleBitfield extends AbstractEncodableBitStringDataType> { @@ -22,11 +20,11 @@ public EncodableFlexibleBitfield(IntSupplier getLengthSupplier, List va this.setValue(value); } - public String encode() throws EncodingException { + public String encode() { return FixedBitfieldEncoder.encode(this.value, this.getLengthSupplier.getAsInt()); } - public void decode(String bitString) throws DecodingException { + public void decode(String bitString) { this.value = FixedBitfieldEncoder.decode(bitString); } 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 d32dcc49..891ff673 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 @@ -7,7 +7,6 @@ import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class EncodableOptimizedFibonacciRange extends AbstractEncodableBitStringDataType> { @@ -20,7 +19,7 @@ public EncodableOptimizedFibonacciRange(List value) { setValue(value); } - public String encode() throws EncodingException { + public String encode() { // 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 = this.value.size() > 0 ? this.value.get(this.value.size() - 1) : 0; @@ -45,7 +44,7 @@ public String encode() throws EncodingException { } } - public void decode(String bitString) throws DecodingException { + public void decode(String bitString) { if (bitString.charAt(16) == '1') { this.value = FibonacciIntegerRangeEncoder.decode(bitString.substring(17)); } else { 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 d3250f07..9dbbf5ae 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 @@ -6,8 +6,6 @@ import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class EncodableOptimizedFixedRange extends AbstractEncodableBitStringDataType> { @@ -20,7 +18,7 @@ public EncodableOptimizedFixedRange(List value) { setValue(value); } - public String encode() throws EncodingException { + public String encode() { // 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 = this.value.size() > 0 ? this.value.get(this.value.size() - 1) : 0; @@ -46,7 +44,7 @@ public String encode() throws EncodingException { } } - public void decode(String bitString) throws DecodingException { + public void decode(String bitString) { if (bitString.charAt(16) == '1') { this.value = FixedIntegerRangeEncoder.decode(bitString.substring(17)); } else { @@ -61,7 +59,7 @@ public void decode(String bitString) throws DecodingException { } } - public String substring(String bitString, int fromIndex) throws DecodingException { + public String substring(String bitString, int fromIndex) { int max = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 16)); if (bitString.charAt(fromIndex + 16) == '1') { return bitString.substring(fromIndex, fromIndex + 17) 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 new file mode 100644 index 00000000..31fd0caa --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableCharacter.java @@ -0,0 +1,26 @@ +package com.iab.gpp.encoder.datatype; + +public class UnencodableCharacter implements DataType { + + private Character value = null; + + public UnencodableCharacter(Character value) { + this.value = value; + } + + @Override + public boolean hasValue() { + return this.value != null; + } + + @Override + public Character getValue() { + return this.value; + } + + @Override + public void setValue(Object value) { + this.value = value.toString().charAt(0); + } + +} 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 new file mode 100644 index 00000000..7435ff2d --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/UnencodableInteger.java @@ -0,0 +1,26 @@ +package com.iab.gpp.encoder.datatype; + +public class UnencodableInteger implements DataType { + + private Integer value = null; + + public UnencodableInteger(Integer value) { + this.value = value; + } + + @Override + public boolean hasValue() { + return this.value != null; + } + + @Override + public Integer getValue() { + return this.value; + } + + @Override + public void setValue(Object value) { + this.value = (Integer)value; + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/AbstractBase64UrlEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/AbstractBase64UrlEncoder.java deleted file mode 100644 index 698a0994..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/AbstractBase64UrlEncoder.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.iab.gpp.encoder.datatype.encoder; - -import java.util.Map; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; - -public abstract class AbstractBase64UrlEncoder { - - abstract protected String pad(String bitString); - - /** - * 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) throws EncodingException { - // should only be 0 or 1 - if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) { - throw new EncodingException("Unencodable Base64Url '" + bitString + "'"); - } - - bitString = pad(bitString); - - String str = ""; - - int index = 0; - while (index <= bitString.length() - 6) { - String s = bitString.substring(index, index + 6); - - try { - int n = FixedIntegerEncoder.decode(s); - Character c = AbstractBase64UrlEncoder.DICT.charAt(n); - str += c; - index += 6; - } catch (DecodingException e) { - throw new EncodingException("Unencodable Base64Url '" + bitString + "'"); - } - } - - return str; - } - - public String decode(String str) throws DecodingException { - // 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++) { - char c = str.charAt(i); - Integer n = AbstractBase64UrlEncoder.REVERSE_DICT.get(c); - String s = FixedIntegerEncoder.encode(n, 6); - bitString += s; - } - - return bitString; - } -} 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 b49ff391..20e6cbd0 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 @@ -4,7 +4,7 @@ import com.iab.gpp.encoder.error.EncodingException; public class BooleanEncoder { - public static String encode(Boolean value) throws EncodingException { + public static String encode(Boolean value) { if (value == true) { return "1"; } else if (value == false) { @@ -14,7 +14,7 @@ public static String encode(Boolean value) throws EncodingException { } } - public static boolean decode(String bitString) throws DecodingException { + public static boolean decode(String bitString) { if (bitString.equals("1")) { return true; } else if (bitString.equals("0")) { diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/CompressedBase64UrlEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/CompressedBase64UrlEncoder.java deleted file mode 100644 index c41e7465..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/CompressedBase64UrlEncoder.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.iab.gpp.encoder.datatype.encoder; - -public class CompressedBase64UrlEncoder extends AbstractBase64UrlEncoder { - - @Override - protected String pad(String bitString) { - while (bitString.length() % 8 > 0) { - bitString += "0"; - } - while (bitString.length() % 6 > 0) { - bitString += "0"; - } - - return bitString; - } - -} 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 20a71c13..05c53dcd 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 @@ -4,13 +4,12 @@ import java.util.List; import java.util.regex.Pattern; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class FixedBitfieldEncoder { private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE); - public static String encode(List value, int bitStringLength) throws EncodingException { + public static String encode(List value, int bitStringLength) { String bitString = ""; for (int i = 0; i < value.size(); i++) { bitString += BooleanEncoder.encode(value.get(i)); @@ -23,7 +22,7 @@ public static String encode(List value, int bitStringLength) throws Enc return bitString; } - public static List decode(String bitString) throws DecodingException { + public static List decode(String bitString) { if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) { throw new DecodingException("Undecodable FixedBitfield '" + 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 ba829322..e130f50d 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 @@ -4,14 +4,12 @@ import java.util.List; import java.util.regex.Pattern; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class FixedIntegerListEncoder { private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE); - public static String encode(List value, int elementBitStringLength, int numElements) - throws EncodingException { + public static String encode(List value, int elementBitStringLength, int numElements) { String bitString = ""; for (int i = 0; i < value.size(); i++) { bitString += FixedIntegerEncoder.encode(value.get(i), elementBitStringLength); 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 5cb8762a..38db681e 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 @@ -8,7 +8,7 @@ public class FixedStringEncoder { private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE); - public static String encode(String value, int stringLength) throws EncodingException { + public static String encode(String value, int stringLength) { while (value.length() < stringLength) { value += " "; } @@ -29,7 +29,7 @@ public static String encode(String value, int stringLength) throws EncodingExcep return bitString; } - public static String decode(String bitString) throws DecodingException { + public static String decode(String bitString) { if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches() || bitString.length() % 6 != 0) { throw new DecodingException("Undecodable FixedString '" + bitString + "'"); } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoder.java deleted file mode 100644 index 848bbfe5..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoder.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.iab.gpp.encoder.datatype.encoder; - -public class TraditionalBase64UrlEncoder extends AbstractBase64UrlEncoder { - - @Override - protected String pad(String bitString) { - while (bitString.length() % 24 > 0) { - bitString += "0"; - } - return bitString; - } - -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/DecodingException.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/DecodingException.java index 91c29b2f..d60c3459 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/DecodingException.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/DecodingException.java @@ -1,6 +1,6 @@ package com.iab.gpp.encoder.error; -public class DecodingException extends Exception { +public class DecodingException extends RuntimeException { private static final long serialVersionUID = 2098268445119981680L; diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/EncodingException.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/EncodingException.java index 2c7f80ad..a7f19355 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/EncodingException.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/EncodingException.java @@ -1,6 +1,6 @@ package com.iab.gpp.encoder.error; -public class EncodingException extends Exception { +public class EncodingException extends RuntimeException { private static final long serialVersionUID = 1161321945571871601L; diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/InvalidFieldException.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/InvalidFieldException.java index 5b1e1aa9..22113280 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/InvalidFieldException.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/InvalidFieldException.java @@ -1,6 +1,6 @@ package com.iab.gpp.encoder.error; -public class InvalidFieldException extends Exception { +public class InvalidFieldException extends RuntimeException { private static final long serialVersionUID = 2098268445119981680L; diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/LazyDecodingException.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/LazyDecodingException.java deleted file mode 100644 index 070a02d8..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/LazyDecodingException.java +++ /dev/null @@ -1,18 +0,0 @@ -package com.iab.gpp.encoder.error; - -public class LazyDecodingException extends DecodingException { - - private static final long serialVersionUID = 2098268445119981680L; - - public LazyDecodingException(String msg) { - super(msg); - } - - public LazyDecodingException(Exception e) { - super(e); - } - - public LazyDecodingException(String msg, Exception e) { - super(msg, e); - } -} 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 new file mode 100644 index 00000000..d2ac0f43 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/EncodableBitStringFields.java @@ -0,0 +1,31 @@ +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> { + + 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 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/Fields.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/Fields.java new file mode 100644 index 00000000..ca091e7f --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/Fields.java @@ -0,0 +1,14 @@ +package com.iab.gpp.encoder.field; + +import java.util.Map; +import com.iab.gpp.encoder.datatype.DataType; + +public interface Fields> { + + boolean containsKey(String key); + void put(String key, T value); + T get(String key); + Map getAll(); + void reset(Fields fields); + +} 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 new file mode 100644 index 00000000..00263e55 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/GenericFields.java @@ -0,0 +1,31 @@ +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> { + + 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 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 384befab..17f1f5d9 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,9 +1,21 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class HeaderV1Field { public static String ID = "Id"; public static String VERSION = "Version"; public static String SECTION_IDS = "SectionIds"; + //@formatter:off + public static List HEADER_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + 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 86c91dff..4cacd6dc 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,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class TcfCaV1Field { public static String VERSION = "Version"; @@ -25,4 +28,34 @@ public class TcfCaV1Field { public static String CUSTOM_PURPOSES_EXPRESS_CONSENT = "CustomPurposesExpressConsent"; public static String CUSTOM_PURPOSES_IMPLIED_CONSENT = "CustomPurposesImpliedConsent"; + //@formatter:off + public static List TCFCAV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + TcfCaV1Field.VERSION, + TcfCaV1Field.CREATED, + TcfCaV1Field.LAST_UPDATED, + TcfCaV1Field.CMP_ID, + TcfCaV1Field.CMP_VERSION, + TcfCaV1Field.CONSENT_SCREEN, + TcfCaV1Field.CONSENT_LANGUAGE, + TcfCaV1Field.VENDOR_LIST_VERSION, + TcfCaV1Field.TCF_POLICY_VERSION, + TcfCaV1Field.USE_NON_STANDARD_STACKS, + TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT, + TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, + TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, + TcfCaV1Field.VENDOR_EXPRESS_CONSENT, + TcfCaV1Field.VENDOR_IMPLIED_CONSENT + }); + //@formatter:on + + //@formatter:off + public static List TCFCAV1_PUBLISHER_PURPOSES_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + 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, + }); + //@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 660443c3..fedb510f 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,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class TcfEuV2Field { public static String VERSION = "Version"; @@ -32,4 +35,52 @@ public class TcfEuV2Field { public static String VENDORS_DISCLOSED_SEGMENT_TYPE = "VendorsDisclosedSegmentType"; public static String VENDORS_DISCLOSED = "VendorsDisclosed"; + //@formatter:off + public static List TCFEUV2_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + TcfEuV2Field.VERSION, + TcfEuV2Field.CREATED, + TcfEuV2Field.LAST_UPDATED, + TcfEuV2Field.CMP_ID, + TcfEuV2Field.CMP_VERSION, + TcfEuV2Field.CONSENT_SCREEN, + TcfEuV2Field.CONSENT_LANGUAGE, + TcfEuV2Field.VENDOR_LIST_VERSION, + TcfEuV2Field.POLICY_VERSION, + TcfEuV2Field.IS_SERVICE_SPECIFIC, + TcfEuV2Field.USE_NON_STANDARD_STACKS, + TcfEuV2Field.SPECIAL_FEATURE_OPTINS, + TcfEuV2Field.PURPOSE_CONSENTS, + TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS, + TcfEuV2Field.PURPOSE_ONE_TREATMENT, + TcfEuV2Field.PUBLISHER_COUNTRY_CODE, + 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[] { + 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, + }); + //@formatter:on + + //@formatter:off + public static List TCFEUV2_VENDORS_ALLOWED_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE, + TcfEuV2Field.VENDORS_ALLOWED, + }); + //@formatter:on + + //@formatter:off + public static List TCFEUV2_VENDORS_DISCLOSED_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE, + TcfEuV2Field.VENDORS_DISCLOSED, + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCaV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCaV1Field.java index 0c139803..07c1a13f 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCaV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCaV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UsCaV1Field { public static String VERSION = "Version"; @@ -19,4 +22,27 @@ public class UsCaV1Field { public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; public static String GPC = "Gpc"; + //@formatter:off + public static List USCAV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsCaV1Field.VERSION, + UsCaV1Field.SALE_OPT_OUT_NOTICE, + UsCaV1Field.SHARING_OPT_OUT_NOTICE, + UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, + UsCaV1Field.SALE_OPT_OUT, + UsCaV1Field.SHARING_OPT_OUT, + UsCaV1Field.SENSITIVE_DATA_PROCESSING, + UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsCaV1Field.PERSONAL_DATA_CONSENTS, + UsCaV1Field.MSPA_COVERED_TRANSACTION, + UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE + }); + //@formatter:on + + //@formatter:off + public static List USCAV1_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsCaV1Field.GPC_SEGMENT_TYPE, + UsCaV1Field.GPC + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCoV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCoV1Field.java index 8bcce1a3..36489c13 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCoV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCoV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UsCoV1Field { public static String VERSION = "Version"; @@ -17,4 +20,27 @@ public class UsCoV1Field { public static String GPC_SEGMENT_TYPE = "GpcSegmentType"; public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; public static String GPC = "Gpc"; + + //@formatter:off + public static List USCOV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsCoV1Field.VERSION, + UsCoV1Field.SHARING_NOTICE, + UsCoV1Field.SALE_OPT_OUT_NOTICE, + UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsCoV1Field.SALE_OPT_OUT, + UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsCoV1Field.SENSITIVE_DATA_PROCESSING, + UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsCoV1Field.MSPA_COVERED_TRANSACTION, + UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE + }); + //@formatter:on + + //@formatter:off + public static List USCOV1_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsCoV1Field.GPC_SEGMENT_TYPE, + UsCoV1Field.GPC + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCtV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCtV1Field.java index ba7b9b07..31e67a69 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCtV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsCtV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UsCtV1Field { public static String VERSION = "Version"; @@ -17,4 +20,27 @@ public class UsCtV1Field { public static String GPC_SEGMENT_TYPE = "GpcSegmentType"; public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; public static String GPC = "Gpc"; + + //@formatter:off + public static List USCTV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsCtV1Field.VERSION, + UsCtV1Field.SHARING_NOTICE, + UsCtV1Field.SALE_OPT_OUT_NOTICE, + UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsCtV1Field.SALE_OPT_OUT, + UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsCtV1Field.SENSITIVE_DATA_PROCESSING, + UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsCtV1Field.MSPA_COVERED_TRANSACTION, + UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE + }); + //@formatter:on + + //@formatter:off + public static List USCTV1_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsCtV1Field.GPC_SEGMENT_TYPE, + UsCtV1Field.GPC + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNatV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNatV1Field.java index 5a023e8f..0bdf0fb6 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNatV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsNatV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UsNatV1Field { public static String VERSION = "Version"; @@ -23,4 +26,31 @@ public class UsNatV1Field { public static String GPC_SEGMENT_INCLUDED = "GpcSegmentIncluded"; public static String GPC = "Gpc"; + //@formatter:off + public static List USNATV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsNatV1Field.VERSION, + UsNatV1Field.SHARING_NOTICE, + UsNatV1Field.SALE_OPT_OUT_NOTICE, + UsNatV1Field.SHARING_OPT_OUT_NOTICE, + UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, + UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, + UsNatV1Field.SALE_OPT_OUT, + UsNatV1Field.SHARING_OPT_OUT, + UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsNatV1Field.SENSITIVE_DATA_PROCESSING, + UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsNatV1Field.PERSONAL_DATA_CONSENTS, + UsNatV1Field.MSPA_COVERED_TRANSACTION, + UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE + }); + //@formatter:on + + //@formatter:off + public static List USNATV1_GPC_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsNatV1Field.GPC_SEGMENT_TYPE, + UsNatV1Field.GPC + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsUtV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsUtV1Field.java index 7a649e90..be7584a4 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsUtV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsUtV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UsUtV1Field { public static String VERSION = "Version"; @@ -14,4 +17,21 @@ public class UsUtV1Field { public static String MSPA_COVERED_TRANSACTION = "MspaCoveredTransaction"; public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode"; public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode"; + + //@formatter:off + public static List USUTV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsUtV1Field.VERSION, + UsUtV1Field.SHARING_NOTICE, + UsUtV1Field.SALE_OPT_OUT_NOTICE, + UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, + UsUtV1Field.SALE_OPT_OUT, + UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsUtV1Field.SENSITIVE_DATA_PROCESSING, + UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsUtV1Field.MSPA_COVERED_TRANSACTION, + UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE + }); + //@formatter:on } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsVaV1Field.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsVaV1Field.java index 6125d171..e926b916 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsVaV1Field.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UsVaV1Field.java @@ -1,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UsVaV1Field { public static String VERSION = "Version"; @@ -14,4 +17,19 @@ public class UsVaV1Field { public static String MSPA_OPT_OUT_OPTION_MODE = "MspaOptOutOptionMode"; public static String MSPA_SERVICE_PROVIDER_MODE = "MspaServiceProviderMode"; + //@formatter:off + public static List USVAV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + UsVaV1Field.VERSION, + UsVaV1Field.SHARING_NOTICE, + UsVaV1Field.SALE_OPT_OUT_NOTICE, + UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + UsVaV1Field.SALE_OPT_OUT, + UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, + UsVaV1Field.SENSITIVE_DATA_PROCESSING, + UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + UsVaV1Field.MSPA_COVERED_TRANSACTION, + UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, + UsVaV1Field.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 c5346823..2551632c 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,5 +1,8 @@ package com.iab.gpp.encoder.field; +import java.util.Arrays; +import java.util.List; + public class UspV1Field { public static String VERSION = "Version"; @@ -7,4 +10,12 @@ public class UspV1Field { public static String OPT_OUT_SALE = "OptOutSale"; public static String LSPA_COVERED = "LspaCovered"; + //@formatter:off + public static List USPV1_CORE_SEGMENT_FIELD_NAMES = Arrays.asList(new String[] { + 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/field/UspV1LegacyField.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1LegacyField.java deleted file mode 100644 index 3b1642c1..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/field/UspV1LegacyField.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.iab.gpp.encoder.field; - -public class UspV1LegacyField { - - public static String VERSION = "Version"; - public static String NOTICE = "Notice"; - public static String OPT_OUT_SALE = "OptOutSale"; - public static String LSPA_COVERED = "LspaCovered"; - -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java deleted file mode 100644 index 5b8f0b7c..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.iab.gpp.encoder.section; - -import java.util.Map; -import com.iab.gpp.encoder.datatype.AbstractEncodableBitStringDataType; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; - -public abstract class AbstractEncodableBitStringSection implements EncodableSection { - protected Map> fields; - protected String[] fieldOrder; - - @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[] getFieldOrder() { - return this.fieldOrder; - } - - public String encodeToBitString() throws EncodingException { - String bitString = ""; - for (int i = 0; i < this.fieldOrder.length; i++) { - String fieldName = this.fieldOrder[i]; - if (this.fields.containsKey(fieldName)) { - AbstractEncodableBitStringDataType field = this.fields.get(fieldName); - bitString += field.encode(); - } else { - throw new EncodingException("Field not found: '" + fieldName + "'"); - } - } - - return bitString; - } - - public void decodeFromBitString(String bitString) throws DecodingException { - int index = 0; - for (int i = 0; i < this.fieldOrder.length; i++) { - String fieldName = this.fieldOrder[i]; - if (this.fields.containsKey(fieldName)) { - AbstractEncodableBitStringDataType field = this.fields.get(fieldName); - String substring = field.substring(bitString, index); - field.decode(substring); - index += substring.length(); - } 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/AbstractEncodableSegmentedBitStringSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableSegmentedBitStringSection.java deleted file mode 100644 index d9339189..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableSegmentedBitStringSection.java +++ /dev/null @@ -1,100 +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.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++) { - String segmentBitString = segmentBitStrings.get(i); - if (segmentBitString != null && segmentBitString.length() > 0) { - int index = 0; - 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); - String substring = field.substring(segmentBitString, index); - field.decode(substring); - index += substring.length(); - } 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 new file mode 100644 index 00000000..5e97e144 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractLazilyEncodableSection.java @@ -0,0 +1,91 @@ +package com.iab.gpp.encoder.section; + +import java.util.List; +import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.segment.EncodableSegment; + +public abstract class AbstractLazilyEncodableSection implements EncodableSection { + + private List segments; + + private String encodedString = null; + + private boolean dirty = false; + private boolean decoded = true; + + public AbstractLazilyEncodableSection() { + this.segments = initializeSegments(); + } + + protected abstract List initializeSegments(); + + protected abstract String encodeSection(List segments); + + protected abstract List decodeSection(String 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); + } + } + + return false; + } + + public Object getFieldValue(String fieldName) { + if (!this.decoded) { + this.segments = this.decodeSection(this.encodedString); + this.dirty = false; + this.decoded = true; + } + + for(EncodableSegment segment : segments) { + if(segment.hasField(fieldName)) { + return segment.getFieldValue(fieldName); + } + } + + throw new InvalidFieldException("Invalid field: '" + fieldName + "'"); + } + + public void setFieldValue(String fieldName, Object value) { + if (!this.decoded) { + this.segments = this.decodeSection(this.encodedString); + this.dirty = false; + this.decoded = true; + } + + for(EncodableSegment segment : segments) { + if(segment.hasField(fieldName)) { + segment.setFieldValue(fieldName, value); + return; + } + } + + throw new InvalidFieldException("Invalid field: '" + fieldName + "'"); + } + + public String encode() { + if (this.encodedString == null || this.encodedString.isEmpty() || this.dirty) { + this.encodedString = this.encodeSection(this.segments); + this.dirty = false; + this.decoded = true; + } + + return this.encodedString; + } + + public void decode(String encodedString) { + this.encodedString = encodedString; + this.dirty = false; + this.decoded = false; + } + +} 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 a547e6d3..e1f0a854 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 @@ -1,22 +1,20 @@ package com.iab.gpp.encoder.section; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; - public interface EncodableSection { int getId(); String getName(); + int getVersion(); + boolean hasField(String fieldName); Object getFieldValue(String fieldName); - void setFieldValue(String fieldName, Object value) throws InvalidFieldException; + void setFieldValue(String fieldName, Object value); - String encode() throws EncodingException; + String encode(); - void decode(String encodedString) throws DecodingException; + void decode(String 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 59ec9483..fd5d991c 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,79 +1,79 @@ package com.iab.gpp.encoder.section; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import com.iab.gpp.encoder.datatype.EncodableFibonacciIntegerRange; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; 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 AbstractEncodableBitStringSection { +public class HeaderV1 extends AbstractLazilyEncodableSection { + public static int ID = 3; public static int VERSION = 1; public static String NAME = "header"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public HeaderV1() { - initFields(); + super(); } - public HeaderV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + public HeaderV1(String encodedString) { + super(); + decode(encodedString); } - private void initFields() { - fields = new HashMap<>(); - fields.put(HeaderV1Field.ID, new EncodableFixedInteger(6, HeaderV1.ID)); - fields.put(HeaderV1Field.VERSION, new EncodableFixedInteger(6, HeaderV1.VERSION)); - fields.put(HeaderV1Field.SECTION_IDS, new EncodableFibonacciIntegerRange(new ArrayList<>())); - - //@formatter:off - fieldOrder = new String[] { - HeaderV1Field.ID, - HeaderV1Field.VERSION, - HeaderV1Field.SECTION_IDS - }; - //@formatter:on + @Override + public int getId() { + return HeaderV1.ID; } @Override - public String encode() throws EncodingException { - String bitString = this.encodeToBitString(); - String encodedString = base64UrlEncoder.encode(bitString); - return encodedString; + public String getName() { + return HeaderV1.NAME; } @Override - public void decode(String encodedString) throws DecodingException { - String bitString = base64UrlEncoder.decode(encodedString); - this.decodeFromBitString(bitString); + public int getVersion() { + return HeaderV1.VERSION; } @Override - public int getId() { - return HeaderV1.ID; + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new HeaderV1CoreSegment()); + return segments; } - + @Override - public String getName() { - return HeaderV1.NAME; + 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]); + } + } + } + + return segments; } - public Integer getVersion() { - return (Integer) this.fields.get(HeaderV1Field.VERSION).getValue(); + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + for(EncodableSegment segment : segments) { + encodedSegments.add(segment.encode()); + } + return String.join(".", encodedSegments); } + @SuppressWarnings("unchecked") public List getSectionsIds() { - return (List) this.fields.get(HeaderV1Field.SECTION_IDS).getValue(); + return (List) this.getFieldValue(HeaderV1Field.SECTION_IDS); } + + } 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 ec3b4891..684aaee5 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 @@ -3,174 +3,92 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.function.IntSupplier; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableDatetime; -import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedString; -import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; -import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.TcfCaV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.TcfCaV1CoreSegment; +import com.iab.gpp.encoder.segment.TcfCaV1PublisherPurposesSegment; -public class TcfCaV1 extends AbstractEncodableSegmentedBitStringSection { +public class TcfCaV1 extends AbstractLazilyEncodableSection { + public static int ID = 5; public static int VERSION = 1; public static String NAME = "tcfcav1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public TcfCaV1() { - initFields(); + super(); } - public TcfCaV1(String encodedString) throws DecodingException { - initFields(); + public TcfCaV1(String encodedString) { + super(); + decode(encodedString); + } - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + @Override + public int getId() { + return TcfCaV1.ID; } - private void initFields() { - fields = new HashMap<>(); - - ZonedDateTime date = ZonedDateTime.now(); - - // core section - fields.put(TcfCaV1Field.VERSION, new EncodableFixedInteger(6, TcfCaV1.VERSION)); - fields.put(TcfCaV1Field.CREATED, new EncodableDatetime(date)); - fields.put(TcfCaV1Field.LAST_UPDATED, new EncodableDatetime(date)); - fields.put(TcfCaV1Field.CMP_ID, new EncodableFixedInteger(12, 0)); - fields.put(TcfCaV1Field.CMP_VERSION, new EncodableFixedInteger(12, 0)); - fields.put(TcfCaV1Field.CONSENT_SCREEN, new EncodableFixedInteger(6, 0)); - fields.put(TcfCaV1Field.CONSENT_LANGUAGE, new EncodableFixedString(2, "EN")); - fields.put(TcfCaV1Field.VENDOR_LIST_VERSION, new EncodableFixedInteger(12, 0)); - fields.put(TcfCaV1Field.TCF_POLICY_VERSION, new EncodableFixedInteger(6, 2)); - fields.put(TcfCaV1Field.USE_NON_STANDARD_STACKS, new EncodableBoolean(false)); - fields.put(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT, new EncodableFixedBitfield( - Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfCaV1Field.VENDOR_EXPRESS_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); - fields.put(TcfCaV1Field.VENDOR_IMPLIED_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); - - // publisher purposes segment - fields.put(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); - fields.put(TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - - EncodableFixedInteger numCustomPurposes = new EncodableFixedInteger(6, 0); - fields.put(TcfCaV1Field.NUM_CUSTOM_PURPOSES, numCustomPurposes); - - IntSupplier getLengthSupplier = new IntSupplier() { - - @Override - public int getAsInt() { - return numCustomPurposes.getValue(); - } + @Override + public String getName() { + return TcfCaV1.NAME; + } - }; - - fields.put(TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT, - new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); - - fields.put(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT, - new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); - - //@formatter:off - String[] coreSegment = new String[] { - TcfCaV1Field.VERSION, - TcfCaV1Field.CREATED, - TcfCaV1Field.LAST_UPDATED, - TcfCaV1Field.CMP_ID, - TcfCaV1Field.CMP_VERSION, - TcfCaV1Field.CONSENT_SCREEN, - TcfCaV1Field.CONSENT_LANGUAGE, - TcfCaV1Field.VENDOR_LIST_VERSION, - TcfCaV1Field.TCF_POLICY_VERSION, - TcfCaV1Field.USE_NON_STANDARD_STACKS, - TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT, - TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, - TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, - TcfCaV1Field.VENDOR_EXPRESS_CONSENT, - TcfCaV1Field.VENDOR_IMPLIED_CONSENT - }; - - String[] publisherPurposesSegment = new String[] { - 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, - }; - - segments = new String[][] { - coreSegment, - publisherPurposesSegment - }; - //@formatter:on + @Override + public int getVersion() { + return TcfCaV1.VERSION; } @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - if (segmentBitStrings.size() >= 2) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new TcfCaV1CoreSegment()); + segments.add(new TcfCaV1PublisherPurposesSegment()); + return segments; + } + + @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++) { + + /** + * The first 3 bits contain the segment id. Rather than decode the entire string, just check the first character. + * + * A-H = '000' = 0 + * 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 + * for the encoding version which only coincidentally works here because the version value is less than 8. + */ + + String encodedSegment = encodedSegments[i]; + if(!encodedSegment.isEmpty()) { + char firstChar = encodedSegment.charAt(0); + + if(firstChar >= 'A' && firstChar <= 'H') { + segments.get(0).decode(encodedSegments[i]); + } else if((firstChar >= 'Y' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'f')) { + segments.get(1).decode(encodedSegments[i]); + } + } } } - - return encodedSegments.stream().collect(Collectors.joining(".")); + + return segments; } @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[4]; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 3. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 3 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 3)) { - // unfortunately, the segment ordering doesn't match the segment ids - case "000": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "011": { - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } + public String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + for(EncodableSegment segment : segments) { + encodedSegments.add(segment.encode()); } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); + return String.join(".", encodedSegments); } @Override @@ -185,107 +103,93 @@ public void setFieldValue(String fieldName, Object value) throws InvalidFieldExc } } - @Override - public int getId() { - return TcfCaV1.ID; - } - - @Override - public String getName() { - return TcfCaV1.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(TcfCaV1Field.VERSION).getValue(); - } - + public ZonedDateTime getCreated() { - return (ZonedDateTime) this.fields.get(TcfCaV1Field.CREATED).getValue(); + return (ZonedDateTime) this.getFieldValue(TcfCaV1Field.CREATED); } public ZonedDateTime getLastUpdated() { - return (ZonedDateTime) this.fields.get(TcfCaV1Field.LAST_UPDATED).getValue(); + return (ZonedDateTime) this.getFieldValue(TcfCaV1Field.LAST_UPDATED); } public Integer getCmpId() { - return (Integer) this.fields.get(TcfCaV1Field.CMP_ID).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.CMP_ID); } public Integer getCmpVersion() { - return (Integer) this.fields.get(TcfCaV1Field.CMP_VERSION).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.CMP_VERSION); } public Integer getConsentScreen() { - return (Integer) this.fields.get(TcfCaV1Field.CONSENT_SCREEN).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.CONSENT_SCREEN); } public String getConsentLanguage() { - return (String) this.fields.get(TcfCaV1Field.CONSENT_LANGUAGE).getValue(); + return (String) this.getFieldValue(TcfCaV1Field.CONSENT_LANGUAGE); } public Integer getVendorListVersion() { - return (Integer) this.fields.get(TcfCaV1Field.VENDOR_LIST_VERSION).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.VENDOR_LIST_VERSION); } public Integer getPolicyVersion() { - return (Integer) this.fields.get(TcfCaV1Field.TCF_POLICY_VERSION).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.TCF_POLICY_VERSION); } public Boolean getUseNonStandardStacks() { - return (Boolean) this.fields.get(TcfCaV1Field.USE_NON_STANDARD_STACKS).getValue(); + return (Boolean) this.getFieldValue(TcfCaV1Field.USE_NON_STANDARD_STACKS); } @SuppressWarnings("unchecked") public List getSpecialFeatureExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT); } @SuppressWarnings("unchecked") public List getPurposesExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.PURPOSES_EXPRESS_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.PURPOSES_EXPRESS_CONSENT); } @SuppressWarnings("unchecked") public List getPurposesImpliedConsent() { - return (List) this.fields.get(TcfCaV1Field.PURPOSES_IMPLIED_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.PURPOSES_IMPLIED_CONSENT); } @SuppressWarnings("unchecked") public List getVendorExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.VENDOR_EXPRESS_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.VENDOR_EXPRESS_CONSENT); } @SuppressWarnings("unchecked") public List getVendorImpliedConsent() { - return (List) this.fields.get(TcfCaV1Field.VENDOR_IMPLIED_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.VENDOR_IMPLIED_CONSENT); } public Integer getPubPurposesSegmentType() { - return (Integer) this.fields.get(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE); } @SuppressWarnings("unchecked") public List getPubPurposesExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT); } @SuppressWarnings("unchecked") public List getPubPurposesImpliedConsent() { - return (List) this.fields.get(TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT); } public Integer getNumCustomPurposes() { - return (Integer) this.fields.get(TcfCaV1Field.NUM_CUSTOM_PURPOSES).getValue(); + return (Integer) this.getFieldValue(TcfCaV1Field.NUM_CUSTOM_PURPOSES); } @SuppressWarnings("unchecked") public List getCustomPurposesExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT); } @SuppressWarnings("unchecked") public List getCustomPurposesImpliedConsent() { - return (List) this.fields.get(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT).getValue(); + return (List) this.getFieldValue(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT); } - } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java index 625121bd..b9b643eb 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java @@ -3,222 +3,119 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.function.IntSupplier; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableDatetime; -import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerRange; -import com.iab.gpp.encoder.datatype.EncodableFixedString; -import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; -import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.TraditionalBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.TcfEuV2Field; - -public class TcfEuV2 extends AbstractEncodableSegmentedBitStringSection { +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.TcfEuV2CoreSegment; +import com.iab.gpp.encoder.segment.TcfEuV2PublisherPurposesSegment; +import com.iab.gpp.encoder.segment.TcfEuV2VendorsAllowedSegment; +import com.iab.gpp.encoder.segment.TcfEuV2VendorsDisclosedSegment; + +public class TcfEuV2 extends AbstractLazilyEncodableSection { + public static int ID = 2; public static int VERSION = 2; public static String NAME = "tcfeuv2"; - private AbstractBase64UrlEncoder base64UrlEncoder = new TraditionalBase64UrlEncoder(); - public TcfEuV2() { - initFields(); + super(); } - public TcfEuV2(String encodedString) throws DecodingException { - initFields(); + public TcfEuV2(String encodedString) { + super(); + decode(encodedString); + } - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + @Override + public int getId() { + return TcfEuV2.ID; } - private void initFields() { - fields = new HashMap<>(); - - ZonedDateTime date = ZonedDateTime.now(); - - // core section - fields.put(TcfEuV2Field.VERSION, new EncodableFixedInteger(6, TcfEuV2.VERSION)); - fields.put(TcfEuV2Field.CREATED, new EncodableDatetime(date)); - fields.put(TcfEuV2Field.LAST_UPDATED, new EncodableDatetime(date)); - fields.put(TcfEuV2Field.CMP_ID, new EncodableFixedInteger(12, 0)); - fields.put(TcfEuV2Field.CMP_VERSION, new EncodableFixedInteger(12, 0)); - fields.put(TcfEuV2Field.CONSENT_SCREEN, new EncodableFixedInteger(6, 0)); - fields.put(TcfEuV2Field.CONSENT_LANGUAGE, new EncodableFixedString(2, "EN")); - fields.put(TcfEuV2Field.VENDOR_LIST_VERSION, new EncodableFixedInteger(12, 0)); - fields.put(TcfEuV2Field.POLICY_VERSION, new EncodableFixedInteger(6, 2)); - fields.put(TcfEuV2Field.IS_SERVICE_SPECIFIC, new EncodableBoolean(false)); - fields.put(TcfEuV2Field.USE_NON_STANDARD_STACKS, new EncodableBoolean(false)); - fields.put(TcfEuV2Field.SPECIAL_FEATURE_OPTINS, new EncodableFixedBitfield( - Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfEuV2Field.PURPOSE_CONSENTS, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfEuV2Field.PURPOSE_ONE_TREATMENT, new EncodableBoolean(false)); - fields.put(TcfEuV2Field.PUBLISHER_COUNTRY_CODE, new EncodableFixedString(2, "AA")); - fields.put(TcfEuV2Field.VENDOR_CONSENTS, new EncodableOptimizedFixedRange(new ArrayList<>())); - fields.put(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, new EncodableOptimizedFixedRange(new ArrayList<>())); - - fields.put(TcfEuV2Field.PUBLISHER_RESTRICTIONS, new EncodableFixedIntegerRange(new ArrayList<>())); - - // publisher purposes segment - fields.put(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); - fields.put(TcfEuV2Field.PUBLISHER_CONSENTS, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - - EncodableFixedInteger numCustomPurposes = new EncodableFixedInteger(6, 0); - fields.put(TcfEuV2Field.NUM_CUSTOM_PURPOSES, numCustomPurposes); - - IntSupplier getLengthSupplier = new IntSupplier() { - - @Override - public int getAsInt() { - return numCustomPurposes.getValue(); - } + @Override + public String getName() { + return TcfEuV2.NAME; + } - }; - - fields.put(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS, - new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); - - fields.put(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS, - new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); - - fields.put(TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE, new EncodableFixedInteger(3, 2)); - fields.put(TcfEuV2Field.VENDORS_ALLOWED, new EncodableOptimizedFixedRange(new ArrayList<>())); - - fields.put(TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE, new EncodableFixedInteger(3, 1)); - fields.put(TcfEuV2Field.VENDORS_DISCLOSED, new EncodableOptimizedFixedRange(new ArrayList<>())); - - //@formatter:off - String[] coreSegment = new String[] { - TcfEuV2Field.VERSION, - TcfEuV2Field.CREATED, - TcfEuV2Field.LAST_UPDATED, - TcfEuV2Field.CMP_ID, - TcfEuV2Field.CMP_VERSION, - TcfEuV2Field.CONSENT_SCREEN, - TcfEuV2Field.CONSENT_LANGUAGE, - TcfEuV2Field.VENDOR_LIST_VERSION, - TcfEuV2Field.POLICY_VERSION, - TcfEuV2Field.IS_SERVICE_SPECIFIC, - TcfEuV2Field.USE_NON_STANDARD_STACKS, - TcfEuV2Field.SPECIAL_FEATURE_OPTINS, - TcfEuV2Field.PURPOSE_CONSENTS, - TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS, - TcfEuV2Field.PURPOSE_ONE_TREATMENT, - TcfEuV2Field.PUBLISHER_COUNTRY_CODE, - TcfEuV2Field.VENDOR_CONSENTS, - TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, - TcfEuV2Field.PUBLISHER_RESTRICTIONS - }; - - String[] publisherPurposesSegment = new String[] { - 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, - }; - - String[] vendorsAllowedSegment = new String[] { - TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE, - TcfEuV2Field.VENDORS_ALLOWED, - }; - - String[] vendorsDisclosedSegment = new String[] { - TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE, - TcfEuV2Field.VENDORS_DISCLOSED, - }; - - segments = new String[][] { - coreSegment, - publisherPurposesSegment, - vendorsAllowedSegment, - vendorsDisclosedSegment - }; - //@formatter:on + @Override + public int getVersion() { + return TcfEuV2.VERSION; } @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new TcfEuV2CoreSegment()); + segments.add(new TcfEuV2PublisherPurposesSegment()); + segments.add(new TcfEuV2VendorsAllowedSegment()); + segments.add(new TcfEuV2VendorsDisclosedSegment()); + return segments; + } + + @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++) { + + /** + * 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 + * Q-X = '010' = 2 + * 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 + * for the encoding version which only coincidentally works here because the version value is less than 8. + */ + + String encodedSegment = encodedSegments[i]; + if(!encodedSegment.isEmpty()) { + char firstChar = encodedSegment.charAt(0); + + // unfortunately, the segment ordering doesn't match the segment ids + if(firstChar >= 'A' && firstChar <= 'H') { + segments.get(0).decode(encodedSegments[i]); + } else if(firstChar >= 'I' && firstChar <= 'P') { + segments.get(3).decode(encodedSegments[i]); + } else if(firstChar >= 'Q' && firstChar <= 'X') { + segments.get(2).decode(encodedSegments[i]); + } else if((firstChar >= 'Y' && firstChar <= 'Z') || (firstChar >= 'a' && firstChar <= 'f')) { + segments.get(1).decode(encodedSegments[i]); + } + } + } + } + + return segments; + } + + @Override + public String encodeSection(List segments) { List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); + if (segments.size() >= 1) { + encodedSegments.add(segments.get(0).encode()); Boolean isServiceSpecific = (Boolean) this.getFieldValue(TcfEuV2Field.IS_SERVICE_SPECIFIC); if (isServiceSpecific) { - if (segmentBitStrings.size() >= 2) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); + if (segments.size() >= 2) { + encodedSegments.add(segments.get(1).encode()); } } else { - if (segmentBitStrings.size() >= 2) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(2))); + if (segments.size() >= 2) { + encodedSegments.add(segments.get(2).encode()); - if (segmentBitStrings.size() >= 3) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(3))); + if (segments.size() >= 3) { + encodedSegments.add(segments.get(3).encode()); } } } } - return encodedSegments.stream().collect(Collectors.joining(".")); - } - - @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[4]; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 3. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 3 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 3)) { - // unfortunately, the segment ordering doesn't match the segment ids - case "000": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "001": { - segmentBitStrings[3] = segmentBitString; - break; - } - case "010": { - segmentBitStrings[2] = segmentBitString; - break; - } - case "011": { - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } - } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); + return String.join(".", encodedSegments); } @Override @@ -233,144 +130,130 @@ public void setFieldValue(String fieldName, Object value) throws InvalidFieldExc } } - @Override - public int getId() { - return TcfEuV2.ID; - } - - @Override - public String getName() { - return TcfEuV2.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(TcfEuV2Field.VERSION).getValue(); - } - + public ZonedDateTime getCreated() { - return (ZonedDateTime) this.fields.get(TcfEuV2Field.CREATED).getValue(); + return (ZonedDateTime) this.getFieldValue(TcfEuV2Field.CREATED); } public ZonedDateTime getLastUpdated() { - return (ZonedDateTime) this.fields.get(TcfEuV2Field.LAST_UPDATED).getValue(); + return (ZonedDateTime) this.getFieldValue(TcfEuV2Field.LAST_UPDATED); } public Integer getCmpId() { - return (Integer) this.fields.get(TcfEuV2Field.CMP_ID).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.CMP_ID); } public Integer getCmpVersion() { - return (Integer) this.fields.get(TcfEuV2Field.CMP_VERSION).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.CMP_VERSION); } public Integer getConsentScreen() { - return (Integer) this.fields.get(TcfEuV2Field.CONSENT_SCREEN).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.CONSENT_SCREEN); } public String getConsentLanguage() { - return (String) this.fields.get(TcfEuV2Field.CONSENT_LANGUAGE).getValue(); + return (String) this.getFieldValue(TcfEuV2Field.CONSENT_LANGUAGE); } public Integer getVendorListVersion() { - return (Integer) this.fields.get(TcfEuV2Field.VENDOR_LIST_VERSION).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.VENDOR_LIST_VERSION); } public Integer getPolicyVersion() { - return (Integer) this.fields.get(TcfEuV2Field.POLICY_VERSION).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.POLICY_VERSION); } public Boolean getIsServiceSpecific() { - return (Boolean) this.fields.get(TcfEuV2Field.IS_SERVICE_SPECIFIC).getValue(); + return (Boolean) this.getFieldValue(TcfEuV2Field.IS_SERVICE_SPECIFIC); } public Boolean getUseNonStandardStacks() { - return (Boolean) this.fields.get(TcfEuV2Field.USE_NON_STANDARD_STACKS).getValue(); + return (Boolean) this.getFieldValue(TcfEuV2Field.USE_NON_STANDARD_STACKS); } @SuppressWarnings("unchecked") public List getSpecialFeatureOptins() { - return (List) this.fields.get(TcfEuV2Field.SPECIAL_FEATURE_OPTINS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.SPECIAL_FEATURE_OPTINS); } @SuppressWarnings("unchecked") public List getPurposeConsents() { - return (List) this.fields.get(TcfEuV2Field.PURPOSE_CONSENTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PURPOSE_CONSENTS); } @SuppressWarnings("unchecked") public List getPurposeLegitimateInterests() { - return (List) this.fields.get(TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS); } public Boolean getPurposeOneTreatment() { - return (Boolean) this.fields.get(TcfEuV2Field.PURPOSE_ONE_TREATMENT).getValue(); + return (Boolean) this.getFieldValue(TcfEuV2Field.PURPOSE_ONE_TREATMENT); } public String getPublisherCountryCode() { - return (String) this.fields.get(TcfEuV2Field.PUBLISHER_COUNTRY_CODE).getValue(); + return (String) this.getFieldValue(TcfEuV2Field.PUBLISHER_COUNTRY_CODE); } @SuppressWarnings("unchecked") public List getVendorConsents() { - return (List) this.fields.get(TcfEuV2Field.VENDOR_CONSENTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.VENDOR_CONSENTS); } @SuppressWarnings("unchecked") public List getVendorLegitimateInterests() { - return (List) this.fields.get(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS); } @SuppressWarnings("unchecked") public List getPublisherRestrictions() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_RESTRICTIONS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PUBLISHER_RESTRICTIONS); } public Integer getPublisherPurposesSegmentType() { - return (Integer) this.fields.get(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE); } @SuppressWarnings("unchecked") public List getPublisherConsents() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_CONSENTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PUBLISHER_CONSENTS); } @SuppressWarnings("unchecked") public List getPublisherLegitimateInterests() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS); } public Integer getNumCustomPurposes() { - return (Integer) this.fields.get(TcfEuV2Field.NUM_CUSTOM_PURPOSES).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.NUM_CUSTOM_PURPOSES); } @SuppressWarnings("unchecked") public List getPublisherCustomConsents() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS); } @SuppressWarnings("unchecked") public List getPublisherCustomLegitimateInterests() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS); } public Integer getVendorsAllowedSegmentType() { - return (Integer) this.fields.get(TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE); } @SuppressWarnings("unchecked") public List getVendorsAllowed() { - return (List) this.fields.get(TcfEuV2Field.VENDORS_ALLOWED).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.VENDORS_ALLOWED); } public Integer getVendorsDisclosedSegmentType() { - return (Integer) this.fields.get(TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE); } @SuppressWarnings("unchecked") public List getVendorsDisclosed() { - return (List) this.fields.get(TcfEuV2Field.VENDORS_DISCLOSED).getValue(); + return (List) this.getFieldValue(TcfEuV2Field.VENDORS_DISCLOSED); } - - - + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCaV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCaV1.java index de88746f..03442533 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCaV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCaV1.java @@ -1,208 +1,142 @@ package com.iab.gpp.encoder.section; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.field.UsCaV1Field; -import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UsCaV1CoreSegment; +import com.iab.gpp.encoder.segment.UsCaV1GpcSegment; -public class UsCaV1 extends AbstractEncodableSegmentedBitStringSection { +public class UsCaV1 extends AbstractLazilyEncodableSection { + public static int ID = 8; public static int VERSION = 1; public static String NAME = "uscav1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public UsCaV1() { - initFields(); + super(); } - public UsCaV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + public UsCaV1(String encodedString) { + super(); + decode(encodedString); } - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsCaV1Field.VERSION, new EncodableFixedInteger(6, UsCaV1.VERSION)); - fields.put(UsCaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0))); - fields.put(UsCaV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - // gpc segment - fields.put(UsCaV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsCaV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsCaV1Field.GPC, new EncodableBoolean(false)); - - //@formatter:off - String[] coreSegment = new String[] { - UsCaV1Field.VERSION, - UsCaV1Field.SALE_OPT_OUT_NOTICE, - UsCaV1Field.SHARING_OPT_OUT_NOTICE, - UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, - UsCaV1Field.SALE_OPT_OUT, - UsCaV1Field.SHARING_OPT_OUT, - UsCaV1Field.SENSITIVE_DATA_PROCESSING, - UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsCaV1Field.PERSONAL_DATA_CONSENTS, - UsCaV1Field.MSPA_COVERED_TRANSACTION, - UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - - String[] gpcSegment = new String[] { - UsCaV1Field.GPC_SEGMENT_TYPE, - UsCaV1Field.GPC - }; - - segments = new String[][] { - coreSegment, - gpcSegment - }; - //@formatter:on + @Override + public int getId() { + return UsCaV1.ID; } @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - if (segmentBitStrings.size() >= 2) { - Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).getValue(); - if (gpcSegmentIncluded) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - - } - } - - return encodedSegments.stream().collect(Collectors.joining(".")); + public String getName() { + return UsCaV1.NAME; } @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[2]; - boolean gpcSegmentIncluded = false; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 2)) { - case "00": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "01": { - gpcSegmentIncluded = true; - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } - } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); + public int getVersion() { + return UsCaV1.VERSION; } @Override - public int getId() { - return UsCaV1.ID; + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsCaV1CoreSegment()); + segments.add(new UsCaV1GpcSegment()); + return segments; } - + @Override - public String getName() { - return UsCaV1.NAME; + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if(encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if(encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED, false); + } + } + + return segments; } - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if(!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if(segments.size() >= 2 && segments.get(1).getFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); } + public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsCaV1Field.SALE_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE); } public Integer getSensitiveDataLimitUseNotice() { - return (Integer) this.fields.get(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE); } public Integer getSharingOptOutNotice() { - return (Integer) this.fields.get(UsCaV1Field.SHARING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE); } public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsCaV1Field.SALE_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.SALE_OPT_OUT); } public Integer getSharingOptOut() { - return (Integer) this.fields.get(UsCaV1Field.SHARING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.SHARING_OPT_OUT); } @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsCaV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + return (List) this.getFieldValue(UsCaV1Field.SENSITIVE_DATA_PROCESSING); } @SuppressWarnings("unchecked") public List getKnownChildSensitiveDataConsents() { - return (List) this.fields.get(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + return (List) this.getFieldValue(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); } public Integer getPersonalDataConsents() { - return (Integer) this.fields.get(UsCaV1Field.PERSONAL_DATA_CONSENTS).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.PERSONAL_DATA_CONSENTS); } public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsCaV1Field.MSPA_COVERED_TRANSACTION).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.MSPA_COVERED_TRANSACTION); } public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE); } public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE); } public Integer getGpcSegmentType() { - return (Integer) this.fields.get(UsCaV1Field.GPC_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(UsCaV1Field.GPC_SEGMENT_TYPE); } public Boolean getGpcSegmentIncluded() { - return (Boolean) this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).getValue(); + return (Boolean) this.getFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED); } public Boolean getGpc() { - return (Boolean) this.fields.get(UsCaV1Field.GPC).getValue(); + return (Boolean) this.getFieldValue(UsCaV1Field.GPC); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCoV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCoV1.java index 05b2f9d6..22bd56a6 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCoV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCoV1.java @@ -1,202 +1,137 @@ package com.iab.gpp.encoder.section; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UsCaV1Field; import com.iab.gpp.encoder.field.UsCoV1Field; -import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UsCoV1CoreSegment; +import com.iab.gpp.encoder.segment.UsCoV1GpcSegment; -public class UsCoV1 extends AbstractEncodableSegmentedBitStringSection { +public class UsCoV1 extends AbstractLazilyEncodableSection { + public static int ID = 10; public static int VERSION = 1; public static String NAME = "uscov1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public UsCoV1() { - initFields(); + super(); } - public UsCoV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + public UsCoV1(String encodedString) { + super(); + decode(encodedString); } - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsCoV1Field.VERSION, new EncodableFixedInteger(6, UsCoV1.VERSION)); - fields.put(UsCoV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0))); - fields.put(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - // gpc segment - fields.put(UsCoV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsCoV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsCoV1Field.GPC, new EncodableBoolean(false)); - - - //@formatter:off - String[] coreSegment = new String[] { - UsCoV1Field.VERSION, - UsCoV1Field.SHARING_NOTICE, - UsCoV1Field.SALE_OPT_OUT_NOTICE, - UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsCoV1Field.SALE_OPT_OUT, - UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsCoV1Field.SENSITIVE_DATA_PROCESSING, - UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsCoV1Field.MSPA_COVERED_TRANSACTION, - UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - - String[] gpcSegment = new String[] { - UsCoV1Field.GPC_SEGMENT_TYPE, - UsCoV1Field.GPC - }; - - segments = new String[][] { - coreSegment, - gpcSegment - }; - //@formatter:on + @Override + public int getId() { + return UsCoV1.ID; } @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - if (segmentBitStrings.size() >= 2) { - Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsCoV1Field.GPC_SEGMENT_INCLUDED).getValue(); - if (gpcSegmentIncluded) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - } - } - - return encodedSegments.stream().collect(Collectors.joining(".")); + public String getName() { + return UsCoV1.NAME; } @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[2]; - boolean gpcSegmentIncluded = false; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 2)) { - case "00": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "01": { - gpcSegmentIncluded = true; - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } - } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); + public int getVersion() { + return UsCoV1.VERSION; } @Override - public int getId() { - return UsCoV1.ID; + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsCoV1CoreSegment()); + segments.add(new UsCoV1GpcSegment()); + return segments; } - + @Override - public String getName() { - return UsCoV1.NAME; + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if(encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if(encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsCoV1Field.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsCoV1Field.GPC_SEGMENT_INCLUDED, false); + } + } + + return segments; } - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if(!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if(segments.size() >= 2 && segments.get(1).getFieldValue(UsCoV1Field.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); } + public Integer getSharingNotice() { - return (Integer) this.fields.get(UsCoV1Field.SHARING_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.SHARING_NOTICE); } public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsCoV1Field.SALE_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE); } public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE); } public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsCoV1Field.SALE_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.SALE_OPT_OUT); } public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT); } @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsCoV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + return (List) this.getFieldValue(UsCoV1Field.SENSITIVE_DATA_PROCESSING); } public Integer getKnownChildSensitiveDataConsents() { - return (Integer) this.fields.get(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); } public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsCoV1Field.MSPA_COVERED_TRANSACTION).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.MSPA_COVERED_TRANSACTION); } public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE); } public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE); } public Integer getGpcSegmentType() { - return (Integer) this.fields.get(UsCoV1Field.GPC_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(UsCoV1Field.GPC_SEGMENT_TYPE); } public Boolean getGpcSegmentIncluded() { - return (Boolean) this.fields.get(UsCoV1Field.GPC_SEGMENT_INCLUDED).getValue(); + return (Boolean) this.getFieldValue(UsCoV1Field.GPC_SEGMENT_INCLUDED); } public Boolean getGpc() { - return (Boolean) this.fields.get(UsCoV1Field.GPC).getValue(); + return (Boolean) this.getFieldValue(UsCoV1Field.GPC); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCtV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCtV1.java index 9df3e780..2acd3f2f 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCtV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsCtV1.java @@ -1,203 +1,138 @@ package com.iab.gpp.encoder.section; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UsCaV1Field; import com.iab.gpp.encoder.field.UsCtV1Field; -import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UsCtV1CoreSegment; +import com.iab.gpp.encoder.segment.UsCtV1GpcSegment; + +public class UsCtV1 extends AbstractLazilyEncodableSection { -public class UsCtV1 extends AbstractEncodableSegmentedBitStringSection { public static int ID = 12; public static int VERSION = 1; public static String NAME = "usctv1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public UsCtV1() { - initFields(); + super(); } - public UsCtV1(String encodedString) throws DecodingException { - initFields(); + public UsCtV1(String encodedString) { + super(); + decode(encodedString); + } - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + @Override + public int getId() { + return UsCtV1.ID; } - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsCtV1Field.VERSION, new EncodableFixedInteger(6, UsCtV1.VERSION)); - fields.put(UsCtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0))); - fields.put(UsCtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - // gpc segment - fields.put(UsCtV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsCtV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsCtV1Field.GPC, new EncodableBoolean(false)); - - //@formatter:off - String[] coreSegment = new String[] { - UsCtV1Field.VERSION, - UsCtV1Field.SHARING_NOTICE, - UsCtV1Field.SALE_OPT_OUT_NOTICE, - UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsCtV1Field.SALE_OPT_OUT, - UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsCtV1Field.SENSITIVE_DATA_PROCESSING, - UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsCtV1Field.MSPA_COVERED_TRANSACTION, - UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - - String[] gpcSegment = new String[] { - UsCtV1Field.GPC_SEGMENT_TYPE, - UsCtV1Field.GPC - }; - - segments = new String[][] { - coreSegment, - gpcSegment - }; - //@formatter:on + @Override + public String getName() { + return UsCtV1.NAME; } @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - if (segmentBitStrings.size() >= 2) { - Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsCtV1Field.GPC_SEGMENT_INCLUDED).getValue(); - if (gpcSegmentIncluded) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - } - } + public int getVersion() { + return UsCtV1.VERSION; + } - return encodedSegments.stream().collect(Collectors.joining(".")); + @Override + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsCtV1CoreSegment()); + segments.add(new UsCtV1GpcSegment()); + return segments; } @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[2]; - boolean gpcSegmentIncluded = false; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 2)) { - case "00": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "01": { - gpcSegmentIncluded = true; - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if(encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if(encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsCtV1Field.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsCtV1Field.GPC_SEGMENT_INCLUDED, false); } } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); - } - @Override - public int getId() { - return UsCtV1.ID; + return segments; } @Override - public String getName() { - return UsCtV1.NAME; + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if(!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if(segments.size() >= 2 && segments.get(1).getFieldValue(UsCtV1Field.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); } - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); - } public Integer getSharingNotice() { - return (Integer) this.fields.get(UsCtV1Field.SHARING_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.SHARING_NOTICE); } public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsCtV1Field.SALE_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE); } public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE); } public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsCtV1Field.SALE_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.SALE_OPT_OUT); } public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT); } @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsCtV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + return (List) this.getFieldValue(UsCtV1Field.SENSITIVE_DATA_PROCESSING); } @SuppressWarnings("unchecked") public List getKnownChildSensitiveDataConsents() { - return (List) this.fields.get(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + return (List) this.getFieldValue(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); } public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsCtV1Field.MSPA_COVERED_TRANSACTION).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.MSPA_COVERED_TRANSACTION); } public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE); } public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE); } public Integer getGpcSegmentType() { - return (Integer) this.fields.get(UsCtV1Field.GPC_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(UsCtV1Field.GPC_SEGMENT_TYPE); } public Boolean getGpcSegmentIncluded() { - return (Boolean) this.fields.get(UsCtV1Field.GPC_SEGMENT_INCLUDED).getValue(); + return (Boolean) this.getFieldValue(UsCtV1Field.GPC_SEGMENT_INCLUDED); } public Boolean getGpc() { - return (Boolean) this.fields.get(UsCtV1Field.GPC).getValue(); + return (Boolean) this.getFieldValue(UsCtV1Field.GPC); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsNatV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsNatV1.java index 6cd943d9..0f0811cf 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsNatV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsNatV1.java @@ -1,233 +1,158 @@ package com.iab.gpp.encoder.section; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; import java.util.List; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UsCaV1Field; import com.iab.gpp.encoder.field.UsNatV1Field; -import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UsNatV1CoreSegment; +import com.iab.gpp.encoder.segment.UsNatV1GpcSegment; + +public class UsNatV1 extends AbstractLazilyEncodableSection { -public class UsNatV1 extends AbstractEncodableSegmentedBitStringSection { public static int ID = 7; public static int VERSION = 1; public static String NAME = "usnatv1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public UsNatV1() { - initFields(); + super(); } - public UsNatV1(String encodedString) throws DecodingException { - initFields(); + public UsNatV1(String encodedString) { + super(); + decode(encodedString); + } - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + @Override + public int getId() { + return UsNatV1.ID; } - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsNatV1Field.VERSION, new EncodableFixedInteger(6, UsNatV1.VERSION)); - fields.put(UsNatV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0))); - fields.put(UsNatV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - // gpc segment - fields.put(UsNatV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsNatV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsNatV1Field.GPC, new EncodableBoolean(false)); - - - //@formatter:off - String[] coreSegment = new String[] { - UsNatV1Field.VERSION, - UsNatV1Field.SHARING_NOTICE, - UsNatV1Field.SALE_OPT_OUT_NOTICE, - UsNatV1Field.SHARING_OPT_OUT_NOTICE, - UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, - UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, - UsNatV1Field.SALE_OPT_OUT, - UsNatV1Field.SHARING_OPT_OUT, - UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsNatV1Field.SENSITIVE_DATA_PROCESSING, - UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsNatV1Field.PERSONAL_DATA_CONSENTS, - UsNatV1Field.MSPA_COVERED_TRANSACTION, - UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - - String[] gpcSegment = new String[] { - UsNatV1Field.GPC_SEGMENT_TYPE, - UsNatV1Field.GPC - }; - - segments = new String[][] { - coreSegment, - gpcSegment - }; - //@formatter:on + @Override + public String getName() { + return UsNatV1.NAME; } @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - if (segmentBitStrings.size() >= 2) { - Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsNatV1Field.GPC_SEGMENT_INCLUDED).getValue(); - if (gpcSegmentIncluded) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - } - } + public int getVersion() { + return UsNatV1.VERSION; + } - return encodedSegments.stream().collect(Collectors.joining(".")); + @Override + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsNatV1CoreSegment()); + segments.add(new UsNatV1GpcSegment()); + return segments; } @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[2]; - boolean gpcSegmentIncluded = false; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 2)) { - case "00": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "01": { - gpcSegmentIncluded = true; - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + if(encodedSegments.length > 0) { + segments.get(0).decode(encodedSegments[0]); + } + + if(encodedSegments.length > 1) { + segments.get(1).setFieldValue(UsNatV1Field.GPC_SEGMENT_INCLUDED, true); + segments.get(1).decode(encodedSegments[1]); + } else { + segments.get(1).setFieldValue(UsNatV1Field.GPC_SEGMENT_INCLUDED, false); } } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); - } - @Override - public int getId() { - return UsNatV1.ID; + return segments; } @Override - public String getName() { - return UsNatV1.NAME; + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + + if(!segments.isEmpty()) { + encodedSegments.add(segments.get(0).encode()); + if(segments.size() >= 2 && segments.get(1).getFieldValue(UsNatV1Field.GPC_SEGMENT_INCLUDED).equals(true)) { + encodedSegments.add(segments.get(1).encode()); + } + } + + return String.join(".", encodedSegments); } - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); - } public Integer getSharingNotice() { - return (Integer) this.fields.get(UsNatV1Field.SHARING_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SHARING_NOTICE); } public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsNatV1Field.SALE_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE); } public Integer getSharingOptOutNotice() { - return (Integer) this.fields.get(UsNatV1Field.SHARING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE); } public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE); } public Integer getSensitiveDataProcessingOptOutNotice() { - return (Integer) this.fields.get(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE); } public Integer getSensitiveDataLimitUseNotice() { - return (Integer) this.fields.get(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE); } public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsNatV1Field.SALE_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SALE_OPT_OUT); } public Integer getSharingOptOut() { - return (Integer) this.fields.get(UsNatV1Field.SHARING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.SHARING_OPT_OUT); } public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT); } @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsNatV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + return (List) this.getFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING); } @SuppressWarnings("unchecked") public List getKnownChildSensitiveDataConsents() { - return (List) this.fields.get(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + return (List) this.getFieldValue(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); } public Integer getPersonalDataConsents() { - return (Integer) this.fields.get(UsNatV1Field.PERSONAL_DATA_CONSENTS).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.PERSONAL_DATA_CONSENTS); } public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsNatV1Field.MSPA_COVERED_TRANSACTION).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.MSPA_COVERED_TRANSACTION); } public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE); } public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE); } public Integer getGpcSegmentType() { - return (Integer) this.fields.get(UsNatV1Field.GPC_SEGMENT_TYPE).getValue(); + return (Integer) this.getFieldValue(UsNatV1Field.GPC_SEGMENT_TYPE); } public Boolean getGpcSegmentIncluded() { - return (Boolean) this.fields.get(UsNatV1Field.GPC_SEGMENT_INCLUDED).getValue(); + return (Boolean) this.getFieldValue(UsNatV1Field.GPC_SEGMENT_INCLUDED); } public Boolean getGpc() { - return (Boolean) this.fields.get(UsNatV1Field.GPC).getValue(); + return (Boolean) this.getFieldValue(UsNatV1Field.GPC); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsUtV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsUtV1.java index 9bd56c35..a73a0b6f 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsUtV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsUtV1.java @@ -1,141 +1,119 @@ package com.iab.gpp.encoder.section; -import java.util.Arrays; -import java.util.HashMap; +import java.util.ArrayList; import java.util.List; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.field.UsUtV1Field; -import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UsUtV1CoreSegment; -public class UsUtV1 extends AbstractEncodableBitStringSection { +public class UsUtV1 extends AbstractLazilyEncodableSection { + public static int ID = 11; public static int VERSION = 1; public static String NAME = "usutv1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public UsUtV1() { - initFields(); + super(); } - public UsUtV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + public UsUtV1(String encodedString) { + super(); + decode(encodedString); } - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsUtV1Field.VERSION, new EncodableFixedInteger(6, UsUtV1.VERSION)); - fields.put(UsUtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - //@formatter:off - fieldOrder = new String[] { - UsUtV1Field.VERSION, - UsUtV1Field.SHARING_NOTICE, - UsUtV1Field.SALE_OPT_OUT_NOTICE, - UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, - UsUtV1Field.SALE_OPT_OUT, - UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsUtV1Field.SENSITIVE_DATA_PROCESSING, - UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsUtV1Field.MSPA_COVERED_TRANSACTION, - UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - //@formatter:on + @Override + public int getId() { + return UsUtV1.ID; } @Override - public String encode() throws EncodingException { - String bitString = this.encodeToBitString(); - String encodedString = base64UrlEncoder.encode(bitString); - return encodedString; + public String getName() { + return UsUtV1.NAME; } @Override - public void decode(String encodedString) throws DecodingException { - String bitString = base64UrlEncoder.decode(encodedString); - this.decodeFromBitString(bitString); + public int getVersion() { + return UsUtV1.VERSION; } @Override - public int getId() { - return UsUtV1.ID; + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsUtV1CoreSegment()); + return segments; } - + @Override - public String getName() { - return UsUtV1.NAME; + 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]); + } + } + } + + return segments; } - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + for(EncodableSegment segment : segments) { + encodedSegments.add(segment.encode()); + } + return String.join(".", encodedSegments); } + public Integer getSharingNotice() { - return (Integer) this.fields.get(UsUtV1Field.SHARING_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.SHARING_NOTICE); } public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsUtV1Field.SALE_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE); } public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE); } public Integer getSensitiveDataProcessingOptOutNotice() { - return (Integer) this.fields.get(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE); } public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsUtV1Field.SALE_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.SALE_OPT_OUT); } public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT); } @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsUtV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + return (List) this.getFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING); } public Integer getKnownChildSensitiveDataConsents() { - return (Integer) this.fields.get(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); } public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsUtV1Field.MSPA_COVERED_TRANSACTION).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.MSPA_COVERED_TRANSACTION); } public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE); } public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + return (Integer) this.getFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE); } - + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsVaV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsVaV1.java index fdd48f49..6695b943 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsVaV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UsVaV1.java @@ -1,135 +1,113 @@ package com.iab.gpp.encoder.section; -import java.util.Arrays; -import java.util.HashMap; +import java.util.ArrayList; import java.util.List; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UspV1Field; import com.iab.gpp.encoder.field.UsVaV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UsVaV1CoreSegment; + +public class UsVaV1 extends AbstractLazilyEncodableSection { -public class UsVaV1 extends AbstractEncodableBitStringSection { public static int ID = 9; public static int VERSION = 1; public static String NAME = "usvav1"; - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - public UsVaV1() { - initFields(); + super(); } - public UsVaV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + public UsVaV1(String encodedString) { + super(); + decode(encodedString); } - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsVaV1Field.VERSION, new EncodableFixedInteger(6, UsVaV1.VERSION)); - fields.put(UsVaV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - //@formatter:off - fieldOrder = new String[] { - UsVaV1Field.VERSION, - UsVaV1Field.SHARING_NOTICE, - UsVaV1Field.SALE_OPT_OUT_NOTICE, - UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsVaV1Field.SALE_OPT_OUT, - UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsVaV1Field.SENSITIVE_DATA_PROCESSING, - UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsVaV1Field.MSPA_COVERED_TRANSACTION, - UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - //@formatter:on + @Override + public int getId() { + return UsVaV1.ID; } @Override - public String encode() throws EncodingException { - String bitString = this.encodeToBitString(); - String encodedString = base64UrlEncoder.encode(bitString); - return encodedString; + public String getName() { + return UsVaV1.NAME; } @Override - public void decode(String encodedString) throws DecodingException { - String bitString = base64UrlEncoder.decode(encodedString); - this.decodeFromBitString(bitString); + public int getVersion() { + return UsVaV1.VERSION; } @Override - public int getId() { - return UsVaV1.ID; + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UsVaV1CoreSegment()); + return segments; } @Override - public String getName() { - return UsVaV1.NAME; + protected List decodeSection(String encodedString) { + List segments = initializeSegments(); + + if(encodedString != null && !encodedString.isEmpty()) { + String[] encodedSegments = encodedString.split("\\."); + + for (int i = 0; i < segments.size(); i++) { + if (encodedSegments.length > i) { + segments.get(i).decode(encodedSegments[i]); + } + } + } + + return segments; } - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); + @Override + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + for (EncodableSegment segment : segments) { + encodedSegments.add(segment.encode()); + } + return String.join(".", encodedSegments); } + public Integer getSharingNotice() { - return (Integer) this.fields.get(UsVaV1Field.SHARING_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.SHARING_NOTICE); } public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsVaV1Field.SALE_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE); } public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE); } public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsVaV1Field.SALE_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.SALE_OPT_OUT); } public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT); } @SuppressWarnings("unchecked") public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsVaV1Field.SENSITIVE_DATA_PROCESSING).getValue(); + return (List) this.getFieldValue(UsVaV1Field.SENSITIVE_DATA_PROCESSING); } public Integer getKnownChildSensitiveDataConsents() { - return (Integer) this.fields.get(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS); } public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsVaV1Field.MSPA_COVERED_TRANSACTION).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.MSPA_COVERED_TRANSACTION); } public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE); } public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); + return (Integer) this.getFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE); } - } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UspV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UspV1.java index cdb20122..e70261e4 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UspV1.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/UspV1.java @@ -1,107 +1,84 @@ package com.iab.gpp.encoder.section; -import java.util.HashMap; -import java.util.Map; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; -import com.iab.gpp.encoder.field.UspV1LegacyField; - -public class UspV1 implements EncodableSection { +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.segment.EncodableSegment; +import com.iab.gpp.encoder.segment.UspV1CoreSegment; + +public class UspV1 extends AbstractLazilyEncodableSection { + public static int ID = 6; public static int VERSION = 1; public static String NAME = "uspv1"; - protected Map fields; - public UspV1() { - initFields(); - } - - public UspV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } + super(); } - private void initFields() { - fields = new HashMap<>(); - fields.put(UspV1LegacyField.VERSION, UspV1.VERSION); - fields.put(UspV1LegacyField.NOTICE, "-"); - fields.put(UspV1LegacyField.OPT_OUT_SALE, "-"); - fields.put(UspV1LegacyField.LSPA_COVERED, "-"); + public UspV1(String encodedString) { + super(); + decode(encodedString); } @Override - public boolean hasField(String fieldName) { - return this.fields.containsKey(fieldName); + public int getId() { + return UspV1.ID; } @Override - public Object getFieldValue(String fieldName) { - if (this.fields.containsKey(fieldName)) { - return this.fields.get(fieldName); - } else { - return null; - } + public String getName() { + return UspV1.NAME; } @Override - public void setFieldValue(String fieldName, Object value) throws InvalidFieldException { - if (this.fields.containsKey(fieldName)) { - this.fields.put(fieldName, value); - } else { - throw new InvalidFieldException(fieldName + " not found"); - } + public int getVersion() { + return UspV1.VERSION; } @Override - public String encode() throws EncodingException { - String str = ""; - str += this.getFieldValue(UspV1LegacyField.VERSION); - str += this.getFieldValue(UspV1LegacyField.NOTICE); - str += this.getFieldValue(UspV1LegacyField.OPT_OUT_SALE); - str += this.getFieldValue(UspV1LegacyField.LSPA_COVERED); - return str; + protected List initializeSegments() { + List segments = new ArrayList<>(); + segments.add(new UspV1CoreSegment()); + return segments; } - + @Override - public void decode(String encodedString) throws DecodingException { - try { - this.setFieldValue(UspV1LegacyField.VERSION, Integer.parseInt(String.valueOf(encodedString.charAt(0)))); - this.setFieldValue(UspV1LegacyField.NOTICE, String.valueOf(encodedString.charAt(1))); - this.setFieldValue(UspV1LegacyField.OPT_OUT_SALE, String.valueOf(encodedString.charAt(2))); - this.setFieldValue(UspV1LegacyField.LSPA_COVERED, String.valueOf(encodedString.charAt(3))); - } catch (InvalidFieldException e) { - throw new DecodingException(e); + 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]); + } + } } + + return segments; } @Override - public int getId() { - return UspV1.ID; - } - - @Override - public String getName() { - return UspV1.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(UspV1LegacyField.VERSION); + protected String encodeSection(List segments) { + List encodedSegments = new ArrayList<>(); + for(EncodableSegment segment : segments) { + encodedSegments.add(segment.encode()); + } + return String.join(".", encodedSegments); } - public String getNotice() { - return (String) fields.get(UspV1LegacyField.NOTICE); + + public Character getNotice() { + return (Character) this.getFieldValue(UspV1Field.NOTICE); } - public String getOptOutSale() { - return (String) fields.get(UspV1LegacyField.OPT_OUT_SALE); + public Character getOptOutSale() { + return (Character) this.getFieldValue(UspV1Field.OPT_OUT_SALE); } - public String getLspaCovered() { - return (String) fields.get(UspV1LegacyField.LSPA_COVERED); + public Character getLspaCovered() { + return (Character) this.getFieldValue(UspV1Field.LSPA_COVERED); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableBitStringSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableBitStringSection.java deleted file mode 100644 index 5b8f0b7c..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableBitStringSection.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.iab.gpp.encoder.section; - -import java.util.Map; -import com.iab.gpp.encoder.datatype.AbstractEncodableBitStringDataType; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; - -public abstract class AbstractEncodableBitStringSection implements EncodableSection { - protected Map> fields; - protected String[] fieldOrder; - - @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[] getFieldOrder() { - return this.fieldOrder; - } - - public String encodeToBitString() throws EncodingException { - String bitString = ""; - for (int i = 0; i < this.fieldOrder.length; i++) { - String fieldName = this.fieldOrder[i]; - if (this.fields.containsKey(fieldName)) { - AbstractEncodableBitStringDataType field = this.fields.get(fieldName); - bitString += field.encode(); - } else { - throw new EncodingException("Field not found: '" + fieldName + "'"); - } - } - - return bitString; - } - - public void decodeFromBitString(String bitString) throws DecodingException { - int index = 0; - for (int i = 0; i < this.fieldOrder.length; i++) { - String fieldName = this.fieldOrder[i]; - if (this.fields.containsKey(fieldName)) { - AbstractEncodableBitStringDataType field = this.fields.get(fieldName); - String substring = field.substring(bitString, index); - field.decode(substring); - index += substring.length(); - } 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/sectionbk/AbstractEncodableSegmentedBitStringSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableSegmentedBitStringSection.java deleted file mode 100644 index d9339189..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/AbstractEncodableSegmentedBitStringSection.java +++ /dev/null @@ -1,100 +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.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++) { - String segmentBitString = segmentBitStrings.get(i); - if (segmentBitString != null && segmentBitString.length() > 0) { - int index = 0; - 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); - String substring = field.substring(segmentBitString, index); - field.decode(substring); - index += substring.length(); - } 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/sectionbk/TcfCaV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfCaV1.java deleted file mode 100644 index ec3b4891..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfCaV1.java +++ /dev/null @@ -1,291 +0,0 @@ -package com.iab.gpp.encoder.section; - -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.function.IntSupplier; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableDatetime; -import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedString; -import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; -import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; -import com.iab.gpp.encoder.field.TcfCaV1Field; - -public class TcfCaV1 extends AbstractEncodableSegmentedBitStringSection { - public static int ID = 5; - public static int VERSION = 1; - public static String NAME = "tcfcav1"; - - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - - public TcfCaV1() { - initFields(); - } - - public TcfCaV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } - } - - private void initFields() { - fields = new HashMap<>(); - - ZonedDateTime date = ZonedDateTime.now(); - - // core section - fields.put(TcfCaV1Field.VERSION, new EncodableFixedInteger(6, TcfCaV1.VERSION)); - fields.put(TcfCaV1Field.CREATED, new EncodableDatetime(date)); - fields.put(TcfCaV1Field.LAST_UPDATED, new EncodableDatetime(date)); - fields.put(TcfCaV1Field.CMP_ID, new EncodableFixedInteger(12, 0)); - fields.put(TcfCaV1Field.CMP_VERSION, new EncodableFixedInteger(12, 0)); - fields.put(TcfCaV1Field.CONSENT_SCREEN, new EncodableFixedInteger(6, 0)); - fields.put(TcfCaV1Field.CONSENT_LANGUAGE, new EncodableFixedString(2, "EN")); - fields.put(TcfCaV1Field.VENDOR_LIST_VERSION, new EncodableFixedInteger(12, 0)); - fields.put(TcfCaV1Field.TCF_POLICY_VERSION, new EncodableFixedInteger(6, 2)); - fields.put(TcfCaV1Field.USE_NON_STANDARD_STACKS, new EncodableBoolean(false)); - fields.put(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT, new EncodableFixedBitfield( - Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfCaV1Field.VENDOR_EXPRESS_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); - fields.put(TcfCaV1Field.VENDOR_IMPLIED_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); - - // publisher purposes segment - fields.put(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); - fields.put(TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - - EncodableFixedInteger numCustomPurposes = new EncodableFixedInteger(6, 0); - fields.put(TcfCaV1Field.NUM_CUSTOM_PURPOSES, numCustomPurposes); - - IntSupplier getLengthSupplier = new IntSupplier() { - - @Override - public int getAsInt() { - return numCustomPurposes.getValue(); - } - - }; - - fields.put(TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT, - new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); - - fields.put(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT, - new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); - - //@formatter:off - String[] coreSegment = new String[] { - TcfCaV1Field.VERSION, - TcfCaV1Field.CREATED, - TcfCaV1Field.LAST_UPDATED, - TcfCaV1Field.CMP_ID, - TcfCaV1Field.CMP_VERSION, - TcfCaV1Field.CONSENT_SCREEN, - TcfCaV1Field.CONSENT_LANGUAGE, - TcfCaV1Field.VENDOR_LIST_VERSION, - TcfCaV1Field.TCF_POLICY_VERSION, - TcfCaV1Field.USE_NON_STANDARD_STACKS, - TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT, - TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, - TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, - TcfCaV1Field.VENDOR_EXPRESS_CONSENT, - TcfCaV1Field.VENDOR_IMPLIED_CONSENT - }; - - String[] publisherPurposesSegment = new String[] { - 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, - }; - - segments = new String[][] { - coreSegment, - publisherPurposesSegment - }; - //@formatter:on - } - - @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - if (segmentBitStrings.size() >= 2) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - } - - return encodedSegments.stream().collect(Collectors.joining(".")); - } - - @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[4]; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 3. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 3 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 3)) { - // unfortunately, the segment ordering doesn't match the segment ids - case "000": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "011": { - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } - } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - } - - @Override - public void setFieldValue(String fieldName, Object value) throws InvalidFieldException { - super.setFieldValue(fieldName, value); - - if (!fieldName.equals(TcfCaV1Field.CREATED) && !fieldName.equals(TcfCaV1Field.LAST_UPDATED)) { - ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC")); - - super.setFieldValue(TcfCaV1Field.CREATED, utcDateTime); - super.setFieldValue(TcfCaV1Field.LAST_UPDATED, utcDateTime); - } - } - - @Override - public int getId() { - return TcfCaV1.ID; - } - - @Override - public String getName() { - return TcfCaV1.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(TcfCaV1Field.VERSION).getValue(); - } - - public ZonedDateTime getCreated() { - return (ZonedDateTime) this.fields.get(TcfCaV1Field.CREATED).getValue(); - } - - public ZonedDateTime getLastUpdated() { - return (ZonedDateTime) this.fields.get(TcfCaV1Field.LAST_UPDATED).getValue(); - } - - public Integer getCmpId() { - return (Integer) this.fields.get(TcfCaV1Field.CMP_ID).getValue(); - } - - public Integer getCmpVersion() { - return (Integer) this.fields.get(TcfCaV1Field.CMP_VERSION).getValue(); - } - - public Integer getConsentScreen() { - return (Integer) this.fields.get(TcfCaV1Field.CONSENT_SCREEN).getValue(); - } - - public String getConsentLanguage() { - return (String) this.fields.get(TcfCaV1Field.CONSENT_LANGUAGE).getValue(); - } - - public Integer getVendorListVersion() { - return (Integer) this.fields.get(TcfCaV1Field.VENDOR_LIST_VERSION).getValue(); - } - - public Integer getPolicyVersion() { - return (Integer) this.fields.get(TcfCaV1Field.TCF_POLICY_VERSION).getValue(); - } - - public Boolean getUseNonStandardStacks() { - return (Boolean) this.fields.get(TcfCaV1Field.USE_NON_STANDARD_STACKS).getValue(); - } - - @SuppressWarnings("unchecked") - public List getSpecialFeatureExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT).getValue(); - } - - @SuppressWarnings("unchecked") - public List getPurposesExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.PURPOSES_EXPRESS_CONSENT).getValue(); - } - - @SuppressWarnings("unchecked") - public List getPurposesImpliedConsent() { - return (List) this.fields.get(TcfCaV1Field.PURPOSES_IMPLIED_CONSENT).getValue(); - } - - @SuppressWarnings("unchecked") - public List getVendorExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.VENDOR_EXPRESS_CONSENT).getValue(); - } - - @SuppressWarnings("unchecked") - public List getVendorImpliedConsent() { - return (List) this.fields.get(TcfCaV1Field.VENDOR_IMPLIED_CONSENT).getValue(); - } - - public Integer getPubPurposesSegmentType() { - return (Integer) this.fields.get(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE).getValue(); - } - - @SuppressWarnings("unchecked") - public List getPubPurposesExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT).getValue(); - } - - @SuppressWarnings("unchecked") - public List getPubPurposesImpliedConsent() { - return (List) this.fields.get(TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT).getValue(); - } - - public Integer getNumCustomPurposes() { - return (Integer) this.fields.get(TcfCaV1Field.NUM_CUSTOM_PURPOSES).getValue(); - } - - @SuppressWarnings("unchecked") - public List getCustomPurposesExpressConsent() { - return (List) this.fields.get(TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT).getValue(); - } - - @SuppressWarnings("unchecked") - public List getCustomPurposesImpliedConsent() { - return (List) this.fields.get(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT).getValue(); - } - -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfEuV2.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfEuV2.java deleted file mode 100644 index 625121bd..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/TcfEuV2.java +++ /dev/null @@ -1,376 +0,0 @@ -package com.iab.gpp.encoder.section; - -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.function.IntSupplier; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableDatetime; -import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerRange; -import com.iab.gpp.encoder.datatype.EncodableFixedString; -import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; -import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.TraditionalBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; -import com.iab.gpp.encoder.field.TcfEuV2Field; - -public class TcfEuV2 extends AbstractEncodableSegmentedBitStringSection { - public static int ID = 2; - public static int VERSION = 2; - public static String NAME = "tcfeuv2"; - - private AbstractBase64UrlEncoder base64UrlEncoder = new TraditionalBase64UrlEncoder(); - - public TcfEuV2() { - initFields(); - } - - public TcfEuV2(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } - } - - private void initFields() { - fields = new HashMap<>(); - - ZonedDateTime date = ZonedDateTime.now(); - - // core section - fields.put(TcfEuV2Field.VERSION, new EncodableFixedInteger(6, TcfEuV2.VERSION)); - fields.put(TcfEuV2Field.CREATED, new EncodableDatetime(date)); - fields.put(TcfEuV2Field.LAST_UPDATED, new EncodableDatetime(date)); - fields.put(TcfEuV2Field.CMP_ID, new EncodableFixedInteger(12, 0)); - fields.put(TcfEuV2Field.CMP_VERSION, new EncodableFixedInteger(12, 0)); - fields.put(TcfEuV2Field.CONSENT_SCREEN, new EncodableFixedInteger(6, 0)); - fields.put(TcfEuV2Field.CONSENT_LANGUAGE, new EncodableFixedString(2, "EN")); - fields.put(TcfEuV2Field.VENDOR_LIST_VERSION, new EncodableFixedInteger(12, 0)); - fields.put(TcfEuV2Field.POLICY_VERSION, new EncodableFixedInteger(6, 2)); - fields.put(TcfEuV2Field.IS_SERVICE_SPECIFIC, new EncodableBoolean(false)); - fields.put(TcfEuV2Field.USE_NON_STANDARD_STACKS, new EncodableBoolean(false)); - fields.put(TcfEuV2Field.SPECIAL_FEATURE_OPTINS, new EncodableFixedBitfield( - Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfEuV2Field.PURPOSE_CONSENTS, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfEuV2Field.PURPOSE_ONE_TREATMENT, new EncodableBoolean(false)); - fields.put(TcfEuV2Field.PUBLISHER_COUNTRY_CODE, new EncodableFixedString(2, "AA")); - fields.put(TcfEuV2Field.VENDOR_CONSENTS, new EncodableOptimizedFixedRange(new ArrayList<>())); - fields.put(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, new EncodableOptimizedFixedRange(new ArrayList<>())); - - fields.put(TcfEuV2Field.PUBLISHER_RESTRICTIONS, new EncodableFixedIntegerRange(new ArrayList<>())); - - // publisher purposes segment - fields.put(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); - fields.put(TcfEuV2Field.PUBLISHER_CONSENTS, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - fields.put(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS, - new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, - false, false, false, false, false, false, false, false, false, false, false, false, false, false))); - - EncodableFixedInteger numCustomPurposes = new EncodableFixedInteger(6, 0); - fields.put(TcfEuV2Field.NUM_CUSTOM_PURPOSES, numCustomPurposes); - - IntSupplier getLengthSupplier = new IntSupplier() { - - @Override - public int getAsInt() { - return numCustomPurposes.getValue(); - } - - }; - - fields.put(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS, - new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); - - fields.put(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS, - new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); - - fields.put(TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE, new EncodableFixedInteger(3, 2)); - fields.put(TcfEuV2Field.VENDORS_ALLOWED, new EncodableOptimizedFixedRange(new ArrayList<>())); - - fields.put(TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE, new EncodableFixedInteger(3, 1)); - fields.put(TcfEuV2Field.VENDORS_DISCLOSED, new EncodableOptimizedFixedRange(new ArrayList<>())); - - //@formatter:off - String[] coreSegment = new String[] { - TcfEuV2Field.VERSION, - TcfEuV2Field.CREATED, - TcfEuV2Field.LAST_UPDATED, - TcfEuV2Field.CMP_ID, - TcfEuV2Field.CMP_VERSION, - TcfEuV2Field.CONSENT_SCREEN, - TcfEuV2Field.CONSENT_LANGUAGE, - TcfEuV2Field.VENDOR_LIST_VERSION, - TcfEuV2Field.POLICY_VERSION, - TcfEuV2Field.IS_SERVICE_SPECIFIC, - TcfEuV2Field.USE_NON_STANDARD_STACKS, - TcfEuV2Field.SPECIAL_FEATURE_OPTINS, - TcfEuV2Field.PURPOSE_CONSENTS, - TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS, - TcfEuV2Field.PURPOSE_ONE_TREATMENT, - TcfEuV2Field.PUBLISHER_COUNTRY_CODE, - TcfEuV2Field.VENDOR_CONSENTS, - TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, - TcfEuV2Field.PUBLISHER_RESTRICTIONS - }; - - String[] publisherPurposesSegment = new String[] { - 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, - }; - - String[] vendorsAllowedSegment = new String[] { - TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE, - TcfEuV2Field.VENDORS_ALLOWED, - }; - - String[] vendorsDisclosedSegment = new String[] { - TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE, - TcfEuV2Field.VENDORS_DISCLOSED, - }; - - segments = new String[][] { - coreSegment, - publisherPurposesSegment, - vendorsAllowedSegment, - vendorsDisclosedSegment - }; - //@formatter:on - } - - @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - Boolean isServiceSpecific = (Boolean) this.getFieldValue(TcfEuV2Field.IS_SERVICE_SPECIFIC); - if (isServiceSpecific) { - if (segmentBitStrings.size() >= 2) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - } else { - if (segmentBitStrings.size() >= 2) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(2))); - - if (segmentBitStrings.size() >= 3) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(3))); - } - } - } - } - - return encodedSegments.stream().collect(Collectors.joining(".")); - } - - @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[4]; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 3. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 3 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 3)) { - // unfortunately, the segment ordering doesn't match the segment ids - case "000": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "001": { - segmentBitStrings[3] = segmentBitString; - break; - } - case "010": { - segmentBitStrings[2] = segmentBitString; - break; - } - case "011": { - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } - } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - } - - @Override - public void setFieldValue(String fieldName, Object value) throws InvalidFieldException { - super.setFieldValue(fieldName, value); - - if (!fieldName.equals(TcfEuV2Field.CREATED) && !fieldName.equals(TcfEuV2Field.LAST_UPDATED)) { - ZonedDateTime utcDateTime = ZonedDateTime.now(ZoneId.of("UTC")); - - super.setFieldValue(TcfEuV2Field.CREATED, utcDateTime); - super.setFieldValue(TcfEuV2Field.LAST_UPDATED, utcDateTime); - } - } - - @Override - public int getId() { - return TcfEuV2.ID; - } - - @Override - public String getName() { - return TcfEuV2.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(TcfEuV2Field.VERSION).getValue(); - } - - public ZonedDateTime getCreated() { - return (ZonedDateTime) this.fields.get(TcfEuV2Field.CREATED).getValue(); - } - - public ZonedDateTime getLastUpdated() { - return (ZonedDateTime) this.fields.get(TcfEuV2Field.LAST_UPDATED).getValue(); - } - - public Integer getCmpId() { - return (Integer) this.fields.get(TcfEuV2Field.CMP_ID).getValue(); - } - - public Integer getCmpVersion() { - return (Integer) this.fields.get(TcfEuV2Field.CMP_VERSION).getValue(); - } - - public Integer getConsentScreen() { - return (Integer) this.fields.get(TcfEuV2Field.CONSENT_SCREEN).getValue(); - } - - public String getConsentLanguage() { - return (String) this.fields.get(TcfEuV2Field.CONSENT_LANGUAGE).getValue(); - } - - public Integer getVendorListVersion() { - return (Integer) this.fields.get(TcfEuV2Field.VENDOR_LIST_VERSION).getValue(); - } - - public Integer getPolicyVersion() { - return (Integer) this.fields.get(TcfEuV2Field.POLICY_VERSION).getValue(); - } - - public Boolean getIsServiceSpecific() { - return (Boolean) this.fields.get(TcfEuV2Field.IS_SERVICE_SPECIFIC).getValue(); - } - - public Boolean getUseNonStandardStacks() { - return (Boolean) this.fields.get(TcfEuV2Field.USE_NON_STANDARD_STACKS).getValue(); - } - - @SuppressWarnings("unchecked") - public List getSpecialFeatureOptins() { - return (List) this.fields.get(TcfEuV2Field.SPECIAL_FEATURE_OPTINS).getValue(); - } - - @SuppressWarnings("unchecked") - public List getPurposeConsents() { - return (List) this.fields.get(TcfEuV2Field.PURPOSE_CONSENTS).getValue(); - } - - @SuppressWarnings("unchecked") - public List getPurposeLegitimateInterests() { - return (List) this.fields.get(TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS).getValue(); - } - - public Boolean getPurposeOneTreatment() { - return (Boolean) this.fields.get(TcfEuV2Field.PURPOSE_ONE_TREATMENT).getValue(); - } - - public String getPublisherCountryCode() { - return (String) this.fields.get(TcfEuV2Field.PUBLISHER_COUNTRY_CODE).getValue(); - } - - @SuppressWarnings("unchecked") - public List getVendorConsents() { - return (List) this.fields.get(TcfEuV2Field.VENDOR_CONSENTS).getValue(); - } - - @SuppressWarnings("unchecked") - public List getVendorLegitimateInterests() { - return (List) this.fields.get(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS).getValue(); - } - - @SuppressWarnings("unchecked") - public List getPublisherRestrictions() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_RESTRICTIONS).getValue(); - } - - public Integer getPublisherPurposesSegmentType() { - return (Integer) this.fields.get(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE).getValue(); - } - - @SuppressWarnings("unchecked") - public List getPublisherConsents() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_CONSENTS).getValue(); - } - - @SuppressWarnings("unchecked") - public List getPublisherLegitimateInterests() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS).getValue(); - } - - public Integer getNumCustomPurposes() { - return (Integer) this.fields.get(TcfEuV2Field.NUM_CUSTOM_PURPOSES).getValue(); - } - - @SuppressWarnings("unchecked") - public List getPublisherCustomConsents() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS).getValue(); - } - - @SuppressWarnings("unchecked") - public List getPublisherCustomLegitimateInterests() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS).getValue(); - } - - public Integer getVendorsAllowedSegmentType() { - return (Integer) this.fields.get(TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE).getValue(); - } - - @SuppressWarnings("unchecked") - public List getVendorsAllowed() { - return (List) this.fields.get(TcfEuV2Field.VENDORS_ALLOWED).getValue(); - } - - public Integer getVendorsDisclosedSegmentType() { - return (Integer) this.fields.get(TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE).getValue(); - } - - @SuppressWarnings("unchecked") - public List getVendorsDisclosed() { - return (List) this.fields.get(TcfEuV2Field.VENDORS_DISCLOSED).getValue(); - } - - - -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCaV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCaV1.java deleted file mode 100644 index de88746f..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCaV1.java +++ /dev/null @@ -1,208 +0,0 @@ -package com.iab.gpp.encoder.section; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UsCaV1Field; -import com.iab.gpp.encoder.field.UspV1Field; - -public class UsCaV1 extends AbstractEncodableSegmentedBitStringSection { - public static int ID = 8; - public static int VERSION = 1; - public static String NAME = "uscav1"; - - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - - public UsCaV1() { - initFields(); - } - - public UsCaV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } - } - - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsCaV1Field.VERSION, new EncodableFixedInteger(6, UsCaV1.VERSION)); - fields.put(UsCaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0))); - fields.put(UsCaV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - // gpc segment - fields.put(UsCaV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsCaV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsCaV1Field.GPC, new EncodableBoolean(false)); - - //@formatter:off - String[] coreSegment = new String[] { - UsCaV1Field.VERSION, - UsCaV1Field.SALE_OPT_OUT_NOTICE, - UsCaV1Field.SHARING_OPT_OUT_NOTICE, - UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, - UsCaV1Field.SALE_OPT_OUT, - UsCaV1Field.SHARING_OPT_OUT, - UsCaV1Field.SENSITIVE_DATA_PROCESSING, - UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsCaV1Field.PERSONAL_DATA_CONSENTS, - UsCaV1Field.MSPA_COVERED_TRANSACTION, - UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - - String[] gpcSegment = new String[] { - UsCaV1Field.GPC_SEGMENT_TYPE, - UsCaV1Field.GPC - }; - - segments = new String[][] { - coreSegment, - gpcSegment - }; - //@formatter:on - } - - @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - if (segmentBitStrings.size() >= 2) { - Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).getValue(); - if (gpcSegmentIncluded) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - - } - } - - return encodedSegments.stream().collect(Collectors.joining(".")); - } - - @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[2]; - boolean gpcSegmentIncluded = false; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 2)) { - case "00": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "01": { - gpcSegmentIncluded = true; - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } - } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); - } - - @Override - public int getId() { - return UsCaV1.ID; - } - - @Override - public String getName() { - return UsCaV1.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); - } - - public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsCaV1Field.SALE_OPT_OUT_NOTICE).getValue(); - } - - public Integer getSensitiveDataLimitUseNotice() { - return (Integer) this.fields.get(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE).getValue(); - } - - public Integer getSharingOptOutNotice() { - return (Integer) this.fields.get(UsCaV1Field.SHARING_OPT_OUT_NOTICE).getValue(); - } - - public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsCaV1Field.SALE_OPT_OUT).getValue(); - } - - public Integer getSharingOptOut() { - return (Integer) this.fields.get(UsCaV1Field.SHARING_OPT_OUT).getValue(); - } - - @SuppressWarnings("unchecked") - public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsCaV1Field.SENSITIVE_DATA_PROCESSING).getValue(); - } - - @SuppressWarnings("unchecked") - public List getKnownChildSensitiveDataConsents() { - return (List) this.fields.get(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); - } - - public Integer getPersonalDataConsents() { - return (Integer) this.fields.get(UsCaV1Field.PERSONAL_DATA_CONSENTS).getValue(); - } - - public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsCaV1Field.MSPA_COVERED_TRANSACTION).getValue(); - } - - public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); - } - - public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); - } - - public Integer getGpcSegmentType() { - return (Integer) this.fields.get(UsCaV1Field.GPC_SEGMENT_TYPE).getValue(); - } - - public Boolean getGpcSegmentIncluded() { - return (Boolean) this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).getValue(); - } - - public Boolean getGpc() { - return (Boolean) this.fields.get(UsCaV1Field.GPC).getValue(); - } -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCoV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCoV1.java deleted file mode 100644 index 05b2f9d6..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCoV1.java +++ /dev/null @@ -1,202 +0,0 @@ -package com.iab.gpp.encoder.section; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UsCaV1Field; -import com.iab.gpp.encoder.field.UsCoV1Field; -import com.iab.gpp.encoder.field.UspV1Field; - -public class UsCoV1 extends AbstractEncodableSegmentedBitStringSection { - public static int ID = 10; - public static int VERSION = 1; - public static String NAME = "uscov1"; - - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - - public UsCoV1() { - initFields(); - } - - public UsCoV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } - } - - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsCoV1Field.VERSION, new EncodableFixedInteger(6, UsCoV1.VERSION)); - fields.put(UsCoV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0))); - fields.put(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - // gpc segment - fields.put(UsCoV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsCoV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsCoV1Field.GPC, new EncodableBoolean(false)); - - - //@formatter:off - String[] coreSegment = new String[] { - UsCoV1Field.VERSION, - UsCoV1Field.SHARING_NOTICE, - UsCoV1Field.SALE_OPT_OUT_NOTICE, - UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsCoV1Field.SALE_OPT_OUT, - UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsCoV1Field.SENSITIVE_DATA_PROCESSING, - UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsCoV1Field.MSPA_COVERED_TRANSACTION, - UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - - String[] gpcSegment = new String[] { - UsCoV1Field.GPC_SEGMENT_TYPE, - UsCoV1Field.GPC - }; - - segments = new String[][] { - coreSegment, - gpcSegment - }; - //@formatter:on - } - - @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - if (segmentBitStrings.size() >= 2) { - Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsCoV1Field.GPC_SEGMENT_INCLUDED).getValue(); - if (gpcSegmentIncluded) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - } - } - - return encodedSegments.stream().collect(Collectors.joining(".")); - } - - @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[2]; - boolean gpcSegmentIncluded = false; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 2)) { - case "00": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "01": { - gpcSegmentIncluded = true; - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } - } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); - } - - @Override - public int getId() { - return UsCoV1.ID; - } - - @Override - public String getName() { - return UsCoV1.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); - } - - public Integer getSharingNotice() { - return (Integer) this.fields.get(UsCoV1Field.SHARING_NOTICE).getValue(); - } - - public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsCoV1Field.SALE_OPT_OUT_NOTICE).getValue(); - } - - public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); - } - - public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsCoV1Field.SALE_OPT_OUT).getValue(); - } - - public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); - } - - @SuppressWarnings("unchecked") - public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsCoV1Field.SENSITIVE_DATA_PROCESSING).getValue(); - } - - public Integer getKnownChildSensitiveDataConsents() { - return (Integer) this.fields.get(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); - } - - public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsCoV1Field.MSPA_COVERED_TRANSACTION).getValue(); - } - - public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); - } - - public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); - } - - public Integer getGpcSegmentType() { - return (Integer) this.fields.get(UsCoV1Field.GPC_SEGMENT_TYPE).getValue(); - } - - public Boolean getGpcSegmentIncluded() { - return (Boolean) this.fields.get(UsCoV1Field.GPC_SEGMENT_INCLUDED).getValue(); - } - - public Boolean getGpc() { - return (Boolean) this.fields.get(UsCoV1Field.GPC).getValue(); - } -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCtV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCtV1.java deleted file mode 100644 index 9df3e780..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsCtV1.java +++ /dev/null @@ -1,203 +0,0 @@ -package com.iab.gpp.encoder.section; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UsCaV1Field; -import com.iab.gpp.encoder.field.UsCtV1Field; -import com.iab.gpp.encoder.field.UspV1Field; - -public class UsCtV1 extends AbstractEncodableSegmentedBitStringSection { - public static int ID = 12; - public static int VERSION = 1; - public static String NAME = "usctv1"; - - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - - public UsCtV1() { - initFields(); - } - - public UsCtV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } - } - - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsCtV1Field.VERSION, new EncodableFixedInteger(6, UsCtV1.VERSION)); - fields.put(UsCtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0))); - fields.put(UsCtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - // gpc segment - fields.put(UsCtV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsCtV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsCtV1Field.GPC, new EncodableBoolean(false)); - - //@formatter:off - String[] coreSegment = new String[] { - UsCtV1Field.VERSION, - UsCtV1Field.SHARING_NOTICE, - UsCtV1Field.SALE_OPT_OUT_NOTICE, - UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsCtV1Field.SALE_OPT_OUT, - UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsCtV1Field.SENSITIVE_DATA_PROCESSING, - UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsCtV1Field.MSPA_COVERED_TRANSACTION, - UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - - String[] gpcSegment = new String[] { - UsCtV1Field.GPC_SEGMENT_TYPE, - UsCtV1Field.GPC - }; - - segments = new String[][] { - coreSegment, - gpcSegment - }; - //@formatter:on - } - - @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - if (segmentBitStrings.size() >= 2) { - Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsCtV1Field.GPC_SEGMENT_INCLUDED).getValue(); - if (gpcSegmentIncluded) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - } - } - - return encodedSegments.stream().collect(Collectors.joining(".")); - } - - @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[2]; - boolean gpcSegmentIncluded = false; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 2)) { - case "00": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "01": { - gpcSegmentIncluded = true; - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } - } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); - } - - @Override - public int getId() { - return UsCtV1.ID; - } - - @Override - public String getName() { - return UsCtV1.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); - } - - public Integer getSharingNotice() { - return (Integer) this.fields.get(UsCtV1Field.SHARING_NOTICE).getValue(); - } - - public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsCtV1Field.SALE_OPT_OUT_NOTICE).getValue(); - } - - public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); - } - - public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsCtV1Field.SALE_OPT_OUT).getValue(); - } - - public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); - } - - @SuppressWarnings("unchecked") - public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsCtV1Field.SENSITIVE_DATA_PROCESSING).getValue(); - } - - @SuppressWarnings("unchecked") - public List getKnownChildSensitiveDataConsents() { - return (List) this.fields.get(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); - } - - public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsCtV1Field.MSPA_COVERED_TRANSACTION).getValue(); - } - - public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); - } - - public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); - } - - public Integer getGpcSegmentType() { - return (Integer) this.fields.get(UsCtV1Field.GPC_SEGMENT_TYPE).getValue(); - } - - public Boolean getGpcSegmentIncluded() { - return (Boolean) this.fields.get(UsCtV1Field.GPC_SEGMENT_INCLUDED).getValue(); - } - - public Boolean getGpc() { - return (Boolean) this.fields.get(UsCtV1Field.GPC).getValue(); - } -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsNatV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsNatV1.java deleted file mode 100644 index 6cd943d9..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsNatV1.java +++ /dev/null @@ -1,233 +0,0 @@ -package com.iab.gpp.encoder.section; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableBoolean; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UsCaV1Field; -import com.iab.gpp.encoder.field.UsNatV1Field; -import com.iab.gpp.encoder.field.UspV1Field; - -public class UsNatV1 extends AbstractEncodableSegmentedBitStringSection { - public static int ID = 7; - public static int VERSION = 1; - public static String NAME = "usnatv1"; - - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - - public UsNatV1() { - initFields(); - } - - public UsNatV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } - } - - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsNatV1Field.VERSION, new EncodableFixedInteger(6, UsNatV1.VERSION)); - fields.put(UsNatV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0))); - fields.put(UsNatV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - // gpc segment - fields.put(UsNatV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); - fields.put(UsNatV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); - fields.put(UsNatV1Field.GPC, new EncodableBoolean(false)); - - - //@formatter:off - String[] coreSegment = new String[] { - UsNatV1Field.VERSION, - UsNatV1Field.SHARING_NOTICE, - UsNatV1Field.SALE_OPT_OUT_NOTICE, - UsNatV1Field.SHARING_OPT_OUT_NOTICE, - UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, - UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, - UsNatV1Field.SALE_OPT_OUT, - UsNatV1Field.SHARING_OPT_OUT, - UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsNatV1Field.SENSITIVE_DATA_PROCESSING, - UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsNatV1Field.PERSONAL_DATA_CONSENTS, - UsNatV1Field.MSPA_COVERED_TRANSACTION, - UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - - String[] gpcSegment = new String[] { - UsNatV1Field.GPC_SEGMENT_TYPE, - UsNatV1Field.GPC - }; - - segments = new String[][] { - coreSegment, - gpcSegment - }; - //@formatter:on - } - - @Override - public String encode() throws EncodingException { - List segmentBitStrings = this.encodeSegmentsToBitStrings(); - List encodedSegments = new ArrayList<>(); - if (segmentBitStrings.size() >= 1) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); - - if (segmentBitStrings.size() >= 2) { - Boolean gpcSegmentIncluded = (Boolean) this.fields.get(UsNatV1Field.GPC_SEGMENT_INCLUDED).getValue(); - if (gpcSegmentIncluded) { - encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); - } - } - } - - return encodedSegments.stream().collect(Collectors.joining(".")); - } - - @Override - public void decode(String encodedSection) throws DecodingException { - String[] encodedSegments = encodedSection.split("\\."); - String[] segmentBitStrings = new String[2]; - boolean gpcSegmentIncluded = false; - for (int i = 0; i < encodedSegments.length; i++) { - /** - * first char will contain 6 bits, we only need the first 2. There is no segment type for the CORE - * string. Instead the first 6 bits are reserved for the encoding version, but because we're only on - * a maximum of encoding version 2 the first 2 bits in the core segment will evaluate to 0. - */ - String segmentBitString = base64UrlEncoder.decode(encodedSegments[i]); - switch (segmentBitString.substring(0, 2)) { - case "00": { - segmentBitStrings[0] = segmentBitString; - break; - } - case "01": { - gpcSegmentIncluded = true; - segmentBitStrings[1] = segmentBitString; - break; - } - default: { - throw new DecodingException("Unable to decode segment '" + encodedSegments[i] + "'"); - } - } - } - this.decodeSegmentsFromBitStrings(Arrays.asList(segmentBitStrings)); - this.fields.get(UsCaV1Field.GPC_SEGMENT_INCLUDED).setValue(gpcSegmentIncluded); - } - - @Override - public int getId() { - return UsNatV1.ID; - } - - @Override - public String getName() { - return UsNatV1.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); - } - - public Integer getSharingNotice() { - return (Integer) this.fields.get(UsNatV1Field.SHARING_NOTICE).getValue(); - } - - public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsNatV1Field.SALE_OPT_OUT_NOTICE).getValue(); - } - - public Integer getSharingOptOutNotice() { - return (Integer) this.fields.get(UsNatV1Field.SHARING_OPT_OUT_NOTICE).getValue(); - } - - public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); - } - - public Integer getSensitiveDataProcessingOptOutNotice() { - return (Integer) this.fields.get(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE).getValue(); - } - - public Integer getSensitiveDataLimitUseNotice() { - return (Integer) this.fields.get(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE).getValue(); - } - - public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsNatV1Field.SALE_OPT_OUT).getValue(); - } - - public Integer getSharingOptOut() { - return (Integer) this.fields.get(UsNatV1Field.SHARING_OPT_OUT).getValue(); - } - - public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); - } - - @SuppressWarnings("unchecked") - public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsNatV1Field.SENSITIVE_DATA_PROCESSING).getValue(); - } - - @SuppressWarnings("unchecked") - public List getKnownChildSensitiveDataConsents() { - return (List) this.fields.get(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); - } - - public Integer getPersonalDataConsents() { - return (Integer) this.fields.get(UsNatV1Field.PERSONAL_DATA_CONSENTS).getValue(); - } - - public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsNatV1Field.MSPA_COVERED_TRANSACTION).getValue(); - } - - public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); - } - - public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); - } - - public Integer getGpcSegmentType() { - return (Integer) this.fields.get(UsNatV1Field.GPC_SEGMENT_TYPE).getValue(); - } - - public Boolean getGpcSegmentIncluded() { - return (Boolean) this.fields.get(UsNatV1Field.GPC_SEGMENT_INCLUDED).getValue(); - } - - public Boolean getGpc() { - return (Boolean) this.fields.get(UsNatV1Field.GPC).getValue(); - } -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsUtV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsUtV1.java deleted file mode 100644 index 9bd56c35..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsUtV1.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.iab.gpp.encoder.section; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UsUtV1Field; -import com.iab.gpp.encoder.field.UspV1Field; - -public class UsUtV1 extends AbstractEncodableBitStringSection { - public static int ID = 11; - public static int VERSION = 1; - public static String NAME = "usutv1"; - - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - - public UsUtV1() { - initFields(); - } - - public UsUtV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } - } - - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsUtV1Field.VERSION, new EncodableFixedInteger(6, UsUtV1.VERSION)); - fields.put(UsUtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - //@formatter:off - fieldOrder = new String[] { - UsUtV1Field.VERSION, - UsUtV1Field.SHARING_NOTICE, - UsUtV1Field.SALE_OPT_OUT_NOTICE, - UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, - UsUtV1Field.SALE_OPT_OUT, - UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsUtV1Field.SENSITIVE_DATA_PROCESSING, - UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsUtV1Field.MSPA_COVERED_TRANSACTION, - UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - //@formatter:on - } - - @Override - public String encode() throws EncodingException { - String bitString = this.encodeToBitString(); - String encodedString = base64UrlEncoder.encode(bitString); - return encodedString; - } - - @Override - public void decode(String encodedString) throws DecodingException { - String bitString = base64UrlEncoder.decode(encodedString); - this.decodeFromBitString(bitString); - } - - @Override - public int getId() { - return UsUtV1.ID; - } - - @Override - public String getName() { - return UsUtV1.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); - } - - public Integer getSharingNotice() { - return (Integer) this.fields.get(UsUtV1Field.SHARING_NOTICE).getValue(); - } - - public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsUtV1Field.SALE_OPT_OUT_NOTICE).getValue(); - } - - public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); - } - - public Integer getSensitiveDataProcessingOptOutNotice() { - return (Integer) this.fields.get(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE).getValue(); - } - - public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsUtV1Field.SALE_OPT_OUT).getValue(); - } - - public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); - } - - @SuppressWarnings("unchecked") - public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsUtV1Field.SENSITIVE_DATA_PROCESSING).getValue(); - } - - public Integer getKnownChildSensitiveDataConsents() { - return (Integer) this.fields.get(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); - } - - public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsUtV1Field.MSPA_COVERED_TRANSACTION).getValue(); - } - - public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); - } - - public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); - } - -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsVaV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsVaV1.java deleted file mode 100644 index fdd48f49..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UsVaV1.java +++ /dev/null @@ -1,135 +0,0 @@ -package com.iab.gpp.encoder.section; - -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; -import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; -import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.field.UspV1Field; -import com.iab.gpp.encoder.field.UsVaV1Field; - -public class UsVaV1 extends AbstractEncodableBitStringSection { - public static int ID = 9; - public static int VERSION = 1; - public static String NAME = "usvav1"; - - private AbstractBase64UrlEncoder base64UrlEncoder = new CompressedBase64UrlEncoder(); - - public UsVaV1() { - initFields(); - } - - public UsVaV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } - } - - private void initFields() { - fields = new HashMap<>(); - - fields.put(UsVaV1Field.VERSION, new EncodableFixedInteger(6, UsVaV1.VERSION)); - fields.put(UsVaV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); - - //@formatter:off - fieldOrder = new String[] { - UsVaV1Field.VERSION, - UsVaV1Field.SHARING_NOTICE, - UsVaV1Field.SALE_OPT_OUT_NOTICE, - UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - UsVaV1Field.SALE_OPT_OUT, - UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, - UsVaV1Field.SENSITIVE_DATA_PROCESSING, - UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - UsVaV1Field.MSPA_COVERED_TRANSACTION, - UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, - UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE - }; - //@formatter:on - } - - @Override - public String encode() throws EncodingException { - String bitString = this.encodeToBitString(); - String encodedString = base64UrlEncoder.encode(bitString); - return encodedString; - } - - @Override - public void decode(String encodedString) throws DecodingException { - String bitString = base64UrlEncoder.decode(encodedString); - this.decodeFromBitString(bitString); - } - - @Override - public int getId() { - return UsVaV1.ID; - } - - @Override - public String getName() { - return UsVaV1.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(UspV1Field.VERSION).getValue(); - } - - public Integer getSharingNotice() { - return (Integer) this.fields.get(UsVaV1Field.SHARING_NOTICE).getValue(); - } - - public Integer getSaleOptOutNotice() { - return (Integer) this.fields.get(UsVaV1Field.SALE_OPT_OUT_NOTICE).getValue(); - } - - public Integer getTargetedAdvertisingOptOutNotice() { - return (Integer) this.fields.get(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE).getValue(); - } - - public Integer getSaleOptOut() { - return (Integer) this.fields.get(UsVaV1Field.SALE_OPT_OUT).getValue(); - } - - public Integer getTargetedAdvertisingOptOut() { - return (Integer) this.fields.get(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT).getValue(); - } - - @SuppressWarnings("unchecked") - public List getSensitiveDataProcessing() { - return (List) this.fields.get(UsVaV1Field.SENSITIVE_DATA_PROCESSING).getValue(); - } - - public Integer getKnownChildSensitiveDataConsents() { - return (Integer) this.fields.get(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS).getValue(); - } - - public Integer getMspaCoveredTransaction() { - return (Integer) this.fields.get(UsVaV1Field.MSPA_COVERED_TRANSACTION).getValue(); - } - - public Integer getMspaOptOutOptionMode() { - return (Integer) this.fields.get(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE).getValue(); - } - - public Integer getMspaServiceProviderMode() { - return (Integer) this.fields.get(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE).getValue(); - } - -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UspV1.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UspV1.java deleted file mode 100644 index cdb20122..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/sectionbk/UspV1.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.iab.gpp.encoder.section; - -import java.util.HashMap; -import java.util.Map; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; -import com.iab.gpp.encoder.field.UspV1LegacyField; - -public class UspV1 implements EncodableSection { - public static int ID = 6; - public static int VERSION = 1; - public static String NAME = "uspv1"; - - protected Map fields; - - public UspV1() { - initFields(); - } - - public UspV1(String encodedString) throws DecodingException { - initFields(); - - if (encodedString != null && encodedString.length() > 0) { - this.decode(encodedString); - } - } - - private void initFields() { - fields = new HashMap<>(); - fields.put(UspV1LegacyField.VERSION, UspV1.VERSION); - fields.put(UspV1LegacyField.NOTICE, "-"); - fields.put(UspV1LegacyField.OPT_OUT_SALE, "-"); - fields.put(UspV1LegacyField.LSPA_COVERED, "-"); - } - - @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); - } else { - return null; - } - } - - @Override - public void setFieldValue(String fieldName, Object value) throws InvalidFieldException { - if (this.fields.containsKey(fieldName)) { - this.fields.put(fieldName, value); - } else { - throw new InvalidFieldException(fieldName + " not found"); - } - } - - @Override - public String encode() throws EncodingException { - String str = ""; - str += this.getFieldValue(UspV1LegacyField.VERSION); - str += this.getFieldValue(UspV1LegacyField.NOTICE); - str += this.getFieldValue(UspV1LegacyField.OPT_OUT_SALE); - str += this.getFieldValue(UspV1LegacyField.LSPA_COVERED); - return str; - } - - @Override - public void decode(String encodedString) throws DecodingException { - try { - this.setFieldValue(UspV1LegacyField.VERSION, Integer.parseInt(String.valueOf(encodedString.charAt(0)))); - this.setFieldValue(UspV1LegacyField.NOTICE, String.valueOf(encodedString.charAt(1))); - this.setFieldValue(UspV1LegacyField.OPT_OUT_SALE, String.valueOf(encodedString.charAt(2))); - this.setFieldValue(UspV1LegacyField.LSPA_COVERED, String.valueOf(encodedString.charAt(3))); - } catch (InvalidFieldException e) { - throw new DecodingException(e); - } - } - - @Override - public int getId() { - return UspV1.ID; - } - - @Override - public String getName() { - return UspV1.NAME; - } - - public Integer getVersion() { - return (Integer) this.fields.get(UspV1LegacyField.VERSION); - } - - public String getNotice() { - return (String) fields.get(UspV1LegacyField.NOTICE); - } - - public String getOptOutSale() { - return (String) fields.get(UspV1LegacyField.OPT_OUT_SALE); - } - - public String getLspaCovered() { - return (String) fields.get(UspV1LegacyField.LSPA_COVERED); - } -} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java new file mode 100644 index 00000000..44e6bc9f --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java @@ -0,0 +1,75 @@ +package com.iab.gpp.encoder.segment; + +import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.field.Fields; + +public abstract class AbstractLazilyEncodableSegment> implements EncodableSegment { + + protected T fields; + + private String encodedString = null; + + private boolean dirty = false; + private boolean decoded = true; + + public AbstractLazilyEncodableSegment() { + this.fields = initializeFields(); + } + + protected abstract T initializeFields(); + + protected abstract String encodeSegment(T fields); + + protected abstract void decodeSegment(String encodedString, T Fields); + + public boolean hasField(String fieldName) { + return this.fields.containsKey(fieldName); + } + + public Object getFieldValue(String fieldName) { + if (!this.decoded) { + this.decodeSegment(this.encodedString, this.fields); + this.dirty = false; + this.decoded = true; + } + + if (this.fields.containsKey(fieldName)) { + return this.fields.get(fieldName).getValue(); + } else { + throw new InvalidFieldException("Invalid field: '" + fieldName + "'"); + } + } + + public void setFieldValue(String fieldName, Object value) { + if (!this.decoded) { + this.decodeSegment(this.encodedString, this.fields); + this.dirty = false; + this.decoded = true; + } + + if (this.fields.containsKey(fieldName)) { + this.fields.get(fieldName).setValue(value); + this.dirty = true; + } else { + throw new InvalidFieldException(fieldName + " not found"); + } + } + + public String encode() { + if (this.encodedString == null || this.encodedString.isEmpty() || this.dirty) { + this.encodedString = encodeSegment(this.fields); + this.dirty = false; + this.decoded = true; + } + + return this.encodedString; + } + + public void decode(String encodedString) { + this.encodedString = encodedString; + this.dirty = false; + this.decoded = false; + } + + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java new file mode 100644 index 00000000..abdde319 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java @@ -0,0 +1,18 @@ +package com.iab.gpp.encoder.segment; + +import java.util.List; + +public interface EncodableSegment { + + List getFieldNames(); + + boolean hasField(String fieldName); + + Object getFieldValue(String fieldName); + + void setFieldValue(String fieldName, Object value); + + String encode(); + + void decode(String encodedString); +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java new file mode 100644 index 00000000..44e18bbf --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java @@ -0,0 +1,57 @@ +package com.iab.gpp.encoder.segment; + +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFibonacciIntegerRange; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.HeaderV1Field; +import com.iab.gpp.encoder.section.HeaderV1; + +public class HeaderV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public HeaderV1CoreSegment() { + super(); + } + + public HeaderV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return HeaderV1Field.HEADER_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(HeaderV1Field.ID, new EncodableFixedInteger(6, HeaderV1.ID)); + fields.put(HeaderV1Field.VERSION, new EncodableFixedInteger(6, HeaderV1.VERSION)); + fields.put(HeaderV1Field.SECTION_IDS, new EncodableFibonacciIntegerRange(new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1CoreSegment.java new file mode 100644 index 00000000..069ec010 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1CoreSegment.java @@ -0,0 +1,82 @@ +package com.iab.gpp.encoder.segment; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableDatetime; +import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedString; +import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfCaV1Field; +import com.iab.gpp.encoder.section.TcfCaV1; + +public class TcfCaV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfCaV1CoreSegment() { + super(); + } + + public TcfCaV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfCaV1Field.TCFCAV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + ZonedDateTime date = ZonedDateTime.now(); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfCaV1Field.VERSION, new EncodableFixedInteger(6, TcfCaV1.VERSION)); + fields.put(TcfCaV1Field.CREATED, new EncodableDatetime(date)); + fields.put(TcfCaV1Field.LAST_UPDATED, new EncodableDatetime(date)); + fields.put(TcfCaV1Field.CMP_ID, new EncodableFixedInteger(12, 0)); + fields.put(TcfCaV1Field.CMP_VERSION, new EncodableFixedInteger(12, 0)); + fields.put(TcfCaV1Field.CONSENT_SCREEN, new EncodableFixedInteger(6, 0)); + fields.put(TcfCaV1Field.CONSENT_LANGUAGE, new EncodableFixedString(2, "EN")); + fields.put(TcfCaV1Field.VENDOR_LIST_VERSION, new EncodableFixedInteger(12, 0)); + fields.put(TcfCaV1Field.TCF_POLICY_VERSION, new EncodableFixedInteger(6, 2)); + fields.put(TcfCaV1Field.USE_NON_STANDARD_STACKS, new EncodableBoolean(false)); + fields.put(TcfCaV1Field.SPECIAL_FEATURE_EXPRESS_CONSENT, new EncodableFixedBitfield( + Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfCaV1Field.VENDOR_EXPRESS_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); + fields.put(TcfCaV1Field.VENDOR_IMPLIED_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1PublisherPurposesSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1PublisherPurposesSegment.java new file mode 100644 index 00000000..89d63390 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1PublisherPurposesSegment.java @@ -0,0 +1,81 @@ +package com.iab.gpp.encoder.segment; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.IntSupplier; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfCaV1Field; + +public class TcfCaV1PublisherPurposesSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfCaV1PublisherPurposesSegment() { + super(); + } + + public TcfCaV1PublisherPurposesSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfCaV1Field.TCFCAV1_PUBLISHER_PURPOSES_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); + fields.put(TcfCaV1Field.PUB_PURPOSES_EXPRESS_CONSENT, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfCaV1Field.PUB_PURPOSES_IMPLIED_CONSENT, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + + EncodableFixedInteger numCustomPurposes = new EncodableFixedInteger(6, 0); + fields.put(TcfCaV1Field.NUM_CUSTOM_PURPOSES, numCustomPurposes); + + IntSupplier getLengthSupplier = new IntSupplier() { + + @Override + public int getAsInt() { + return numCustomPurposes.getValue(); + } + + }; + + fields.put(TcfCaV1Field.CUSTOM_PURPOSES_EXPRESS_CONSENT, + new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + + fields.put(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT, + new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2CoreSegment.java new file mode 100644 index 00000000..5e894459 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2CoreSegment.java @@ -0,0 +1,88 @@ +package com.iab.gpp.encoder.segment; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.TraditionalBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableDatetime; +import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerRange; +import com.iab.gpp.encoder.datatype.EncodableFixedString; +import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfEuV2Field; +import com.iab.gpp.encoder.section.TcfEuV2; + +public class TcfEuV2CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = TraditionalBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfEuV2CoreSegment() { + super(); + } + + public TcfEuV2CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfEuV2Field.TCFEUV2_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + ZonedDateTime date = ZonedDateTime.now(); + + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfEuV2Field.VERSION, new EncodableFixedInteger(6, TcfEuV2.VERSION)); + fields.put(TcfEuV2Field.CREATED, new EncodableDatetime(date)); + fields.put(TcfEuV2Field.LAST_UPDATED, new EncodableDatetime(date)); + fields.put(TcfEuV2Field.CMP_ID, new EncodableFixedInteger(12, 0)); + fields.put(TcfEuV2Field.CMP_VERSION, new EncodableFixedInteger(12, 0)); + fields.put(TcfEuV2Field.CONSENT_SCREEN, new EncodableFixedInteger(6, 0)); + fields.put(TcfEuV2Field.CONSENT_LANGUAGE, new EncodableFixedString(2, "EN")); + fields.put(TcfEuV2Field.VENDOR_LIST_VERSION, new EncodableFixedInteger(12, 0)); + fields.put(TcfEuV2Field.POLICY_VERSION, new EncodableFixedInteger(6, 2)); + fields.put(TcfEuV2Field.IS_SERVICE_SPECIFIC, new EncodableBoolean(false)); + fields.put(TcfEuV2Field.USE_NON_STANDARD_STACKS, new EncodableBoolean(false)); + fields.put(TcfEuV2Field.SPECIAL_FEATURE_OPTINS, new EncodableFixedBitfield( + Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfEuV2Field.PURPOSE_CONSENTS, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfEuV2Field.PURPOSE_LEGITIMATE_INTERESTS, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfEuV2Field.PURPOSE_ONE_TREATMENT, new EncodableBoolean(false)); + fields.put(TcfEuV2Field.PUBLISHER_COUNTRY_CODE, new EncodableFixedString(2, "AA")); + fields.put(TcfEuV2Field.VENDOR_CONSENTS, new EncodableOptimizedFixedRange(new ArrayList<>())); + fields.put(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, new EncodableOptimizedFixedRange(new ArrayList<>())); + + fields.put(TcfEuV2Field.PUBLISHER_RESTRICTIONS, new EncodableFixedIntegerRange(new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2PublisherPurposesSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2PublisherPurposesSegment.java new file mode 100644 index 00000000..4d351f67 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2PublisherPurposesSegment.java @@ -0,0 +1,81 @@ +package com.iab.gpp.encoder.segment; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.function.IntSupplier; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.TraditionalBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfEuV2Field; + +public class TcfEuV2PublisherPurposesSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = TraditionalBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfEuV2PublisherPurposesSegment() { + super(); + } + + public TcfEuV2PublisherPurposesSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfEuV2Field.TCFEUV2_PUBLISHER_PURPOSES_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); + fields.put(TcfEuV2Field.PUBLISHER_CONSENTS, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + fields.put(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS, + new EncodableFixedBitfield(Arrays.asList(false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false, false, false, false, false))); + + EncodableFixedInteger numCustomPurposes = new EncodableFixedInteger(6, 0); + fields.put(TcfEuV2Field.NUM_CUSTOM_PURPOSES, numCustomPurposes); + + IntSupplier getLengthSupplier = new IntSupplier() { + + @Override + public int getAsInt() { + return numCustomPurposes.getValue(); + } + + }; + + fields.put(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS, + new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + + fields.put(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS, + new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsAllowedSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsAllowedSegment.java new file mode 100644 index 00000000..ffe382be --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsAllowedSegment.java @@ -0,0 +1,55 @@ +package com.iab.gpp.encoder.segment; + +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.TraditionalBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfEuV2Field; + +public class TcfEuV2VendorsAllowedSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = TraditionalBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfEuV2VendorsAllowedSegment() { + super(); + } + + public TcfEuV2VendorsAllowedSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfEuV2Field.TCFEUV2_VENDORS_ALLOWED_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfEuV2Field.VENDORS_ALLOWED_SEGMENT_TYPE, new EncodableFixedInteger(3, 2)); + fields.put(TcfEuV2Field.VENDORS_ALLOWED, new EncodableOptimizedFixedRange(new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsDisclosedSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsDisclosedSegment.java new file mode 100644 index 00000000..1487eb5b --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsDisclosedSegment.java @@ -0,0 +1,55 @@ +package com.iab.gpp.encoder.segment; + +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.TraditionalBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.TcfEuV2Field; + +public class TcfEuV2VendorsDisclosedSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = TraditionalBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public TcfEuV2VendorsDisclosedSegment() { + super(); + } + + public TcfEuV2VendorsDisclosedSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return TcfEuV2Field.TCFEUV2_VENDORS_DISCLOSED_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(TcfEuV2Field.VENDORS_DISCLOSED_SEGMENT_TYPE, new EncodableFixedInteger(3, 1)); + fields.put(TcfEuV2Field.VENDORS_DISCLOSED, new EncodableOptimizedFixedRange(new ArrayList<>())); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java new file mode 100644 index 00000000..4350e694 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java @@ -0,0 +1,67 @@ +package com.iab.gpp.encoder.segment; + +import java.util.Arrays; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCaV1Field; +import com.iab.gpp.encoder.section.UsCaV1; + +public class UsCaV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsCaV1CoreSegment() { + super(); + } + + public UsCaV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsCaV1Field.USCAV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsCaV1Field.VERSION, new EncodableFixedInteger(6, UsCaV1.VERSION)); + fields.put(UsCaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0))); + fields.put(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0))); + fields.put(UsCaV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1GpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1GpcSegment.java new file mode 100644 index 00000000..d3b15593 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1GpcSegment.java @@ -0,0 +1,55 @@ +package com.iab.gpp.encoder.segment; + +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCaV1Field; + +public class UsCaV1GpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsCaV1GpcSegment() { + super(); + } + + public UsCaV1GpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsCaV1Field.USCAV1_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsCaV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsCaV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsCaV1Field.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java new file mode 100644 index 00000000..4885f8f6 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java @@ -0,0 +1,66 @@ +package com.iab.gpp.encoder.segment; + +import java.util.Arrays; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCoV1Field; +import com.iab.gpp.encoder.section.UsCoV1; + +public class UsCoV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsCoV1CoreSegment() { + super(); + } + + public UsCoV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsCoV1Field.USCOV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsCoV1Field.VERSION, new EncodableFixedInteger(6, UsCoV1.VERSION)); + fields.put(UsCoV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0))); + fields.put(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1GpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1GpcSegment.java new file mode 100644 index 00000000..6281419c --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1GpcSegment.java @@ -0,0 +1,55 @@ +package com.iab.gpp.encoder.segment; + +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCoV1Field; + +public class UsCoV1GpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsCoV1GpcSegment() { + super(); + } + + public UsCoV1GpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsCoV1Field.USCOV1_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsCoV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsCoV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsCoV1Field.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java new file mode 100644 index 00000000..22a44d61 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java @@ -0,0 +1,67 @@ +package com.iab.gpp.encoder.segment; + +import java.util.Arrays; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCtV1Field; +import com.iab.gpp.encoder.section.UsCtV1; + +public class UsCtV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsCtV1CoreSegment() { + super(); + } + + public UsCtV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsCtV1Field.USCTV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsCtV1Field.VERSION, new EncodableFixedInteger(6, UsCtV1.VERSION)); + fields.put(UsCtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); + fields.put(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0))); + fields.put(UsCtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1GpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1GpcSegment.java new file mode 100644 index 00000000..6ff912c0 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1GpcSegment.java @@ -0,0 +1,55 @@ +package com.iab.gpp.encoder.segment; + +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCtV1Field; + +public class UsCtV1GpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsCtV1GpcSegment() { + super(); + } + + public UsCtV1GpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsCtV1Field.USCTV1_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsCtV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsCtV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsCtV1Field.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java new file mode 100644 index 00000000..ee664225 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java @@ -0,0 +1,71 @@ +package com.iab.gpp.encoder.segment; + +import java.util.Arrays; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsNatV1Field; +import com.iab.gpp.encoder.section.UsNatV1; + +public class UsNatV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsNatV1CoreSegment() { + super(); + } + + public UsNatV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsNatV1Field.USNATV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsNatV1Field.VERSION, new EncodableFixedInteger(6, UsNatV1.VERSION)); + fields.put(UsNatV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); + fields.put(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0))); + fields.put(UsNatV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1GpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1GpcSegment.java new file mode 100644 index 00000000..ea8d9746 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1GpcSegment.java @@ -0,0 +1,55 @@ +package com.iab.gpp.encoder.segment; + +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableBoolean; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsNatV1Field; + +public class UsNatV1GpcSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsNatV1GpcSegment() { + super(); + } + + public UsNatV1GpcSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsNatV1Field.USNATV1_GPC_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsNatV1Field.GPC_SEGMENT_TYPE, new EncodableFixedInteger(2, 1)); + fields.put(UsNatV1Field.GPC_SEGMENT_INCLUDED, new EncodableBoolean(true)); + fields.put(UsNatV1Field.GPC, new EncodableBoolean(false)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java new file mode 100644 index 00000000..21c941b5 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java @@ -0,0 +1,67 @@ +package com.iab.gpp.encoder.segment; + +import java.util.Arrays; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsUtV1Field; +import com.iab.gpp.encoder.section.UsUtV1; + +public class UsUtV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsUtV1CoreSegment() { + super(); + } + + public UsUtV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsUtV1Field.USUTV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsUtV1Field.VERSION, new EncodableFixedInteger(6, UsUtV1.VERSION)); + fields.put(UsUtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); + fields.put(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java new file mode 100644 index 00000000..c52f7ba6 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java @@ -0,0 +1,66 @@ +package com.iab.gpp.encoder.segment; + +import java.util.Arrays; +import java.util.List; +import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; +import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; +import com.iab.gpp.encoder.bitstring.BitStringEncoder; +import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsVaV1Field; +import com.iab.gpp.encoder.section.UsVaV1; + +public class UsVaV1CoreSegment extends AbstractLazilyEncodableSegment { + + private AbstractBase64UrlEncoder base64UrlEncoder = CompressedBase64UrlEncoder.getInstance(); + private BitStringEncoder bitStringEncoder = BitStringEncoder.getInstance(); + + public UsVaV1CoreSegment() { + super(); + } + + public UsVaV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UsVaV1Field.USVAV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected EncodableBitStringFields initializeFields() { + EncodableBitStringFields fields = new EncodableBitStringFields(); + fields.put(UsVaV1Field.VERSION, new EncodableFixedInteger(6, UsVaV1.VERSION)); + fields.put(UsVaV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.SENSITIVE_DATA_PROCESSING, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); + fields.put(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + return fields; + } + + @Override + protected String encodeSegment(EncodableBitStringFields fields) { + String bitString = bitStringEncoder.encode(fields, getFieldNames()); + String encodedString = base64UrlEncoder.encode(bitString); + return encodedString; + } + + @Override + protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { + if(encodedString == null || encodedString.isEmpty()) { + this.fields.reset(fields); + } + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java new file mode 100644 index 00000000..d7ec8525 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java @@ -0,0 +1,60 @@ +package com.iab.gpp.encoder.segment; + +import java.util.List; +import com.iab.gpp.encoder.datatype.UnencodableCharacter; +import com.iab.gpp.encoder.datatype.UnencodableInteger; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.field.GenericFields; +import com.iab.gpp.encoder.field.UspV1Field; +import com.iab.gpp.encoder.section.UspV1; + +public class UspV1CoreSegment extends AbstractLazilyEncodableSegment { + + public UspV1CoreSegment() { + super(); + } + + public UspV1CoreSegment(String encodedString) { + super(); + this.decode(encodedString); + } + + @Override + public List getFieldNames() { + return UspV1Field.USPV1_CORE_SEGMENT_FIELD_NAMES; + } + + @Override + protected GenericFields initializeFields() { + GenericFields fields = new GenericFields(); + fields.put(UspV1Field.VERSION, new UnencodableInteger(UspV1.VERSION)); + fields.put(UspV1Field.NOTICE, new UnencodableCharacter('-')); + fields.put(UspV1Field.OPT_OUT_SALE, new UnencodableCharacter('-')); + fields.put(UspV1Field.LSPA_COVERED, new UnencodableCharacter('-')); + return fields; + } + + @Override + protected String encodeSegment(GenericFields fields) { + String str = ""; + str += fields.get(UspV1Field.VERSION).getValue(); + str += fields.get(UspV1Field.NOTICE).getValue(); + str += fields.get(UspV1Field.OPT_OUT_SALE).getValue(); + str += fields.get(UspV1Field.LSPA_COVERED).getValue(); + return str; + } + + @Override + protected void decodeSegment(String encodedString, GenericFields fields) { + if (encodedString == null || encodedString.length() != 4) { + throw new DecodingException("Invalid uspv1 string: '" + encodedString + "'"); + } + + fields.get(UspV1Field.VERSION).setValue(Integer.parseInt(encodedString.substring(0, 1))); + fields.get(UspV1Field.NOTICE).setValue(encodedString.charAt(1)); + fields.get(UspV1Field.OPT_OUT_SALE).setValue(encodedString.charAt(2)); + fields.get(UspV1Field.LSPA_COVERED).setValue(encodedString.charAt(3)); + } + +} + diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index f46c51ab..8538f47d 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -7,9 +7,6 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; -import com.iab.gpp.encoder.error.LazyDecodingException; import com.iab.gpp.encoder.field.TcfCaV1Field; import com.iab.gpp.encoder.field.TcfEuV2Field; import com.iab.gpp.encoder.field.UsCaV1Field; @@ -34,7 +31,7 @@ public class GppModelTest { private ZonedDateTime utcDateTime = ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC")); @Test - public void testEncodeDefault() throws EncodingException, LazyDecodingException { + public void testEncodeDefault() { GppModel gppModel = new GppModel(); Assertions.assertEquals(false, gppModel.hasSection(UspV1.ID)); Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.ID)); @@ -63,14 +60,14 @@ public void testLazyDecodingException() { GppModel gppModel = new GppModel("invalid gpp string"); try { gppModel.getHeader(); - Assertions.fail("Expected LazyDecodingException"); - } catch (LazyDecodingException e) { + Assertions.fail("Expected DecodingException"); + } catch (DecodingException e) { } } @Test - public void testEncodeDefaultAll() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncodeDefaultAll() { GppModel gppModel = new GppModel(); Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.NAME)); @@ -117,7 +114,7 @@ public void testEncodeDefaultAll() throws EncodingException, InvalidFieldExcepti } @Test - public void testEncodeUspv1() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncodeUspv1() { GppModel gppModel = new GppModel(); Assertions.assertEquals(false, gppModel.hasSection(UspV1.ID)); Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.ID)); @@ -127,9 +124,9 @@ public void testEncodeUspv1() throws EncodingException, InvalidFieldException, L Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.NAME)); Assertions.assertEquals(false, gppModel.hasSection(TcfCaV1.NAME)); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.NOTICE, "Y"); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE, "N"); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED, "N"); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.NOTICE, 'Y'); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE, 'N'); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED, 'N'); Assertions.assertEquals(Arrays.asList(6), gppModel.getSectionIds()); Assertions.assertEquals(true, gppModel.hasSection(UspV1.ID)); @@ -157,7 +154,7 @@ public void testEncodeUspv1() throws EncodingException, InvalidFieldException, L } @Test - public void testEncodeTcfEuV2() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncodeTcfEuV2() { GppModel gppModel = new GppModel(); Assertions.assertEquals(false, gppModel.hasSection(UspV1.ID)); Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.ID)); @@ -207,7 +204,7 @@ public void testEncodeTcfEuV2() throws EncodingException, InvalidFieldException, } @Test - public void testEncodeUspV1AndTcfEuV2() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncodeUspV1AndTcfEuV2() { GppModel gppModel = new GppModel(); Assertions.assertEquals(false, gppModel.hasSection(UspV1.NAME)); Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.NAME)); @@ -231,9 +228,9 @@ public void testEncodeUspV1AndTcfEuV2() throws EncodingException, InvalidFieldEx Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); Assertions.assertEquals(false, gppModel.hasSection(TcfCaV1.NAME)); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.NOTICE, "Y"); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE, "N"); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED, "N"); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.NOTICE, 'Y'); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE, 'N'); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED, 'N'); Assertions.assertEquals(true, gppModel.hasSection(UspV1.NAME)); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); @@ -253,7 +250,7 @@ public void testEncodeUspV1AndTcfEuV2() throws EncodingException, InvalidFieldEx @Test public void testEncodeUspV1AndTcfEuV2AndTcfCaV1() - throws EncodingException, InvalidFieldException, LazyDecodingException { + { GppModel gppModel = new GppModel(); Assertions.assertEquals(false, gppModel.hasSection(UspV1.ID)); Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.ID)); @@ -287,9 +284,9 @@ public void testEncodeUspV1AndTcfEuV2AndTcfCaV1() Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); Assertions.assertEquals(false, gppModel.hasSection(TcfCaV1.NAME)); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.NOTICE, "Y"); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE, "N"); - gppModel.setFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED, "N"); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.NOTICE, 'Y'); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE, 'N'); + gppModel.setFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED, 'N'); Assertions.assertEquals(true, gppModel.hasSection(UspV1.ID)); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.ID)); @@ -355,7 +352,7 @@ public void testEncodeUspV1AndTcfEuV2AndTcfCaV1() } @Test - public void testDecodeDefaults() throws DecodingException { + public void testDecodeDefaults() { String gppString = "DBAA"; GppModel gppModel = new GppModel(gppString); @@ -370,7 +367,7 @@ public void testDecodeDefaults() throws DecodingException { } @Test - public void testDecodeDefaultsAll() throws DecodingException { + public void testDecodeDefaultsAll() { String gppString = "DBACOaw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAAA.QA~BAAAAAAA.QA~BAAAAAA~BAAAAAA.QA~BAAAAAAA~BAAAAAAA.QA"; GppModel gppModel = new GppModel(gppString); @@ -387,7 +384,7 @@ public void testDecodeDefaultsAll() throws DecodingException { } @Test - public void testDecodeUspv1() throws DecodingException { + public void testDecodeUspv1() { String gppString = "DBABTA~1YNN"; GppModel gppModel = new GppModel(gppString); @@ -400,17 +397,17 @@ public void testDecodeUspv1() throws DecodingException { Assertions.assertEquals(false, gppModel.hasSection(TcfEuV2.NAME)); Assertions.assertEquals(false, gppModel.hasSection(TcfCaV1.NAME)); - Assertions.assertEquals("Y", gppModel.getFieldValue(UspV1.ID, UspV1Field.NOTICE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.ID, UspV1Field.OPT_OUT_SALE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.ID, UspV1Field.LSPA_COVERED)); + Assertions.assertEquals('Y', gppModel.getFieldValue(UspV1.ID, UspV1Field.NOTICE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.ID, UspV1Field.OPT_OUT_SALE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.ID, UspV1Field.LSPA_COVERED)); - Assertions.assertEquals("Y", gppModel.getFieldValue(UspV1.NAME, UspV1Field.NOTICE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED)); + Assertions.assertEquals('Y', gppModel.getFieldValue(UspV1.NAME, UspV1Field.NOTICE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED)); } @Test - public void testDecodeTcfEuV2() throws DecodingException { + public void testDecodeTcfEuV2() { String gppString = "DBABMA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA"; GppModel gppModel = new GppModel(gppString); @@ -453,7 +450,7 @@ public void testDecodeTcfEuV2() throws DecodingException { } @Test - public void testDecodeUspv1AndTcfEuV2() throws DecodingException { + public void testDecodeUspv1AndTcfEuV2() { String gppString = "DBACNYA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~1YNN"; GppModel gppModel = new GppModel(gppString); @@ -467,13 +464,13 @@ public void testDecodeUspv1AndTcfEuV2() throws DecodingException { Assertions.assertEquals(false, gppModel.hasSection(TcfCaV1.NAME)); - Assertions.assertEquals("Y", gppModel.getFieldValue(UspV1.ID, UspV1Field.NOTICE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.ID, UspV1Field.OPT_OUT_SALE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.ID, UspV1Field.LSPA_COVERED)); + Assertions.assertEquals('Y', gppModel.getFieldValue(UspV1.ID, UspV1Field.NOTICE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.ID, UspV1Field.OPT_OUT_SALE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.ID, UspV1Field.LSPA_COVERED)); - Assertions.assertEquals("Y", gppModel.getFieldValue(UspV1.NAME, UspV1Field.NOTICE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED)); + Assertions.assertEquals('Y', gppModel.getFieldValue(UspV1.NAME, UspV1Field.NOTICE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED)); Assertions.assertEquals(2, gppModel.getFieldValue(TcfEuV2.ID, TcfEuV2Field.VERSION)); Assertions.assertEquals(880, gppModel.getFieldValue(TcfEuV2.ID, TcfEuV2Field.CMP_ID)); @@ -511,13 +508,13 @@ public void testDecodeUspv1AndTcfEuV2() throws DecodingException { UspV1 uspV1Section = (UspV1) gppModel.getSection(UspV1.NAME); Integer uspV1Version = uspV1Section.getVersion(); - String notice = uspV1Section.getNotice(); + Character notice = uspV1Section.getNotice(); Assertions.assertEquals(1, uspV1Version); - Assertions.assertEquals("Y", notice); + Assertions.assertEquals('Y', notice); } @Test - public void testDecodeUspv1AndTcfEuV2AndTcfCaV1() throws DecodingException { + public void testDecodeUspv1AndTcfEuV2AndTcfCaV1() { String gppString = "DBACOeA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACAC.fHHHA4444ao~1YNN"; GppModel gppModel = new GppModel(gppString); @@ -527,9 +524,9 @@ public void testDecodeUspv1AndTcfEuV2AndTcfCaV1() throws DecodingException { Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); Assertions.assertEquals(true, gppModel.hasSection(TcfCaV1.NAME)); - Assertions.assertEquals("Y", gppModel.getFieldValue(UspV1.NAME, UspV1Field.NOTICE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE)); - Assertions.assertEquals("N", gppModel.getFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED)); + Assertions.assertEquals('Y', gppModel.getFieldValue(UspV1.NAME, UspV1Field.NOTICE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.NAME, UspV1Field.OPT_OUT_SALE)); + Assertions.assertEquals('N', gppModel.getFieldValue(UspV1.NAME, UspV1Field.LSPA_COVERED)); Assertions.assertEquals(2, gppModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VERSION)); Assertions.assertEquals(880, gppModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.CMP_ID)); @@ -553,9 +550,9 @@ public void testDecodeUspv1AndTcfEuV2AndTcfCaV1() throws DecodingException { UspV1 uspV1Section = (UspV1) gppModel.getSection(UspV1.NAME); Integer uspV1Version = uspV1Section.getVersion(); - String notice = uspV1Section.getNotice(); + Character notice = uspV1Section.getNotice(); Assertions.assertEquals(1, uspV1Version); - Assertions.assertEquals("Y", notice); + Assertions.assertEquals('Y', notice); TcfCaV1 tcfCaV1Section = (TcfCaV1) gppModel.getSection(TcfCaV1.NAME); Assertions.assertEquals(50, tcfCaV1Section.getCmpId()); @@ -598,7 +595,7 @@ public void testDecodeUspv1AndTcfEuV2AndTcfCaV1() throws DecodingException { } @Test - public void testEncode1() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncode1() { GppModel gppModel = new GppModel(); gppModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS, Arrays.asList(28)); @@ -609,7 +606,7 @@ public void testEncode1() throws EncodingException, InvalidFieldException, LazyD } @Test - public void testEncode2() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncode2() { GppModel gppModel = new GppModel(); gppModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS, Arrays.asList(29)); @@ -620,7 +617,7 @@ public void testEncode2() throws EncodingException, InvalidFieldException, LazyD } @Test - public void testEncode3() throws EncodingException, InvalidFieldException, LazyDecodingException { + public void testEncode3() { GppModel gppModel = new GppModel(); gppModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS, Arrays.asList(1, 173, 722)); @@ -632,26 +629,26 @@ public void testEncode3() throws EncodingException, InvalidFieldException, LazyD } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { GppModel gppModel = new GppModel("DBABMA~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAOAAAABAAAAA.QAAA.IAAA"); Assertions.assertEquals(Arrays.asList(28), gppModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS)); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { GppModel gppModel = new GppModel("DBABMA~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAOwAQAOgAAAA.QAAA.IAAA"); Assertions.assertEquals(Arrays.asList(29), gppModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS)); } @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { GppModel gppModel = new GppModel("DBABMA~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAFpQAwAAgCtAWkAAAAAAA.QAAA.IAAA"); Assertions.assertEquals(Arrays.asList(1, 173, 722), gppModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS)); } @Test - public void testConsistency() throws InvalidFieldException, EncodingException, DecodingException { + public void testConsistency() { GppModel fromObjectModel = new GppModel(); fromObjectModel.setFieldValue(TcfEuV2.NAME, TcfEuV2Field.PURPOSE_CONSENTS, @@ -673,4 +670,28 @@ public void testConsistency() throws InvalidFieldException, EncodingException, D decodedModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS)); } + + @Test + public void testDecodingNull() { + GppModel gppModel = new GppModel("DBABTA~1---"); + Assertions.assertEquals("DBABTA~1---", gppModel.encode()); + + gppModel.decode(null); + Assertions.assertEquals("DBAA", gppModel.encode()); + + gppModel.setFieldValue("uspv1", UspV1Field.NOTICE, 'Y'); + Assertions.assertEquals("DBABTA~1Y--", gppModel.encode()); + } + + @Test + public void testDecodingEmptyString() { + GppModel gppModel = new GppModel("DBABTA~1---"); + Assertions.assertEquals("DBABTA~1---", gppModel.encode()); + + gppModel.decode(null); + Assertions.assertEquals("DBAA", gppModel.encode()); + + gppModel.setFieldValue("uspv1", UspV1Field.NOTICE, 'Y'); + Assertions.assertEquals("DBABTA~1Y--", gppModel.encode()); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRangeTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRangeTest.java index 73af6f6e..8036f13f 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRangeTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRangeTest.java @@ -3,71 +3,69 @@ import java.util.Arrays; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class EncodableOptimizedFixedRangeTest { private EncodableOptimizedFixedRange encodableOptimizedFixedRange = new EncodableOptimizedFixedRange(); @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { encodableOptimizedFixedRange.setValue(Arrays.asList(12, 24, 48)); Assertions.assertEquals("00000000001100000000000000001000000000001000000000000000000000001", encodableOptimizedFixedRange.encode()); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { encodableOptimizedFixedRange.setValue(Arrays.asList(18, 30)); Assertions.assertEquals("00000000000111100000000000000000001000000000001", encodableOptimizedFixedRange.encode()); } @Test - public void testEncode3() throws EncodingException { + public void testEncode3() { encodableOptimizedFixedRange.setValue(Arrays.asList(28)); Assertions.assertEquals("000000000001110000000000000000000000000000001", encodableOptimizedFixedRange.encode()); } @Test - public void testEncode4() throws EncodingException { + public void testEncode4() { encodableOptimizedFixedRange.setValue(Arrays.asList(29)); Assertions.assertEquals("0000000000011101100000000000100000000000011101", encodableOptimizedFixedRange.encode()); } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { encodableOptimizedFixedRange.decode("00000000001100000000000000001000000000001000000000000000000000001"); Assertions.assertEquals(Arrays.asList(12, 24, 48), encodableOptimizedFixedRange.getValue()); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { encodableOptimizedFixedRange.decode("00000000000111100000000000000000001000000000001"); Assertions.assertEquals(Arrays.asList(18, 30), encodableOptimizedFixedRange.getValue()); } @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { encodableOptimizedFixedRange.decode("000000000001110000000000000000000000000000001"); Assertions.assertEquals(Arrays.asList(28), encodableOptimizedFixedRange.getValue()); } @Test - public void testDecode4() throws DecodingException { + public void testDecode4() { encodableOptimizedFixedRange.decode("0000000000011101100000000000100000000000011101"); Assertions.assertEquals(Arrays.asList(29), encodableOptimizedFixedRange.getValue()); } @Test - public void testSubstring1() throws DecodingException { + public void testSubstring1() { Assertions.assertEquals("000000000001110000000000000000000000000000001", encodableOptimizedFixedRange.substring( "000010001111010010000110111111111100000000001111010010000110111111111100000000000000000000000000000000000000000100001101000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000000000000000000000000001000000000000000000000000000000", 213)); } @Test - public void testSubstring2() throws DecodingException { + public void testSubstring2() { Assertions.assertEquals("0000000000011101100000000000100000000000011101", encodableOptimizedFixedRange.substring( "000010001111010010000110111111111100000000001111010010000110111111111100000000000000000000000000000000000000000100001101000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110110000000000010000000000001110100000000000000000000000000000", 213)); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoderTest.java index 3d1450f5..fea6ee70 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/BooleanEncoderTest.java @@ -3,27 +3,26 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class BooleanEncoderTest { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { Assertions.assertEquals("0", BooleanEncoder.encode(false)); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { Assertions.assertEquals("1", BooleanEncoder.encode(true)); } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { Assertions.assertEquals(false, BooleanEncoder.decode("0")); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { Assertions.assertEquals(true, BooleanEncoder.decode("1")); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoderTest.java index 77b5c9cf..9ded962f 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoderTest.java @@ -5,77 +5,76 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class FixedBitfieldEncoderTest { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { Assertions.assertEquals("00", FixedBitfieldEncoder.encode(new ArrayList<>(), 2)); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { Assertions.assertEquals("0", FixedBitfieldEncoder.encode(Arrays.asList(false), 1)); } @Test - public void testEncode3() throws EncodingException { + public void testEncode3() { Assertions.assertEquals("1", FixedBitfieldEncoder.encode(Arrays.asList(true), 1)); } @Test - public void testEncode4() throws EncodingException { + public void testEncode4() { Assertions.assertEquals("00", FixedBitfieldEncoder.encode(Arrays.asList(false, false), 2)); } @Test - public void testEncode5() throws EncodingException { + public void testEncode5() { Assertions.assertEquals("01", FixedBitfieldEncoder.encode(Arrays.asList(false, true), 2)); } @Test - public void testEncode6() throws EncodingException { + public void testEncode6() { Assertions.assertEquals("10", FixedBitfieldEncoder.encode(Arrays.asList(true, false), 2)); } @Test - public void testEncode7() throws EncodingException { + public void testEncode7() { Assertions.assertEquals("11", FixedBitfieldEncoder.encode(Arrays.asList(true, true), 2)); } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { Assertions.assertEquals(new ArrayList<>(), FixedBitfieldEncoder.decode("")); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { Assertions.assertEquals(Arrays.asList(false), FixedBitfieldEncoder.decode("0")); } @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { Assertions.assertEquals(Arrays.asList(true), FixedBitfieldEncoder.decode("1")); } @Test - public void testDecode4() throws DecodingException { + public void testDecode4() { Assertions.assertEquals(Arrays.asList(false, false), FixedBitfieldEncoder.decode("00")); } @Test - public void testDecode5() throws DecodingException { + public void testDecode5() { Assertions.assertEquals(Arrays.asList(false, true), FixedBitfieldEncoder.decode("01")); } @Test - public void testDecode6() throws DecodingException { + public void testDecode6() { Assertions.assertEquals(Arrays.asList(true, false), FixedBitfieldEncoder.decode("10")); } @Test - public void testDecode7() throws DecodingException { + public void testDecode7() { Assertions.assertEquals(Arrays.asList(true, true), FixedBitfieldEncoder.decode("11")); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoderTest.java index 2c95b455..df656eeb 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoderTest.java @@ -5,182 +5,181 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; public class FixedIntegerListEncoderTest { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { Assertions.assertEquals("0000", FixedIntegerListEncoder.encode(new ArrayList<>(), 2, 2)); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { Assertions.assertEquals("0000", FixedIntegerListEncoder.encode(Arrays.asList(0), 2, 2)); } @Test - public void testEncode3() throws EncodingException { + public void testEncode3() { Assertions.assertEquals("0000", FixedIntegerListEncoder.encode(Arrays.asList(0, 0), 2, 2)); } @Test - public void testEncode4() throws EncodingException { + public void testEncode4() { Assertions.assertEquals("0001", FixedIntegerListEncoder.encode(Arrays.asList(0, 1), 2, 2)); } @Test - public void testEncode5() throws EncodingException { + public void testEncode5() { Assertions.assertEquals("0010", FixedIntegerListEncoder.encode(Arrays.asList(0, 2), 2, 2)); } @Test - public void testEncode6() throws EncodingException { + public void testEncode6() { Assertions.assertEquals("0011", FixedIntegerListEncoder.encode(Arrays.asList(0, 3), 2, 2)); } @Test - public void testEncode7() throws EncodingException { + public void testEncode7() { Assertions.assertEquals("0100", FixedIntegerListEncoder.encode(Arrays.asList(1, 0), 2, 2)); } @Test - public void testEncode8() throws EncodingException { + public void testEncode8() { Assertions.assertEquals("0101", FixedIntegerListEncoder.encode(Arrays.asList(1, 1), 2, 2)); } @Test - public void testEncode9() throws EncodingException { + public void testEncode9() { Assertions.assertEquals("0110", FixedIntegerListEncoder.encode(Arrays.asList(1, 2), 2, 2)); } @Test - public void testEncode10() throws EncodingException { + public void testEncode10() { Assertions.assertEquals("0111", FixedIntegerListEncoder.encode(Arrays.asList(1, 3), 2, 2)); } @Test - public void testEncode11() throws EncodingException { + public void testEncode11() { Assertions.assertEquals("1000", FixedIntegerListEncoder.encode(Arrays.asList(2, 0), 2, 2)); } @Test - public void testEncode12() throws EncodingException { + public void testEncode12() { Assertions.assertEquals("1001", FixedIntegerListEncoder.encode(Arrays.asList(2, 1), 2, 2)); } @Test - public void testEncode13() throws EncodingException { + public void testEncode13() { Assertions.assertEquals("1010", FixedIntegerListEncoder.encode(Arrays.asList(2, 2), 2, 2)); } @Test - public void testEncode14() throws EncodingException { + public void testEncode14() { Assertions.assertEquals("1011", FixedIntegerListEncoder.encode(Arrays.asList(2, 3), 2, 2)); } @Test - public void testEncode15() throws EncodingException { + public void testEncode15() { Assertions.assertEquals("1100", FixedIntegerListEncoder.encode(Arrays.asList(3, 0), 2, 2)); } @Test - public void testEncode16() throws EncodingException { + public void testEncode16() { Assertions.assertEquals("1101", FixedIntegerListEncoder.encode(Arrays.asList(3, 1), 2, 2)); } @Test - public void testEncode17() throws EncodingException { + public void testEncode17() { Assertions.assertEquals("1110", FixedIntegerListEncoder.encode(Arrays.asList(3, 2), 2, 2)); } @Test - public void testEncode18() throws EncodingException { + public void testEncode18() { Assertions.assertEquals("1111", FixedIntegerListEncoder.encode(Arrays.asList(3, 3), 2, 2)); } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { Assertions.assertEquals(Arrays.asList(0, 0), FixedIntegerListEncoder.decode("", 2, 2)); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { Assertions.assertEquals(Arrays.asList(0, 0), FixedIntegerListEncoder.decode("0000", 2, 2)); } @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { Assertions.assertEquals(Arrays.asList(0, 1), FixedIntegerListEncoder.decode("0001", 2, 2)); } @Test - public void testDecode4() throws DecodingException { + public void testDecode4() { Assertions.assertEquals(Arrays.asList(0, 2), FixedIntegerListEncoder.decode("0010", 2, 2)); } @Test - public void testDecode5() throws DecodingException { + public void testDecode5() { Assertions.assertEquals(Arrays.asList(0, 3), FixedIntegerListEncoder.decode("0011", 2, 2)); } @Test - public void testDecode6() throws DecodingException { + public void testDecode6() { Assertions.assertEquals(Arrays.asList(1, 0), FixedIntegerListEncoder.decode("0100", 2, 2)); } @Test - public void testDecode7() throws DecodingException { + public void testDecode7() { Assertions.assertEquals(Arrays.asList(1, 1), FixedIntegerListEncoder.decode("0101", 2, 2)); } @Test - public void testDecode8() throws DecodingException { + public void testDecode8() { Assertions.assertEquals(Arrays.asList(1, 2), FixedIntegerListEncoder.decode("0110", 2, 2)); } @Test - public void testDecode9() throws DecodingException { + public void testDecode9() { Assertions.assertEquals(Arrays.asList(1, 3), FixedIntegerListEncoder.decode("0111", 2, 2)); } @Test - public void testDecode10() throws DecodingException { + public void testDecode10() { Assertions.assertEquals(Arrays.asList(2, 0), FixedIntegerListEncoder.decode("1000", 2, 2)); } @Test - public void testDecode11() throws DecodingException { + public void testDecode11() { Assertions.assertEquals(Arrays.asList(2, 1), FixedIntegerListEncoder.decode("1001", 2, 2)); } @Test - public void testDecode12() throws DecodingException { + public void testDecode12() { Assertions.assertEquals(Arrays.asList(2, 2), FixedIntegerListEncoder.decode("1010", 2, 2)); } @Test - public void testDecode13() throws DecodingException { + public void testDecode13() { Assertions.assertEquals(Arrays.asList(2, 3), FixedIntegerListEncoder.decode("1011", 2, 2)); } @Test - public void testDecode14() throws DecodingException { + public void testDecode14() { Assertions.assertEquals(Arrays.asList(3, 0), FixedIntegerListEncoder.decode("1100", 2, 2)); } @Test - public void testDecode15() throws DecodingException { + public void testDecode15() { Assertions.assertEquals(Arrays.asList(3, 1), FixedIntegerListEncoder.decode("1101", 2, 2)); } @Test - public void testDecode16() throws DecodingException { + public void testDecode16() { Assertions.assertEquals(Arrays.asList(3, 2), FixedIntegerListEncoder.decode("1110", 2, 2)); } @Test - public void testDecode17() throws DecodingException { + public void testDecode17() { Assertions.assertEquals(Arrays.asList(3, 3), FixedIntegerListEncoder.decode("1111", 2, 2)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoderTest.java index aba5ee84..4fef7dcc 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedStringEncoderTest.java @@ -8,12 +8,12 @@ public class FixedStringEncoderTest { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { Assertions.assertEquals("000000000001", FixedStringEncoder.encode("AB", 2)); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { Assertions.assertEquals("100000111111", FixedStringEncoder.encode("a", 2)); } @@ -28,12 +28,12 @@ public void testEncode3() { } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { Assertions.assertEquals("AB", FixedStringEncoder.decode("000000000001")); } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { Assertions.assertEquals("a", FixedStringEncoder.decode("100000111111")); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoderTest.java deleted file mode 100644 index a24cdf12..00000000 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/TraditionalBase64UrlEncoderTest.java +++ /dev/null @@ -1,42 +0,0 @@ -package com.iab.gpp.encoder.datatype.encoder; - -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; - -public class TraditionalBase64UrlEncoderTest { - - private TraditionalBase64UrlEncoder base64UrlEncoder = new TraditionalBase64UrlEncoder(); - - @Test - public void testEncode1() throws EncodingException { - Assertions.assertEquals("DBABMAAA", base64UrlEncoder.encode("0000110000010000000000010011")); - } - - @Test - public void testEncode2() throws EncodingException { - Assertions.assertEquals("DBACNYAA", base64UrlEncoder.encode("000011000001000000000010001101011")); - } - - @Test - public void testEncode3() throws EncodingException { - Assertions.assertEquals("DBABjwAA", base64UrlEncoder.encode("00001100000100000000000110001111")); - } - - @Test - public void testDecode1() throws DecodingException { - Assertions.assertEquals("000011000001000000000001001100000000000000000000", base64UrlEncoder.decode("DBABMAAA")); - } - - @Test - public void testDecode2() throws DecodingException { - Assertions.assertEquals("000011000001000000000010001101011000000000000000", base64UrlEncoder.decode("DBACNYAA")); - } - - @Test - public void testDecode3() throws DecodingException { - Assertions.assertEquals("000011000001000000000001100011110000000000000000", base64UrlEncoder.decode("DBABjwAA")); - } - -} diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/HeaderV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/HeaderV1Test.java index 4c74ec5a..16c365c5 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/HeaderV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/HeaderV1Test.java @@ -4,80 +4,32 @@ import java.util.Arrays; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; public class HeaderV1Test { @Test - public void testEncodeToBitString1() throws EncodingException, InvalidFieldException { - HeaderV1 headerV1 = new HeaderV1(); - headerV1.setFieldValue("SectionIds", new ArrayList<>()); - Assertions.assertEquals("000011000001000000000000", headerV1.encodeToBitString()); - } - - @Test - public void testEncodeToBitString2() throws EncodingException, InvalidFieldException { - HeaderV1 headerV1 = new HeaderV1(); - headerV1.setFieldValue("SectionIds", Arrays.asList(2)); - Assertions.assertEquals("0000110000010000000000010011", headerV1.encodeToBitString()); - } - - @Test - public void testEncodeToBitString3() throws EncodingException, InvalidFieldException { - HeaderV1 headerV1 = new HeaderV1(); - headerV1.setFieldValue("SectionIds", Arrays.asList(2, 6)); - Assertions.assertEquals("000011000001000000000010001101011", headerV1.encodeToBitString()); - } - - @Test - public void testDecodeFromBitString1() throws DecodingException { - HeaderV1 headerV1 = new HeaderV1(); - headerV1.decodeFromBitString("000011000001000000000000"); - Assertions.assertEquals(new ArrayList<>(), headerV1.getFieldValue("SectionIds")); - Assertions.assertEquals(headerV1.getFieldValue("SectionIds"), headerV1.getSectionsIds()); - } - - @Test - public void testDecodeFromBitString2() throws DecodingException { - HeaderV1 headerV1 = new HeaderV1(); - headerV1.decodeFromBitString("0000110000010000000000010011"); - Assertions.assertEquals(Arrays.asList(2), headerV1.getFieldValue("SectionIds")); - Assertions.assertEquals(headerV1.getFieldValue("SectionIds"), headerV1.getSectionsIds()); - } - - @Test - public void testDecodeFromBitString3() throws DecodingException { - HeaderV1 headerV1 = new HeaderV1(); - headerV1.decodeFromBitString("000001000011000000000010001101011"); - Assertions.assertEquals(Arrays.asList(2, 6), headerV1.getFieldValue("SectionIds")); - Assertions.assertEquals(headerV1.getFieldValue("SectionIds"), headerV1.getSectionsIds()); - } - - @Test - public void testEncode1() throws EncodingException, InvalidFieldException { + public void testEncode1() { HeaderV1 headerV1 = new HeaderV1(); headerV1.setFieldValue("SectionIds", new ArrayList<>()); Assertions.assertEquals("DBAA", headerV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { HeaderV1 headerV1 = new HeaderV1(); headerV1.setFieldValue("SectionIds", Arrays.asList(2)); Assertions.assertEquals("DBABMA", headerV1.encode()); } @Test - public void testEncode3() throws EncodingException, InvalidFieldException { + public void testEncode3() { HeaderV1 headerV1 = new HeaderV1(); headerV1.setFieldValue("SectionIds", Arrays.asList(2, 6)); Assertions.assertEquals("DBACNYA", headerV1.encode()); } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { HeaderV1 headerV1 = new HeaderV1(); headerV1.decode("DBAA"); Assertions.assertEquals(new ArrayList<>(), headerV1.getFieldValue("SectionIds")); @@ -86,7 +38,7 @@ public void testDecode1() throws DecodingException { } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { HeaderV1 headerV1 = new HeaderV1(); headerV1.decode("DBABMA"); Assertions.assertEquals(Arrays.asList(2), headerV1.getFieldValue("SectionIds")); @@ -95,7 +47,7 @@ public void testDecode2() throws DecodingException { } @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { HeaderV1 headerV1 = new HeaderV1(); headerV1.decode("DBACNYA"); Assertions.assertEquals(Arrays.asList(2, 6), headerV1.getFieldValue("SectionIds")); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java index eae50785..a1762dee 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java @@ -6,15 +6,12 @@ import java.util.Arrays; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.TcfCaV1Field; public class TcfCaV1Test { @Test - public void testEncode1() throws EncodingException, InvalidFieldException { + public void testEncode1() { TcfCaV1 tcfCaV1 = new TcfCaV1(); tcfCaV1.setFieldValue(TcfCaV1Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); @@ -23,7 +20,7 @@ public void testEncode1() throws EncodingException, InvalidFieldException { } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { TcfCaV1 tcfCaV1 = new TcfCaV1(); tcfCaV1.setFieldValue(TcfCaV1Field.CMP_ID, 50); @@ -57,7 +54,7 @@ public void testEncode2() throws EncodingException, InvalidFieldException { } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { TcfCaV1 tcfCaV1 = new TcfCaV1("CAAAAAAAAAAAAAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA"); Assertions.assertEquals(0, tcfCaV1.getCmpId()); @@ -99,7 +96,7 @@ public void testDecode1() throws DecodingException { } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { TcfCaV1 tcfCaV1 = new TcfCaV1("BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACAC.fHHHA4444ao"); Assertions.assertEquals(50, tcfCaV1.getCmpId()); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java index 20eb2a7b..b11dbdbc 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java @@ -6,15 +6,12 @@ import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.TcfEuV2Field; public class TcfEuV2Test { @Test - public void testEncode1() throws EncodingException, InvalidFieldException { + public void testEncode1() { TcfEuV2 tcfEuV2 = new TcfEuV2(); tcfEuV2.setFieldValue(TcfEuV2Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); tcfEuV2.setFieldValue(TcfEuV2Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); @@ -22,16 +19,30 @@ public void testEncode1() throws EncodingException, InvalidFieldException { } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { TcfEuV2 tcfEuV2 = new TcfEuV2(); tcfEuV2.setFieldValue(TcfEuV2Field.IS_SERVICE_SPECIFIC, true); tcfEuV2.setFieldValue(TcfEuV2Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); tcfEuV2.setFieldValue(TcfEuV2Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); + + Assertions.assertEquals(3, tcfEuV2.getFieldValue(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE)); + Assertions.assertEquals( + Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false), + tcfEuV2.getFieldValue(TcfEuV2Field.PUBLISHER_CONSENTS)); + Assertions.assertEquals( + Arrays.asList(false, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false), + tcfEuV2.getFieldValue(TcfEuV2Field.PUBLISHER_LEGITIMATE_INTERESTS)); + Assertions.assertEquals(0, tcfEuV2.getFieldValue(TcfEuV2Field.NUM_CUSTOM_PURPOSES)); + Assertions.assertEquals(Arrays.asList(), tcfEuV2.getFieldValue(TcfEuV2Field.PUBLISHER_CUSTOM_CONSENTS)); + Assertions.assertEquals(Arrays.asList(), tcfEuV2.getFieldValue(TcfEuV2Field.PUBLISHER_CUSTOM_LEGITIMATE_INTERESTS)); + Assertions.assertEquals("CPSG_8APSG_8AAAAAAENAACgAAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAAA", tcfEuV2.encode()); } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { TcfEuV2 tcfEuV2 = new TcfEuV2("CAAAAAAAAAAAAAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA"); Assertions.assertEquals(2, tcfEuV2.getVersion()); @@ -84,7 +95,7 @@ public void testDecode1() throws DecodingException { } @Test - public void testDecode2() throws DecodingException { + public void testDecode2() { TcfEuV2 tcfEuV2 = new TcfEuV2("CPSG_8APSG_8AAAAAAENAACgAAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAAA"); Assertions.assertEquals(2, tcfEuV2.getVersion()); @@ -138,7 +149,7 @@ public void testDecode2() throws DecodingException { @SuppressWarnings("unchecked") @Test - public void testDecode3() throws DecodingException { + public void testDecode3() { TcfEuV2 tcfEuV2 = new TcfEuV2( "CPcqBNJPcqBNJNwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA.QGLtV_T9fb2vj-_Z99_tkeYwf95y3p-wzhheMs-8NyZeH_B4Wv2MyvBX4JiQKGRgksjLBAQdtHGlcTQgBwIlViTLMYk2MjzNKJrJEilsbO2dYGD9Pn8HT3ZCY70-vv__7v3ff_3g.IGLtV_T9fb2vj-_Z99_tkeYwf95y3p-wzhheMs-8NyZeH_B4Wv2MyvBX4JiQKGRgksjLBAQdtHGlcTQgBwIlViTLMYk2MjzNKJrJEilsbO2dYGD9Pn8HT3ZCY70-vv__7v3ff_3g"); @@ -241,7 +252,7 @@ public void testDecode3() throws DecodingException { @SuppressWarnings("unchecked") @Test - public void testDecode4() throws DecodingException { + public void testDecode4() { TcfEuV2 tcfEuV2 = new TcfEuV2( "CPi8wgAPi8wgAAOACBENCuCoAP_AAEfAACiQJHNd_H__bX9n-f7_6ft0eY1f9_r37uQzDhfNk-8F3L_W_LwX_2E7NF36tq4KmR4ku1LBIUNtHMnUDUmxaokVrzHsak2cpzNKJ_BkknsZe2dYGF9vm5tj-QKZ7_5_d3f52T_9_9v-39z33913v3d93-_13LjdV5_9H_v9fR_b8_Kf9_5-_4v8_____3_e______8AEEggCTDVuIAuxLHAm0DCKBECMKwkKoFABBQDC0QGADg4KdlYBPrCBAAgFAEYEQIcAUYEAgAAAgCQiACQIsEAAAIgEAAIAEQiEABAwCCgAsDAIAAQDQMUQoABAkIMiAiKUwICIEggJbKhBKC6Q0wgCrLACgkRsFAAiAAAUgACAsHAMESAlYsECTFG-QAjBCgFEqFaAGGgAwABBI4RABgACCRwqADAAEEjgA"); @@ -278,7 +289,7 @@ public void testDecode4() throws DecodingException { @SuppressWarnings("unchecked") @Test - public void testDecode5() throws DecodingException { + public void testDecode5() { TcfEuV2 tcfEuV2 = new TcfEuV2( "CPgA5EAPgA5EAAOACBENCuCoAP_AAEfAACiQI0Nd_H__bX9n-f7_6Pt0cY1f9_r3ruQzDhfFk-8F3L_W3LwX32E7NF36pq4KmR4ku1LBIQFtHMnUDUmxaokVrzHsak2cpyNKI7BkknsZe2dYGF9Pm5lD-QKZ7_5_d3f52T_9_9v-39z339V3v3d93-_12PjdV599H_v9fR_b8_Kf9_5-_4v8___4IQAAAAQQ_AJMNW4gC7EscCbQMIoAQIwrCQqAUAEFAMLRAYAODgpmVgEusIEACAUARgRAhxBRgQCAAACAJCIAJAiwQAIAiAQAAgARAIQAEDAIKACwMAgABANAxACgAECQgyICIpTAgIgSCAlsqEEoKpDTCAKssAKARGwUACIAABSAAICwcAwRICViwQJMUbwAw0AGAAIJHCIAMAAQSOFQAYAAgkcA"); @@ -314,7 +325,7 @@ public void testDecode5() throws DecodingException { } @Test - public void testDecode6() throws DecodingException { + public void testDecode6() { TcfEuV2 tcfEuV2 = new TcfEuV2("COv_eg6Ov_eg6AOADBENAaCgAP_AAH_AACiQAVEUQQoAIQAqIoghAAQgAA.YAAAAAAAAAAAAAAAAAA"); Assertions.assertEquals(2, tcfEuV2.getFieldValue("Version")); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java index 1a10fa9e..f33a1e94 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java @@ -4,22 +4,19 @@ import java.util.Arrays; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.UsCaV1Field; public class UsCaV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UsCaV1 usCaV1 = new UsCaV1(); Assertions.assertEquals("BAAAAAAA.QA", usCaV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { UsCaV1 usCaV1 = new UsCaV1(); usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); @@ -39,7 +36,7 @@ public void testEncode2() throws EncodingException, InvalidFieldException { } @Test - public void testEncode3() throws EncodingException, InvalidFieldException { + public void testEncode3() { UsCaV1 usCaV1 = new UsCaV1(); usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); @@ -59,7 +56,7 @@ public void testEncode3() throws EncodingException, InvalidFieldException { } @Test - public void testEncodeWithGpcSegmentExcluded() throws EncodingException, InvalidFieldException { + public void testEncodeWithGpcSegmentExcluded() { UsCaV1 usCaV1 = new UsCaV1(); usCaV1.setFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED, false); @@ -67,7 +64,7 @@ public void testEncodeWithGpcSegmentExcluded() throws EncodingException, Invalid } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { UsCaV1 usCaV1 = new UsCaV1("BbYbGwXY.YA"); Assertions.assertEquals(1, usCaV1.getSaleOptOutNotice()); @@ -85,7 +82,7 @@ public void testDecode1() throws DecodingException { } @Test - public void testDecodeWithGpcSegmentExcluded() throws DecodingException { + public void testDecodeWithGpcSegmentExcluded() { UsCaV1 usCaV1 = new UsCaV1("BbYbGwXY"); Assertions.assertEquals(1, usCaV1.getSaleOptOutNotice()); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java index 9c730803..f00b108b 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java @@ -4,21 +4,18 @@ import java.util.Arrays; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.UsCoV1Field; public class UsCoV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UsCoV1 usCoV1 = new UsCoV1(); Assertions.assertEquals("BAAAAAA.QA", usCoV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { UsCoV1 usCoV1 = new UsCoV1(); usCoV1.setFieldValue(UsCoV1Field.SHARING_NOTICE, 1); @@ -37,14 +34,14 @@ public void testEncode2() throws EncodingException, InvalidFieldException { } @Test - public void testEncodeWithGpcSegmentExcluded() throws EncodingException, InvalidFieldException { + public void testEncodeWithGpcSegmentExcluded() { UsCoV1 usCoV1 = new UsCoV1(); usCoV1.setFieldValue(UsCoV1Field.GPC_SEGMENT_INCLUDED, false); Assertions.assertEquals("BAAAAAA", usCoV1.encode()); } @Test - public void testDecode1() throws DecodingException { + public void testDecode1() { UsCoV1 usCoV1 = new UsCoV1("BbYbG2wA.YA"); Assertions.assertEquals(1, usCoV1.getSharingNotice()); @@ -61,7 +58,7 @@ public void testDecode1() throws DecodingException { } @Test - public void testDecodeWithGpcSegmentExcluded() throws DecodingException { + public void testDecodeWithGpcSegmentExcluded() { UsCoV1 usCoV1 = new UsCoV1("BbYbG2wA"); Assertions.assertEquals(1, usCoV1.getSharingNotice()); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java index 2053e24c..864a1966 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java @@ -5,20 +5,18 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.UsCtV1Field; public class UsCtV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UsCtV1 usCtV1 = new UsCtV1(); Assertions.assertEquals("BAAAAAAA.QA", usCtV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { UsCtV1 usCtV1 = new UsCtV1(); usCtV1.setFieldValue(UsCtV1Field.SHARING_NOTICE, 1); @@ -37,7 +35,7 @@ public void testEncode2() throws EncodingException, InvalidFieldException { } @Test - public void testEncodeWithGpcSegmentExcluded() throws EncodingException, InvalidFieldException { + public void testEncodeWithGpcSegmentExcluded() { UsCtV1 usCtV1 = new UsCtV1(); usCtV1.setFieldValue(UsCtV1Field.GPC_SEGMENT_INCLUDED, false); Assertions.assertEquals("BAAAAAAA", usCtV1.encode()); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java index f0707542..379752e6 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java @@ -5,21 +5,19 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.UsNatV1Field; public class UsNatV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UsNatV1 usNatV1 = new UsNatV1(); Assertions.assertEquals("BAAAAAAAAAA.QA", usNatV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { UsNatV1 usNatV1 = new UsNatV1(); usNatV1.setFieldValue(UsNatV1Field.SHARING_NOTICE, 1); @@ -43,7 +41,7 @@ public void testEncode2() throws EncodingException, InvalidFieldException { } @Test - public void testEncode3() throws EncodingException, InvalidFieldException { + public void testEncode3() { UsNatV1 usNatV1 = new UsNatV1(); usNatV1.setFieldValue(UsNatV1Field.SHARING_NOTICE, 1); @@ -67,7 +65,7 @@ public void testEncode3() throws EncodingException, InvalidFieldException { } @Test - public void testEncodeWithGpcSegmentIncluded() throws EncodingException, InvalidFieldException { + public void testEncodeWithGpcSegmentIncluded() { UsNatV1 usNatV1 = new UsNatV1(); usNatV1.setFieldValue(UsNatV1Field.GPC_SEGMENT_INCLUDED, false); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java index f26808a6..ac647a6b 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java @@ -5,20 +5,18 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; -import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.UsUtV1Field; public class UsUtV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UsUtV1 usUtV1 = new UsUtV1(); Assertions.assertEquals("BAAAAAAA", usUtV1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { UsUtV1 usUtV1 = new UsUtV1(); usUtV1.setFieldValue(UsUtV1Field.SHARING_NOTICE, 1); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java index e65bec8c..06b5165f 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java @@ -12,13 +12,13 @@ public class UsVaV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UsVaV1 usVaV1 = new UsVaV1(); Assertions.assertEquals("BAAAAAA", usVaV1.encode()); } @Test - public void testEncode2() throws EncodingException { + public void testEncode2() { UsVaV1 usVaV1 = new UsVaV1(); try { diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UspV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UspV1Test.java index 13eb280d..ffc7e741 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UspV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UspV1Test.java @@ -3,34 +3,33 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; public class UspV1Test { @Test - public void testEncode1() throws EncodingException { + public void testEncode1() { UspV1 uspv1 = new UspV1(); Assertions.assertEquals("1---", uspv1.encode()); } @Test - public void testEncode2() throws EncodingException, InvalidFieldException { + public void testEncode2() { UspV1 uspv1 = new UspV1(); - uspv1.setFieldValue("Notice", "Y"); - uspv1.setFieldValue("OptOutSale", "N"); - uspv1.setFieldValue("LspaCovered", "N"); + uspv1.setFieldValue("Notice", 'Y'); + uspv1.setFieldValue("OptOutSale", 'N'); + uspv1.setFieldValue("LspaCovered", 'N'); Assertions.assertEquals("1YNN", uspv1.encode()); } @Test - public void testEncode3() throws EncodingException, InvalidFieldException { + public void testEncode3() { UspV1 uspv1 = new UspV1(); uspv1.setFieldValue("Version", 2); - uspv1.setFieldValue("Notice", "N"); - uspv1.setFieldValue("OptOutSale", "Y"); - uspv1.setFieldValue("LspaCovered", "Y"); + uspv1.setFieldValue("Notice", 'N'); + uspv1.setFieldValue("OptOutSale", 'Y'); + uspv1.setFieldValue("LspaCovered", 'Y'); Assertions.assertEquals("2NYY", uspv1.encode()); } @@ -39,9 +38,9 @@ public void testEncode3() throws EncodingException, InvalidFieldException { public void testDecode1() throws DecodingException, InvalidFieldException { UspV1 uspv1 = new UspV1("1NYN"); Assertions.assertEquals(1, uspv1.getFieldValue("Version")); - Assertions.assertEquals("N", uspv1.getFieldValue("Notice")); - Assertions.assertEquals("Y", uspv1.getFieldValue("OptOutSale")); - Assertions.assertEquals("N", uspv1.getFieldValue("LspaCovered")); + Assertions.assertEquals('N', uspv1.getFieldValue("Notice")); + Assertions.assertEquals('Y', uspv1.getFieldValue("OptOutSale")); + Assertions.assertEquals('N', uspv1.getFieldValue("LspaCovered")); Assertions.assertEquals(uspv1.getFieldValue("Version"), uspv1.getVersion()); Assertions.assertEquals(uspv1.getFieldValue("Notice"), uspv1.getNotice()); @@ -51,11 +50,11 @@ public void testDecode1() throws DecodingException, InvalidFieldException { @Test public void testDecode2() throws DecodingException, InvalidFieldException { - UspV1 uspv1 = new UspV1("2YNY"); - Assertions.assertEquals(2, uspv1.getFieldValue("Version")); - Assertions.assertEquals("Y", uspv1.getFieldValue("Notice")); - Assertions.assertEquals("N", uspv1.getFieldValue("OptOutSale")); - Assertions.assertEquals("Y", uspv1.getFieldValue("LspaCovered")); + UspV1 uspv1 = new UspV1("1YNY"); + Assertions.assertEquals(1, uspv1.getFieldValue("Version")); + Assertions.assertEquals('Y', uspv1.getFieldValue("Notice")); + Assertions.assertEquals('N', uspv1.getFieldValue("OptOutSale")); + Assertions.assertEquals('Y', uspv1.getFieldValue("LspaCovered")); Assertions.assertEquals(uspv1.getFieldValue("Version"), uspv1.getVersion()); Assertions.assertEquals(uspv1.getFieldValue("Notice"), uspv1.getNotice()); From 6eccd6d68d997c0603d28dd8127cbeeab01f28ea Mon Sep 17 00:00:00 2001 From: chad Date: Wed, 6 Sep 2023 05:43:53 -0600 Subject: [PATCH 06/36] tests for null and empty string constructor arguments --- .../java/com/iab/gpp/encoder/GppModelTest.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index 8538f47d..2799e551 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -671,6 +671,24 @@ public void testConsistency() { } + @Test + public void testNullConstructor() { + GppModel gppModel = new GppModel(null); + Assertions.assertEquals("DBAA", gppModel.encode()); + + gppModel.setFieldValue("uspv1", UspV1Field.NOTICE, 'Y'); + Assertions.assertEquals("DBABTA~1Y--", gppModel.encode()); + } + + @Test + public void testEmptyStringConstructor() { + GppModel gppModel = new GppModel(""); + Assertions.assertEquals("DBAA", gppModel.encode()); + + gppModel.setFieldValue("uspv1", UspV1Field.NOTICE, 'Y'); + Assertions.assertEquals("DBABTA~1Y--", gppModel.encode()); + } + @Test public void testDecodingNull() { GppModel gppModel = new GppModel("DBABTA~1---"); From 11376528fcb40b237f7d493a52bd6af2af85d3b7 Mon Sep 17 00:00:00 2001 From: chad Date: Sun, 10 Sep 2023 19:40:58 -0600 Subject: [PATCH 07/36] validation --- .../AbstractEncodableBitStringDataType.java | 29 +- .../encoder/datatype/EncodableBoolean.java | 1 - .../encoder/datatype/EncodableDatetime.java | 7 +- .../datatype/EncodableFibonacciInteger.java | 6 + .../EncodableFibonacciIntegerRange.java | 7 +- .../datatype/EncodableFixedBitfield.java | 1 - .../datatype/EncodableFixedInteger.java | 13 +- .../datatype/EncodableFixedIntegerList.java | 15 +- .../datatype/EncodableFixedIntegerRange.java | 7 +- .../datatype/EncodableFixedString.java | 13 +- .../datatype/EncodableFlexibleBitfield.java | 1 - .../EncodableOptimizedFibonacciRange.java | 6 + .../EncodableOptimizedFixedRange.java | 6 + .../datatype/UnencodableCharacter.java | 27 +- .../encoder/datatype/UnencodableInteger.java | 27 +- .../encoder/FixedBitfieldEncoder.java | 5 + .../datatype/encoder/FixedIntegerEncoder.java | 9 +- .../encoder/FixedIntegerListEncoder.java | 5 + .../datatype/encoder/FixedLongEncoder.java | 6 + .../encoder/error/ValidationException.java | 18 + .../AbstractLazilyEncodableSegment.java | 10 +- .../gpp/encoder/segment/EncodableSegment.java | 4 +- .../encoder/segment/HeaderV1CoreSegment.java | 1 + .../encoder/segment/UsCaV1CoreSegment.java | 131 +++- .../encoder/segment/UsCoV1CoreSegment.java | 101 ++- .../encoder/segment/UsCtV1CoreSegment.java | 108 +++- .../encoder/segment/UsNatV1CoreSegment.java | 177 ++++- .../encoder/segment/UsUtV1CoreSegment.java | 108 +++- .../encoder/segment/UsVaV1CoreSegment.java | 105 ++- .../gpp/encoder/segment/UspV1CoreSegment.java | 8 +- .../com/iab/gpp/encoder/GppModelTest.java | 2 +- .../encoder/FixedBitfieldEncoderTest.java | 11 + .../encoder/FixedIntegerEncoderTest.java | 11 + .../encoder/FixedIntegerListEncoderTest.java | 11 + .../encoder/FixedLongEncoderTest.java | 12 + .../iab/gpp/encoder/section/UsCaV1Test.java | 486 +++++++++++++- .../iab/gpp/encoder/section/UsCoV1Test.java | 388 ++++++++++- .../iab/gpp/encoder/section/UsCtV1Test.java | 386 ++++++++++- .../iab/gpp/encoder/section/UsNatV1Test.java | 606 ++++++++++++++++-- .../iab/gpp/encoder/section/UsUtV1Test.java | 375 ++++++++++- .../iab/gpp/encoder/section/UsVaV1Test.java | 368 ++++++++++- 41 files changed, 3359 insertions(+), 259 deletions(-) create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/ValidationException.java 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 12a6011b..b286f397 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 @@ -1,12 +1,26 @@ package com.iab.gpp.encoder.datatype; +import java.util.Collection; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import com.iab.gpp.encoder.error.ValidationException; + public abstract class AbstractEncodableBitStringDataType implements EncodableDataType { + protected Predicate validator; protected T value; protected AbstractEncodableBitStringDataType() { - + this.validator = v -> true; + } + + protected AbstractEncodableBitStringDataType(Predicate validator) { + this.validator = validator; } + public void setValidator(Predicate validator) { + this.validator = validator; + } + public boolean hasValue() { return this.value != null; } @@ -17,7 +31,18 @@ public T getValue() { @SuppressWarnings("unchecked") public void setValue(Object value) { - this.value = (T) value; + T v = (T) value; + if (validator.test(v)) { + this.value = v; + } else { + if (v instanceof Collection) { + throw new ValidationException("Invalid value '" + + ((Collection) v).stream().map(i -> i.toString()).collect(Collectors.joining(",")) + "'"); + } else { + throw new ValidationException("Invalid value '" + v + "'"); + } + } + } public abstract String substring(String str, int fromIndex); 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 a8f0b601..54211270 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 @@ -22,7 +22,6 @@ public void decode(String bitString) { } public String substring(String bitString, int fromIndex) { - // TODO: validate return bitString.substring(fromIndex, fromIndex + 1); } } 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 4fdfd447..9404b31b 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,6 +1,7 @@ package com.iab.gpp.encoder.datatype; import java.time.ZonedDateTime; +import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.DatetimeEncoder; public class EncodableDatetime extends AbstractEncodableBitStringDataType { @@ -13,6 +14,11 @@ public EncodableDatetime(ZonedDateTime value) { super(); setValue(value); } + + public EncodableDatetime(ZonedDateTime value, Predicate validator) { + super(validator); + setValue(value); + } public String encode() { return DatetimeEncoder.encode(this.value); @@ -23,7 +29,6 @@ public void decode(String bitString) { } public String substring(String bitString, int fromIndex) { - // TODO: validate return bitString.substring(fromIndex, fromIndex + 36); } } 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 dc413368..6f49714e 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,5 +1,6 @@ package com.iab.gpp.encoder.datatype; +import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerEncoder; public class EncodableFibonacciInteger extends AbstractEncodableBitStringDataType { @@ -13,6 +14,11 @@ public EncodableFibonacciInteger(Integer value) { setValue(value); } + public EncodableFibonacciInteger(Integer value, Predicate validator) { + super(validator); + setValue(value); + } + public String encode() { return FibonacciIntegerEncoder.encode(this.value); } 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 48d69559..55b10474 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 @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; +import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerRangeEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.error.DecodingException; @@ -18,6 +19,11 @@ public EncodableFibonacciIntegerRange(List value) { setValue(value); } + public EncodableFibonacciIntegerRange(List value, Predicate> validator) { + super(validator); + setValue(value); + } + public String encode() { return FibonacciIntegerRangeEncoder.encode(this.value); } @@ -27,7 +33,6 @@ public void decode(String bitString) { } public String substring(String bitString, int fromIndex) throws DecodingException { - // TODO: add some validation int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 12)); int index = fromIndex + 12; for (int i = 0; i < count; i++) { 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 5f4cd5e4..e723cf79 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 @@ -28,7 +28,6 @@ public void decode(String bitString) { } public String substring(String bitString, int fromIndex) { - // TODO: validate return bitString.substring(fromIndex, fromIndex + this.numElements); } 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 05802f65..c0ad3296 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,5 +1,6 @@ package com.iab.gpp.encoder.datatype; +import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; public class EncodableFixedInteger extends AbstractEncodableBitStringDataType { @@ -17,6 +18,17 @@ public EncodableFixedInteger(int bitStringLength, Integer value) { setValue(value); } + protected EncodableFixedInteger(int bitStringLength, Predicate validator) { + super(validator); + this.bitStringLength = bitStringLength; + } + + public EncodableFixedInteger(int bitStringLength, Integer value, Predicate validator) { + super(validator); + this.bitStringLength = bitStringLength; + setValue(value); + } + public String encode() { return FixedIntegerEncoder.encode(this.value, this.bitStringLength); } @@ -26,7 +38,6 @@ public void decode(String bitString) { } public String substring(String bitString, int fromIndex) { - // TODO: validate return bitString.substring(fromIndex, fromIndex + this.bitStringLength); } } 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 9ac06346..b8762014 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,6 +2,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerListEncoder; public class EncodableFixedIntegerList extends AbstractEncodableBitStringDataType> { @@ -22,6 +23,19 @@ public EncodableFixedIntegerList(int elementBitStringLength, List value setValue(value); } + protected EncodableFixedIntegerList(int elementBitStringLength, int numElements, Predicate> validator) { + super(validator); + this.elementBitStringLength = elementBitStringLength; + this.numElements = numElements; + } + + public EncodableFixedIntegerList(int elementBitStringLength, List value, Predicate> validator) { + super(validator); + this.elementBitStringLength = elementBitStringLength; + this.numElements = value.size(); + setValue(value); + } + public String encode() { return FixedIntegerListEncoder.encode(this.value, this.elementBitStringLength, this.numElements); } @@ -31,7 +45,6 @@ public void decode(String bitString) { } public String substring(String bitString, int fromIndex) { - // TODO: validate return bitString.substring(fromIndex, fromIndex + (this.elementBitStringLength * numElements)); } 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 d78f5186..dfe188ec 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 @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; +import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; @@ -17,6 +18,11 @@ public EncodableFixedIntegerRange(List value) { setValue(value); } + public EncodableFixedIntegerRange(List value, Predicate> validator) { + super(validator); + setValue(value); + } + public String encode() { return FixedIntegerRangeEncoder.encode(this.value); } @@ -26,7 +32,6 @@ public void decode(String bitString) { } public String substring(String bitString, int fromIndex) { - // TODO: add some validation int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 12)); int index = fromIndex + 12; for (int i = 0; i < count; i++) { 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 f7c92665..d5ee908e 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,5 +1,6 @@ package com.iab.gpp.encoder.datatype; +import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FixedStringEncoder; public class EncodableFixedString extends AbstractEncodableBitStringDataType { @@ -17,6 +18,17 @@ public EncodableFixedString(int stringLength, String value) { setValue(value); } + protected EncodableFixedString(int stringLength, Predicate validator) { + super(validator); + this.stringLength = stringLength; + } + + public EncodableFixedString(int stringLength, String value, Predicate validator) { + super(validator); + this.stringLength = stringLength; + setValue(value); + } + public String encode() { return FixedStringEncoder.encode(this.value, this.stringLength); } @@ -26,7 +38,6 @@ public void decode(String bitString) { } public String substring(String bitString, int fromIndex) { - // TODO: validate return bitString.substring(fromIndex, fromIndex + this.stringLength * 6); } } 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 b38235ac..ec1ee316 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 @@ -29,7 +29,6 @@ public void decode(String bitString) { } public String substring(String bitString, int fromIndex) { - // TODO: validate return bitString.substring(fromIndex, fromIndex + this.getLengthSupplier.getAsInt()); } 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 891ff673..4d58f860 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 @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; +import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerRangeEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; @@ -19,6 +20,11 @@ public EncodableOptimizedFibonacciRange(List value) { setValue(value); } + public EncodableOptimizedFibonacciRange(List value, Predicate> validator) { + super(validator); + setValue(value); + } + public String encode() { // 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 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 9dbbf5ae..d2325706 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 @@ -3,6 +3,7 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; +import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; @@ -18,6 +19,11 @@ public EncodableOptimizedFixedRange(List value) { setValue(value); } + public EncodableOptimizedFixedRange(List value, Predicate> validator) { + super(validator); + setValue(value); + } + public String encode() { // 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 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 31fd0caa..4ef9c256 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 @@ -1,13 +1,31 @@ package com.iab.gpp.encoder.datatype; +import java.util.function.Predicate; +import com.iab.gpp.encoder.error.ValidationException; + public class UnencodableCharacter implements DataType { + private Predicate validator; private Character value = null; + public UnencodableCharacter() { + this.validator = v -> true; + } + public UnencodableCharacter(Character value) { - this.value = value; + this.validator = v -> true; + setValue(value); } + public UnencodableCharacter(Character value, Predicate validator) { + this.validator = validator; + setValue(value); + } + + public void setValidator(Predicate validator) { + this.validator = validator; + } + @Override public boolean hasValue() { return this.value != null; @@ -20,7 +38,12 @@ public Character getValue() { @Override public void setValue(Object value) { - this.value = value.toString().charAt(0); + Character c = (Character)value.toString().charAt(0); + if(validator.test(c)) { + this.value = c; + } else { + throw new ValidationException("Invalid value '" + c + "'"); + } } } 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 7435ff2d..60dcddfd 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 @@ -1,13 +1,31 @@ package com.iab.gpp.encoder.datatype; +import java.util.function.Predicate; +import com.iab.gpp.encoder.error.ValidationException; + public class UnencodableInteger implements DataType { + private Predicate validator; private Integer value = null; + public UnencodableInteger() { + this.validator = v -> true; + } + public UnencodableInteger(Integer value) { - this.value = value; + this.validator = v -> true; + setValue(value); } + public UnencodableInteger(Integer value, Predicate validator) { + this.validator = validator; + setValue(value); + } + + public void setValidator(Predicate validator) { + this.validator = validator; + } + @Override public boolean hasValue() { return this.value != null; @@ -20,7 +38,12 @@ public Integer getValue() { @Override public void setValue(Object value) { - this.value = (Integer)value; + Integer i = (Integer)value; + if(validator.test(i)) { + this.value = i; + } else { + throw new ValidationException("Invalid value '" + i + "'"); + } } } 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 05c53dcd..6c922263 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 @@ -4,12 +4,17 @@ import java.util.List; import java.util.regex.Pattern; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class 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)); 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 2870af60..2c0da692 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 @@ -2,6 +2,7 @@ import java.util.regex.Pattern; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class FixedIntegerEncoder { @@ -20,6 +21,11 @@ public static String encode(int value, int bitStringLength) { value = value >> 1; } + if (bitString.length() > bitStringLength) { + throw new EncodingException( + "Numberic value '" + value + "' is too large for a bit string length of '" + bitStringLength + "'"); + } + while (bitString.length() < bitStringLength) { bitString = "0" + bitString; } @@ -31,9 +37,6 @@ public static int decode(String bitString) throws DecodingException { if (!BITSTRING_VERIFICATION_PATTERN.matcher(bitString).matches()) { throw new DecodingException("Undecodable FixedInteger '" + bitString + "'"); } - - // return parseInt(bitString, 2); - int value = 0; for (int i = 0; i < bitString.length(); i++) { 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 e130f50d..044dfe26 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 @@ -4,12 +4,17 @@ import java.util.List; import java.util.regex.Pattern; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class 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) { + 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); 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 76ef8baf..4d5a9ab5 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 @@ -2,6 +2,7 @@ import java.util.regex.Pattern; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class FixedLongEncoder { @@ -18,6 +19,11 @@ public static String encode(long value, int bitStringLength) { value = value >> 1; } + if (bitString.length() > bitStringLength) { + throw new EncodingException( + "Numberic value '" + value + "' is too large for a bit string length of '" + bitStringLength + "'"); + } + while (bitString.length() < bitStringLength) { bitString = "0" + bitString; } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/ValidationException.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/ValidationException.java new file mode 100644 index 00000000..733a740b --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/error/ValidationException.java @@ -0,0 +1,18 @@ +package com.iab.gpp.encoder.error; + +public class ValidationException extends DecodingException { + + private static final long serialVersionUID = 2098268445119981680L; + + public ValidationException(String msg) { + super(msg); + } + + public ValidationException(Exception e) { + super(e); + } + + public ValidationException(String msg, Exception e) { + super(msg, e); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java index 44e6bc9f..dc2d6c6b 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java @@ -21,7 +21,12 @@ public AbstractLazilyEncodableSegment() { protected abstract String encodeSegment(T fields); protected abstract void decodeSegment(String encodedString, T Fields); - + + @Override + public void validate() { + + } + public boolean hasField(String fieldName) { return this.fields.containsKey(fieldName); } @@ -57,6 +62,7 @@ public void setFieldValue(String fieldName, Object value) { public String encode() { if (this.encodedString == null || this.encodedString.isEmpty() || this.dirty) { + this.validate(); this.encodedString = encodeSegment(this.fields); this.dirty = false; this.decoded = true; @@ -71,5 +77,5 @@ public void decode(String encodedString) { this.decoded = false; } - + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java index abdde319..457328e7 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java @@ -5,7 +5,7 @@ public interface EncodableSegment { List getFieldNames(); - + boolean hasField(String fieldName); Object getFieldValue(String fieldName); @@ -15,4 +15,6 @@ public interface EncodableSegment { String encode(); void decode(String encodedString); + + void validate(); } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java index 44e18bbf..d8c9918c 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java @@ -41,6 +41,7 @@ protected EncodableBitStringFields initializeFields() { @Override protected String encodeSegment(EncodableBitStringFields fields) { + validate(); String bitString = bitStringEncoder.encode(fields, getFieldNames()); String encodedString = base64UrlEncoder.encode(bitString); return encodedString; diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java index 4350e694..41999f44 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java @@ -7,6 +7,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsCaV1Field; import com.iab.gpp.encoder.section.UsCaV1; @@ -29,23 +30,37 @@ public UsCaV1CoreSegment(String encodedString) { public List getFieldNames() { return UsCaV1Field.USCAV1_CORE_SEGMENT_FIELD_NAMES; } - + @Override protected EncodableBitStringFields initializeFields() { EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsCaV1Field.VERSION, new EncodableFixedInteger(6, UsCaV1.VERSION)); - fields.put(UsCaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCaV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCaV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); fields.put(UsCaV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0))); - fields.put(UsCaV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0), v -> { + for(Integer i : v) { + if(i < 0 || i > 2) { + return false; + } + } + return true; + })); + fields.put(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0), v -> { + for(Integer i : v) { + if(i < 0 || i > 2) { + return false; + } + } + return true; + })); + fields.put(UsCaV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1, (v -> v >= 1 && v <= 2))); + fields.put(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); return fields; } @@ -58,10 +73,100 @@ protected String encodeSegment(EncodableBitStringFields fields) { @Override protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { - if(encodedString == null || encodedString.isEmpty()) { + if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } + + @Override + public void validate() { + super.validate(); + Integer sharingOptOutNotice = ((EncodableFixedInteger) fields.get(UsCaV1Field.SHARING_OPT_OUT_NOTICE)).getValue(); + Integer sharingOptOut = ((EncodableFixedInteger) fields.get(UsCaV1Field.SHARING_OPT_OUT)).getValue(); + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCaV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCaV1Field.SALE_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = ((EncodableFixedInteger) fields.get(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = ((EncodableFixedInteger) fields.get(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + Integer sensitiveDataLimtUserNotice = ((EncodableFixedInteger) fields.get(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE)).getValue(); + + if (sharingOptOutNotice == 0) { + if (sharingOptOut != 0) { + throw new ValidationException("Invalid usca sharing notice / opt out combination: {" + + sharingOptOutNotice + " / " + sharingOptOut + "}"); + } + } else if (sharingOptOutNotice == 1) { + if (sharingOptOut != 1 && sharingOptOut != 2) { + throw new ValidationException("Invalid usca sharing notice / opt out combination: {" + + sharingOptOutNotice + " / " + sharingOptOut + "}"); + } + } else if (sharingOptOutNotice == 2) { + if (sharingOptOut != 1) { + throw new ValidationException("Invalid usca sharing notice / opt out combination: {" + + sharingOptOutNotice + " / " + sharingOptOut + "}"); + } + } + + if (saleOptOutNotice == 0) { + if (saleOptOut != 0) { + throw new ValidationException("Invalid usca sale notice / opt out combination: {" + + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usca sale notice / opt out combination: {" + + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usca sale notice / opt out combination: {" + + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } + + if (mspaServiceProviderMode == 0) { + if(saleOptOutNotice != 0) { + throw new ValidationException("Invalid usca mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + + if(sharingOptOutNotice != 0) { + throw new ValidationException("Invalid usca mspa service provider mode / sharing opt out notice combination: {" + + mspaServiceProviderMode + " / " + sharingOptOutNotice + "}"); + } + + if(sensitiveDataLimtUserNotice != 0) { + throw new ValidationException("Invalid usca mspa service provider mode / sensitive data limit use notice combination: {" + + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); + } + } else if (mspaServiceProviderMode == 1) { + if (mspaOptOutOptionMode != 2) { + throw new ValidationException("Invalid usca mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); + } + + if(saleOptOutNotice != 0) { + throw new ValidationException("Invalid usca mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + + if(sharingOptOutNotice != 0) { + throw new ValidationException("Invalid usca mspa service provider mode / sharing opt out notice combination: {" + + mspaServiceProviderMode + " / " + sharingOptOutNotice + "}"); + } + + if(sensitiveDataLimtUserNotice != 0) { + throw new ValidationException("Invalid usca mspa service provider mode / sensitive data limit use notice combination: {" + + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); + } + } else if (mspaServiceProviderMode == 2) { + if (mspaOptOutOptionMode != 1) { + throw new ValidationException("Invalid usca mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaOptOutOptionMode + "}"); + } + } + } + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java index 4885f8f6..4cbaff8e 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java @@ -7,6 +7,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsCoV1Field; import com.iab.gpp.encoder.section.UsCoV1; @@ -34,17 +35,26 @@ public List getFieldNames() { protected EncodableBitStringFields initializeFields() { EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsCoV1Field.VERSION, new EncodableFixedInteger(6, UsCoV1.VERSION)); - fields.put(UsCoV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCoV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCoV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCoV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); fields.put(UsCoV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0))); - fields.put(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0), v -> { + for(Integer i : v) { + if(i < 0 || i > 2) { + return false; + } + } + return true; + })); + fields.put(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCoV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1, (v -> v >= 1 && v <= 2))); + fields.put(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); return fields; } @@ -57,10 +67,79 @@ protected String encodeSegment(EncodableBitStringFields fields) { @Override protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { - if(encodedString == null || encodedString.isEmpty()) { + if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } + + @Override + public void validate() { + super.validate(); + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT)).getValue(); + Integer targetedAdvertisingOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = ((EncodableFixedInteger) fields.get(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = ((EncodableFixedInteger) fields.get(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + + if (saleOptOutNotice == 0) { + if (saleOptOut != 0) { + throw new ValidationException("Invalid usco sale notice / opt out combination: {" + + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usco sale notice / opt out combination: {" + + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usco sale notice / opt out combination: {" + + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } + + if (targetedAdvertisingOptOutNotice == 0) { + if (targetedAdvertisingOptOut != 0) { + throw new ValidationException("Invalid usco targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usco targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usco targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } + + if (mspaServiceProviderMode == 0) { + if(saleOptOutNotice != 0) { + throw new ValidationException("Invalid usco mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 1) { + if (mspaOptOutOptionMode != 2) { + throw new ValidationException("Invalid usco mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); + } + + if(saleOptOutNotice != 0) { + throw new ValidationException("Invalid usco mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 2) { + if (mspaOptOutOptionMode != 1) { + throw new ValidationException("Invalid usco mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaOptOutOptionMode + "}"); + } + } + } + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java index 22a44d61..ec9f6294 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java @@ -7,7 +7,9 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; +import com.iab.gpp.encoder.field.UsCoV1Field; import com.iab.gpp.encoder.field.UsCtV1Field; import com.iab.gpp.encoder.section.UsCtV1; @@ -34,18 +36,33 @@ public List getFieldNames() { protected EncodableBitStringFields initializeFields() { EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsCtV1Field.VERSION, new EncodableFixedInteger(6, UsCtV1.VERSION)); - fields.put(UsCtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsCtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); fields.put(UsCtV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0), v -> { + for(Integer i : v) { + if(i < 0 || i > 2) { + return false; + } + } + return true; + })); fields.put(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0))); - fields.put(UsCtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0), v -> { + for(Integer i : v) { + if(i < 0 || i > 2) { + return false; + } + } + return true; + })); + fields.put(UsCtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1, (v -> v >= 1 && v <= 2))); + fields.put(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); return fields; } @@ -58,10 +75,79 @@ protected String encodeSegment(EncodableBitStringFields fields) { @Override protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { - if(encodedString == null || encodedString.isEmpty()) { + if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } + + @Override + public void validate() { + super.validate(); + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT)).getValue(); + Integer targetedAdvertisingOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = ((EncodableFixedInteger) fields.get(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = ((EncodableFixedInteger) fields.get(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + + if (saleOptOutNotice == 0) { + if (saleOptOut != 0) { + throw new ValidationException("Invalid usct sale notice / opt out combination: {" + + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usct sale notice / opt out combination: {" + + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usct sale notice / opt out combination: {" + + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } + + if (targetedAdvertisingOptOutNotice == 0) { + if (targetedAdvertisingOptOut != 0) { + throw new ValidationException("Invalid usct targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usct targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usct targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } + + if (mspaServiceProviderMode == 0) { + if(saleOptOutNotice != 0) { + throw new ValidationException("Invalid usct mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 1) { + if (mspaOptOutOptionMode != 2) { + throw new ValidationException("Invalid usct mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); + } + + if(saleOptOutNotice != 0) { + throw new ValidationException("Invalid usct mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 2) { + if (mspaOptOutOptionMode != 1) { + throw new ValidationException("Invalid usct mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaOptOutOptionMode + "}"); + } + } + } + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java index ee664225..e4e6c951 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java @@ -7,6 +7,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsNatV1Field; import com.iab.gpp.encoder.section.UsNatV1; @@ -34,22 +35,39 @@ public List getFieldNames() { protected EncodableBitStringFields initializeFields() { EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsNatV1Field.VERSION, new EncodableFixedInteger(6, UsNatV1.VERSION)); - fields.put(UsNatV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsNatV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsNatV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsNatV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsNatV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsNatV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0))); - fields.put(UsNatV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), v -> { + for (Integer i : v) { + if (i < 0 || i > 2) { + return false; + } + } + return true; + })); + fields.put(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedIntegerList(2, Arrays.asList(0, 0), v -> { + for (Integer i : v) { + if (i < 0 || i > 2) { + return false; + } + } + return true; + })); + fields.put(UsNatV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsNatV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1, (v -> v >= 1 && v <= 2))); + fields.put(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); return fields; } @@ -62,10 +80,137 @@ protected String encodeSegment(EncodableBitStringFields fields) { @Override protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { - if(encodedString == null || encodedString.isEmpty()) { + if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } + + @Override + public void validate() { + super.validate(); + Integer sharingNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.SHARING_NOTICE)).getValue(); + Integer sharingOptOutNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.SHARING_OPT_OUT_NOTICE)).getValue(); + Integer sharingOptOut = ((EncodableFixedInteger) fields.get(UsNatV1Field.SHARING_OPT_OUT)).getValue(); + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsNatV1Field.SALE_OPT_OUT)).getValue(); + Integer targetedAdvertisingOptOutNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = ((EncodableFixedInteger) fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = ((EncodableFixedInteger) fields.get(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = ((EncodableFixedInteger) fields.get(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + Integer sensitiveDataLimtUserNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE)).getValue(); + + if (sharingNotice == 0) { + if (sharingOptOut != 0) { + throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" + + sharingNotice + " / " + sharingOptOut + "}"); + } + } else if (sharingNotice == 1) { + if (sharingOptOut != 1 && sharingOptOut != 2) { + throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" + + sharingNotice + " / " + sharingOptOut + "}"); + } + } else if (sharingNotice == 2) { + if (sharingOptOut != 1) { + throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" + + sharingNotice + " / " + sharingOptOut + "}"); + } + } + + if (sharingOptOutNotice == 0) { + if (sharingOptOut != 0) { + throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" + + sharingOptOutNotice + " / " + sharingOptOut + "}"); + } + } else if (sharingOptOutNotice == 1) { + if (sharingOptOut != 1 && sharingOptOut != 2) { + throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" + + sharingOptOutNotice + " / " + sharingOptOut + "}"); + } + } else if (sharingOptOutNotice == 2) { + if (sharingOptOut != 1) { + throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" + + sharingOptOutNotice + " / " + sharingOptOut + "}"); + } + } + + if (saleOptOutNotice == 0) { + if (saleOptOut != 0) { + throw new ValidationException("Invalid usnat sale notice / opt out combination: {" + + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usnat sale notice / opt out combination: {" + + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usnat sale notice / opt out combination: {" + + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } + + if (targetedAdvertisingOptOutNotice == 0) { + if (targetedAdvertisingOptOut != 0) { + throw new ValidationException("Invalid usnat targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usnat targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usnat targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } + + if (mspaServiceProviderMode == 0) { + if(saleOptOutNotice != 0) { + throw new ValidationException("Invalid usnat mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + + if(sharingOptOutNotice != 0) { + throw new ValidationException("Invalid usnat mspa service provider mode / sharing opt out notice combination: {" + + mspaServiceProviderMode + " / " + sharingOptOutNotice + "}"); + } + + if(sensitiveDataLimtUserNotice != 0) { + throw new ValidationException("Invalid usnat mspa service provider mode / sensitive data limit use notice combination: {" + + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); + } + } else if (mspaServiceProviderMode == 1) { + if (mspaOptOutOptionMode != 2) { + throw new ValidationException("Invalid usnat mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); + } + + if(saleOptOutNotice != 0) { + throw new ValidationException("Invalid usnat mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + + if(sharingOptOutNotice != 0) { + throw new ValidationException("Invalid usnat mspa service provider mode / sharing opt out notice combination: {" + + mspaServiceProviderMode + " / " + sharingOptOutNotice + "}"); + } + + if(sensitiveDataLimtUserNotice != 0) { + throw new ValidationException("Invalid usnat mspa service provider mode / sensitive data limit use notice combination: {" + + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); + } + } else if (mspaServiceProviderMode == 2) { + if (mspaOptOutOptionMode != 1) { + throw new ValidationException("Invalid usnat mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaOptOutOptionMode + "}"); + } + } + } + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java index 21c941b5..63f8e3ae 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java @@ -7,6 +7,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsUtV1Field; import com.iab.gpp.encoder.section.UsUtV1; @@ -34,18 +35,28 @@ public List getFieldNames() { protected EncodableBitStringFields initializeFields() { EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsUtV1Field.VERSION, new EncodableFixedInteger(6, UsUtV1.VERSION)); - fields.put(UsUtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsUtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsUtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsUtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0), v -> { + for (Integer i : v) { + if (i < 0 || i > 2) { + return false; + } + } + return true; + })); + fields.put(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsUtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1, (v -> v >= 1 && v <= 2))); + fields.put(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); return fields; } @@ -58,10 +69,83 @@ protected String encodeSegment(EncodableBitStringFields fields) { @Override protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { - if(encodedString == null || encodedString.isEmpty()) { + if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } + + @Override + public void validate() { + super.validate(); + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsUtV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsUtV1Field.SALE_OPT_OUT)).getValue(); + Integer targetedAdvertisingOptOutNotice = + ((EncodableFixedInteger) fields.get(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = + ((EncodableFixedInteger) fields.get(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = + ((EncodableFixedInteger) fields.get(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = + ((EncodableFixedInteger) fields.get(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + + if (saleOptOutNotice == 0) { + if (saleOptOut != 0) { + throw new ValidationException( + "Invalid usut sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException( + "Invalid usut sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException( + "Invalid usut sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } + + if (targetedAdvertisingOptOutNotice == 0) { + if (targetedAdvertisingOptOut != 0) { + throw new ValidationException("Invalid usut targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usut targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usut targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } + + if (mspaServiceProviderMode == 0) { + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usut mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 1) { + if (mspaOptOutOptionMode != 2) { + throw new ValidationException("Invalid usut mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); + } + + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usut mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 2) { + if (mspaOptOutOptionMode != 1) { + throw new ValidationException("Invalid usut mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaOptOutOptionMode + "}"); + } + } + } + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java index c52f7ba6..1a009e52 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java @@ -7,6 +7,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsVaV1Field; import com.iab.gpp.encoder.section.UsVaV1; @@ -34,17 +35,26 @@ public List getFieldNames() { protected EncodableBitStringFields initializeFields() { EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsVaV1Field.VERSION, new EncodableFixedInteger(6, UsVaV1.VERSION)); - fields.put(UsVaV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0)); + fields.put(UsVaV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsVaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsVaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); fields.put(UsVaV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0))); - fields.put(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0)); - fields.put(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0)); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0), v -> { + for (Integer i : v) { + if (i < 0 || i > 2) { + return false; + } + } + return true; + })); + fields.put(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, + new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsVaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1, (v -> v >= 1 && v <= 2))); + fields.put(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); return fields; } @@ -57,10 +67,83 @@ protected String encodeSegment(EncodableBitStringFields fields) { @Override protected void decodeSegment(String encodedString, EncodableBitStringFields fields) { - if(encodedString == null || encodedString.isEmpty()) { + if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } + + @Override + public void validate() { + super.validate(); + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsVaV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsVaV1Field.SALE_OPT_OUT)).getValue(); + Integer targetedAdvertisingOptOutNotice = + ((EncodableFixedInteger) fields.get(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = + ((EncodableFixedInteger) fields.get(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = + ((EncodableFixedInteger) fields.get(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = + ((EncodableFixedInteger) fields.get(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + + if (saleOptOutNotice == 0) { + if (saleOptOut != 0) { + throw new ValidationException( + "Invalid usva sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException( + "Invalid usva sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } else if (saleOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException( + "Invalid usva sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); + } + } + + if (targetedAdvertisingOptOutNotice == 0) { + if (targetedAdvertisingOptOut != 0) { + throw new ValidationException("Invalid usva targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 1) { + if (saleOptOut != 1 && saleOptOut != 2) { + throw new ValidationException("Invalid usva targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } else if (targetedAdvertisingOptOutNotice == 2) { + if (saleOptOut != 1) { + throw new ValidationException("Invalid usva targeted advertising notice / opt out combination: {" + + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); + } + } + + if (mspaServiceProviderMode == 0) { + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usva mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 1) { + if (mspaOptOutOptionMode != 2) { + throw new ValidationException("Invalid usva mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); + } + + if (saleOptOutNotice != 0) { + throw new ValidationException("Invalid usva mspa service provider mode / sale opt out notice combination: {" + + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); + } + } else if (mspaServiceProviderMode == 2) { + if (mspaOptOutOptionMode != 1) { + throw new ValidationException("Invalid usva mspa service provider / opt out option modes combination: {" + + mspaServiceProviderMode + " / " + mspaOptOutOptionMode + "}"); + } + } + } + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java index d7ec8525..6c07675d 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java @@ -28,9 +28,9 @@ public List getFieldNames() { protected GenericFields initializeFields() { GenericFields fields = new GenericFields(); fields.put(UspV1Field.VERSION, new UnencodableInteger(UspV1.VERSION)); - fields.put(UspV1Field.NOTICE, new UnencodableCharacter('-')); - fields.put(UspV1Field.OPT_OUT_SALE, new UnencodableCharacter('-')); - fields.put(UspV1Field.LSPA_COVERED, new UnencodableCharacter('-')); + fields.put(UspV1Field.NOTICE, new UnencodableCharacter('-', (v -> v == 'Y' || v == 'N' || v == '-'))); + fields.put(UspV1Field.OPT_OUT_SALE, new UnencodableCharacter('-', (v -> v == 'Y' || v == 'N' || v == '-'))); + fields.put(UspV1Field.LSPA_COVERED, new UnencodableCharacter('-', (v -> v == 'Y' || v == 'N' || v == '-'))); return fields; } @@ -49,7 +49,7 @@ protected void decodeSegment(String encodedString, GenericFields fields) { if (encodedString == null || encodedString.length() != 4) { throw new DecodingException("Invalid uspv1 string: '" + encodedString + "'"); } - + fields.get(UspV1Field.VERSION).setValue(Integer.parseInt(encodedString.substring(0, 1))); fields.get(UspV1Field.NOTICE).setValue(encodedString.charAt(1)); fields.get(UspV1Field.OPT_OUT_SALE).setValue(encodedString.charAt(2)); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index 2799e551..035f33ae 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -108,7 +108,7 @@ public void testEncodeDefaultAll() { String gppString = gppModel.encode(); Assertions.assertEquals( - "DBACOaw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAAA.QA~BAAAAAAA.QA~BAAAAAA~BAAAAAA.QA~BAAAAAAA~BAAAAAAA.QA", + "DBACOaw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAQA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA", gppString); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoderTest.java index 9ded962f..d66e3538 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedBitfieldEncoderTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class FixedBitfieldEncoderTest { @@ -43,6 +44,16 @@ public void testEncode7() { Assertions.assertEquals("11", FixedBitfieldEncoder.encode(Arrays.asList(true, true), 2)); } + @Test + public void testEncode8() { + try { + FixedBitfieldEncoder.encode(Arrays.asList(true, true, true), 2); + Assertions.fail("EncodingException expected"); + } catch (EncodingException e) { + + } + } + @Test public void testDecode1() { Assertions.assertEquals(new ArrayList<>(), FixedBitfieldEncoder.decode("")); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoderTest.java index cc8cc48b..a30b882b 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerEncoderTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class FixedIntegerEncoderTest { @@ -30,6 +31,16 @@ public void testEncode4() { public void testEncode5() { Assertions.assertEquals("00000111", FixedIntegerEncoder.encode(7, 8)); } + + @Test + public void testEncode6() { + try { + FixedIntegerEncoder.encode(8, 1); + Assertions.fail("EncodingException expected"); + } catch (EncodingException e) { + + } + } @Test public void testDecode1() throws DecodingException { diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoderTest.java index df656eeb..25de7e17 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedIntegerListEncoderTest.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class FixedIntegerListEncoderTest { @@ -98,6 +99,16 @@ public void testEncode18() { Assertions.assertEquals("1111", FixedIntegerListEncoder.encode(Arrays.asList(3, 3), 2, 2)); } + @Test + public void testEncode19() { + try { + FixedIntegerListEncoder.encode(Arrays.asList(3, 3), 1, 1); + Assertions.fail("EncodingException expected"); + } catch (EncodingException e) { + + } + } + @Test public void testDecode1() { Assertions.assertEquals(Arrays.asList(0, 0), FixedIntegerListEncoder.decode("", 2, 2)); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoderTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoderTest.java index b762f314..9a90a6dd 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoderTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/encoder/FixedLongEncoderTest.java @@ -3,6 +3,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class FixedLongEncoderTest { @@ -31,10 +32,21 @@ public void testEncode5() { Assertions.assertEquals("00000111", FixedLongEncoder.encode(7, 8)); } + @Test public void testEncode6() { Assertions.assertEquals("001111011111010001110101111011110101", FixedLongEncoder.encode(16630898421L, 36)); } + + @Test + public void testEncode7() { + try { + FixedIntegerEncoder.encode(8, 1); + Assertions.fail("EncodingException expected"); + } catch (EncodingException e) { + + } + } @Test public void testDecode1() throws DecodingException { diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java index f33a1e94..0022210c 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java @@ -4,6 +4,7 @@ import java.util.Arrays; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.UsCaV1Field; public class UsCaV1Test { @@ -12,7 +13,7 @@ public class UsCaV1Test { public void testEncode1() { UsCaV1 usCaV1 = new UsCaV1(); - Assertions.assertEquals("BAAAAAAA.QA", usCaV1.encode()); + Assertions.assertEquals("BAAAAABA.QA", usCaV1.encode()); } @Test @@ -20,19 +21,19 @@ public void testEncode2() { UsCaV1 usCaV1 = new UsCaV1(); usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); - usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); - usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 3); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 1); - usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 2); - usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3, 0)); - usCaV1.setFieldValue(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(0, 1)); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 1); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0)); + usCaV1.setFieldValue(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(2, 1)); usCaV1.setFieldValue(UsCaV1Field.PERSONAL_DATA_CONSENTS, 1); - usCaV1.setFieldValue(UsCaV1Field.MSPA_COVERED_TRANSACTION, 3); + usCaV1.setFieldValue(UsCaV1Field.MSPA_COVERED_TRANSACTION, 1); usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); usCaV1.setFieldValue(UsCaV1Field.GPC, true); - Assertions.assertEquals("BbYbGwXY.YA", usCaV1.encode()); + Assertions.assertEquals("BVWSSSVY.YA", usCaV1.encode()); } @Test @@ -41,41 +42,464 @@ public void testEncode3() { usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); - usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); - usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 2); - usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 2); - usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0)); - usCaV1.setFieldValue(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(0, 0)); - usCaV1.setFieldValue(UsCaV1Field.PERSONAL_DATA_CONSENTS, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 1); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0)); + usCaV1.setFieldValue(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(2, 1)); + usCaV1.setFieldValue(UsCaV1Field.PERSONAL_DATA_CONSENTS, 1); usCaV1.setFieldValue(UsCaV1Field.MSPA_COVERED_TRANSACTION, 1); usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); - usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); usCaV1.setFieldValue(UsCaV1Field.GPC, true); - Assertions.assertEquals("BUoAAABQ.YA", usCaV1.encode()); + Assertions.assertEquals("BVWSSSVY.YA", usCaV1.encode()); } + + @Test + public void testSetInvalidValues() { + UsCaV1 usCaV1 = new UsCaV1(); + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 0, 0, 0, 3, 0, 0, 0, 0)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(0, 3)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.PERSONAL_DATA_CONSENTS, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + } + + @Test + public void testValidateSharing() { + UsCaV1 usCaV1 = new UsCaV1(); + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 0); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 0); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 0); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 1); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 2); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT, 1); + usCaV1.encode(); + } + + @Test + public void testValidateSale() { + UsCaV1 usCaV1 = new UsCaV1(); + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 0); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 0); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 0); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 1); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 2); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT, 1); + usCaV1.encode(); + } + + @Test + public void testValidateMspaServiceProviderMode() { + UsCaV1 usCaV1 = new UsCaV1(); + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 2); + usCaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCaV1.encode(); + + + usCaV1.setFieldValue(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 0); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 1); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usCaV1.encode(); + + usCaV1.setFieldValue(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCaV1.setFieldValue(UsCaV1Field.SALE_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SHARING_OPT_OUT_NOTICE, 2); + usCaV1.setFieldValue(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 2); + usCaV1.encode(); + } + @Test public void testEncodeWithGpcSegmentExcluded() { UsCaV1 usCaV1 = new UsCaV1(); usCaV1.setFieldValue(UsCaV1Field.GPC_SEGMENT_INCLUDED, false); - Assertions.assertEquals("BAAAAAAA", usCaV1.encode()); + Assertions.assertEquals("BAAAAABA", usCaV1.encode()); } @Test public void testDecode1() { - UsCaV1 usCaV1 = new UsCaV1("BbYbGwXY.YA"); + UsCaV1 usCaV1 = new UsCaV1("BVWSSSVY.YA"); Assertions.assertEquals(1, usCaV1.getSaleOptOutNotice()); - Assertions.assertEquals(2, usCaV1.getSharingOptOut()); - Assertions.assertEquals(3, usCaV1.getSensitiveDataLimitUseNotice()); + Assertions.assertEquals(1, usCaV1.getSharingOptOut()); + Assertions.assertEquals(1, usCaV1.getSensitiveDataLimitUseNotice()); Assertions.assertEquals(1, usCaV1.getSaleOptOut()); - Assertions.assertEquals(2, usCaV1.getSharingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3, 0), usCaV1.getSensitiveDataProcessing()); - Assertions.assertEquals(Arrays.asList(0, 1), usCaV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usCaV1.getSharingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0), usCaV1.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(2, 1), usCaV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usCaV1.getPersonalDataConsents()); - Assertions.assertEquals(3, usCaV1.getMspaCoveredTransaction()); + Assertions.assertEquals(1, usCaV1.getMspaCoveredTransaction()); Assertions.assertEquals(1, usCaV1.getMspaOptOutOptionMode()); Assertions.assertEquals(2, usCaV1.getMspaServiceProviderMode()); Assertions.assertEquals(true, usCaV1.getGpc()); @@ -83,17 +507,17 @@ public void testDecode1() { @Test public void testDecodeWithGpcSegmentExcluded() { - UsCaV1 usCaV1 = new UsCaV1("BbYbGwXY"); + UsCaV1 usCaV1 = new UsCaV1("BVWSSSVY"); Assertions.assertEquals(1, usCaV1.getSaleOptOutNotice()); - Assertions.assertEquals(2, usCaV1.getSharingOptOut()); - Assertions.assertEquals(3, usCaV1.getSensitiveDataLimitUseNotice()); + Assertions.assertEquals(1, usCaV1.getSharingOptOut()); + Assertions.assertEquals(1, usCaV1.getSensitiveDataLimitUseNotice()); Assertions.assertEquals(1, usCaV1.getSaleOptOut()); - Assertions.assertEquals(2, usCaV1.getSharingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3, 0), usCaV1.getSensitiveDataProcessing()); - Assertions.assertEquals(Arrays.asList(0, 1), usCaV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usCaV1.getSharingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0), usCaV1.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(2, 1), usCaV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usCaV1.getPersonalDataConsents()); - Assertions.assertEquals(3, usCaV1.getMspaCoveredTransaction()); + Assertions.assertEquals(1, usCaV1.getMspaCoveredTransaction()); Assertions.assertEquals(1, usCaV1.getMspaOptOutOptionMode()); Assertions.assertEquals(2, usCaV1.getMspaServiceProviderMode()); Assertions.assertEquals(false, usCaV1.getGpcSegmentIncluded()); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java index f00b108b..efe5a2ef 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java @@ -4,6 +4,7 @@ import java.util.Arrays; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.UsCoV1Field; public class UsCoV1Test { @@ -11,7 +12,7 @@ public class UsCoV1Test { @Test public void testEncode1() { UsCoV1 usCoV1 = new UsCoV1(); - Assertions.assertEquals("BAAAAAA.QA", usCoV1.encode()); + Assertions.assertEquals("BAAAAEA.QA", usCoV1.encode()); } @Test @@ -19,58 +20,393 @@ public void testEncode2() { UsCoV1 usCoV1 = new UsCoV1(); usCoV1.setFieldValue(UsCoV1Field.SHARING_NOTICE, 1); - usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); - usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 1); - usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); - usCoV1.setFieldValue(UsCoV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2)); - usCoV1.setFieldValue(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCoV1.setFieldValue(UsCoV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2)); + usCoV1.setFieldValue(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 1); usCoV1.setFieldValue(UsCoV1Field.MSPA_COVERED_TRANSACTION, 1); - usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); - usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); usCoV1.setFieldValue(UsCoV1Field.GPC, true); - Assertions.assertEquals("BbYbG2w.YA", usCoV1.encode()); + Assertions.assertEquals("BVWSSVg.YA", usCoV1.encode()); + } + + @Test + public void testSetInvalidValues() { + UsCoV1 usCoV1 = new UsCoV1(); + + try { + usCoV1.setFieldValue(UsCoV1Field.SHARING_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 5); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + } + + @Test + public void testValidateSale() { + UsCoV1 usCoV1 = new UsCoV1(); + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 1); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 0); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 0); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 0); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 1); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 2); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT, 1); + usCoV1.encode(); + } + + @Test + public void testValidateTargetedAdvertising() { + UsCoV1 usCoV1 = new UsCoV1(); + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usCoV1.setFieldValue(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCoV1.encode(); } + + @Test + public void testValidateMspaServiceProviderMode() { + UsCoV1 usCoV1 = new UsCoV1(); + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); + usCoV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCoV1.encode(); + + + usCoV1.setFieldValue(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 0); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 1); + usCoV1.encode(); + + usCoV1.setFieldValue(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCoV1.setFieldValue(UsCoV1Field.SALE_OPT_OUT_NOTICE, 2); + usCoV1.encode(); + } + @Test public void testEncodeWithGpcSegmentExcluded() { UsCoV1 usCoV1 = new UsCoV1(); usCoV1.setFieldValue(UsCoV1Field.GPC_SEGMENT_INCLUDED, false); - Assertions.assertEquals("BAAAAAA", usCoV1.encode()); + Assertions.assertEquals("BAAAAEA", usCoV1.encode()); } @Test public void testDecode1() { - UsCoV1 usCoV1 = new UsCoV1("BbYbG2wA.YA"); + UsCoV1 usCoV1 = new UsCoV1("BVWSSVg.YA"); Assertions.assertEquals(1, usCoV1.getSharingNotice()); - Assertions.assertEquals(2, usCoV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usCoV1.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usCoV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usCoV1.getTargetedAdvertisingOptOutNotice()); Assertions.assertEquals(1, usCoV1.getSaleOptOut()); - Assertions.assertEquals(2, usCoV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2), usCoV1.getSensitiveDataProcessing()); - Assertions.assertEquals(3, usCoV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usCoV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2), usCoV1.getSensitiveDataProcessing()); + Assertions.assertEquals(1, usCoV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usCoV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usCoV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usCoV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usCoV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usCoV1.getMspaServiceProviderMode()); Assertions.assertEquals(true, usCoV1.getGpc()); } @Test public void testDecodeWithGpcSegmentExcluded() { - UsCoV1 usCoV1 = new UsCoV1("BbYbG2wA"); + UsCoV1 usCoV1 = new UsCoV1("BVWSSVg"); Assertions.assertEquals(1, usCoV1.getSharingNotice()); - Assertions.assertEquals(2, usCoV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usCoV1.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usCoV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usCoV1.getTargetedAdvertisingOptOutNotice()); Assertions.assertEquals(1, usCoV1.getSaleOptOut()); - Assertions.assertEquals(2, usCoV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2), usCoV1.getSensitiveDataProcessing()); - Assertions.assertEquals(3, usCoV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usCoV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2), usCoV1.getSensitiveDataProcessing()); + Assertions.assertEquals(1, usCoV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usCoV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usCoV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usCoV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usCoV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usCoV1.getMspaServiceProviderMode()); Assertions.assertEquals(false, usCoV1.getGpcSegmentIncluded()); } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java index 864a1966..af353058 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.UsCtV1Field; public class UsCtV1Test { @@ -12,7 +13,7 @@ public class UsCtV1Test { @Test public void testEncode1() { UsCtV1 usCtV1 = new UsCtV1(); - Assertions.assertEquals("BAAAAAAA.QA", usCtV1.encode()); + Assertions.assertEquals("BAAAAAEA.QA", usCtV1.encode()); } @Test @@ -20,58 +21,391 @@ public void testEncode2() { UsCtV1 usCtV1 = new UsCtV1(); usCtV1.setFieldValue(UsCtV1Field.SHARING_NOTICE, 1); - usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); - usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 1); - usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); - usCtV1.setFieldValue(UsCtV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3)); - usCtV1.setFieldValue(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(1, 2, 3)); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCtV1.setFieldValue(UsCtV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1)); + usCtV1.setFieldValue(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(2, 1, 0)); usCtV1.setFieldValue(UsCtV1Field.MSPA_COVERED_TRANSACTION, 1); - usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); - usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); usCtV1.setFieldValue(UsCtV1Field.GPC, true); - Assertions.assertEquals("BbYbG22w.YA", usCtV1.encode()); + Assertions.assertEquals("BVWSSZFg.YA", usCtV1.encode()); + } + + @Test + public void testSetInvalidValues() { + UsCtV1 usCtV1 = new UsCtV1(); + + try { + usCtV1.setFieldValue(UsCtV1Field.SHARING_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 1, 2, 0, 1)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(1, 2, 3)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 4); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + } + + @Test + public void testValidateSale() { + UsCtV1 usCtV1 = new UsCtV1(); + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 1); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 0); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 0); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 0); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 1); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 2); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT, 1); + usCtV1.encode(); + } + + @Test + public void testValidateTargetedAdvertising() { + UsCtV1 usCtV1 = new UsCtV1(); + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usCtV1.setFieldValue(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usCtV1.encode(); } + + @Test + public void testValidateMspaServiceProviderMode() { + UsCtV1 usCtV1 = new UsCtV1(); + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); + usCtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usCtV1.encode(); + + + usCtV1.setFieldValue(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 0); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 1); + usCtV1.encode(); + + usCtV1.setFieldValue(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usCtV1.setFieldValue(UsCtV1Field.SALE_OPT_OUT_NOTICE, 2); + usCtV1.encode(); + } + @Test public void testEncodeWithGpcSegmentExcluded() { UsCtV1 usCtV1 = new UsCtV1(); usCtV1.setFieldValue(UsCtV1Field.GPC_SEGMENT_INCLUDED, false); - Assertions.assertEquals("BAAAAAAA", usCtV1.encode()); + Assertions.assertEquals("BAAAAAEA", usCtV1.encode()); } @Test public void testDecode1() throws DecodingException { - UsCtV1 usCtV1 = new UsCtV1("BbYbG22w.YAAA"); + UsCtV1 usCtV1 = new UsCtV1("BVWSSZFg.YA"); Assertions.assertEquals(1, usCtV1.getSharingNotice()); - Assertions.assertEquals(2, usCtV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usCtV1.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usCtV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usCtV1.getTargetedAdvertisingOptOutNotice()); Assertions.assertEquals(1, usCtV1.getSaleOptOut()); - Assertions.assertEquals(2, usCtV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3), usCtV1.getSensitiveDataProcessing()); - Assertions.assertEquals(Arrays.asList(1, 2, 3), usCtV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usCtV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usCtV1.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(2, 1, 0), usCtV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usCtV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usCtV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usCtV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usCtV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usCtV1.getMspaServiceProviderMode()); Assertions.assertEquals(true, usCtV1.getGpc()); } @Test public void testDecodeWithGpcSegmentExcluded() throws DecodingException { - UsCtV1 usCtV1 = new UsCtV1("BbYbG22w"); + UsCtV1 usCtV1 = new UsCtV1("BVWSSZFg"); Assertions.assertEquals(1, usCtV1.getSharingNotice()); - Assertions.assertEquals(2, usCtV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usCtV1.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usCtV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usCtV1.getTargetedAdvertisingOptOutNotice()); Assertions.assertEquals(1, usCtV1.getSaleOptOut()); - Assertions.assertEquals(2, usCtV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3), usCtV1.getSensitiveDataProcessing()); - Assertions.assertEquals(Arrays.asList(1, 2, 3), usCtV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usCtV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usCtV1.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(2, 1, 0), usCtV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usCtV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usCtV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usCtV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usCtV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usCtV1.getMspaServiceProviderMode()); Assertions.assertEquals(false, usCtV1.getGpcSegmentIncluded()); } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java index 379752e6..ac3cd9ab 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.UsNatV1Field; public class UsNatV1Test { @@ -13,7 +14,7 @@ public class UsNatV1Test { public void testEncode1() { UsNatV1 usNatV1 = new UsNatV1(); - Assertions.assertEquals("BAAAAAAAAAA.QA", usNatV1.encode()); + Assertions.assertEquals("BAAAAAAAAQA.QA", usNatV1.encode()); } @Test @@ -21,25 +22,546 @@ public void testEncode2() { UsNatV1 usNatV1 = new UsNatV1(); usNatV1.setFieldValue(UsNatV1Field.SHARING_NOTICE, 1); - usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); - usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 3); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); - usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 2); - usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 3); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 1); - usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 2); - usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 3); - usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3)); - usNatV1.setFieldValue(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(0, 1)); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 1); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0)); + usNatV1.setFieldValue(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(2, 1)); usNatV1.setFieldValue(UsNatV1Field.PERSONAL_DATA_CONSENTS, 1); usNatV1.setFieldValue(UsNatV1Field.MSPA_COVERED_TRANSACTION, 1); - usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); - usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); usNatV1.setFieldValue(UsNatV1Field.GPC, true); - Assertions.assertEquals("BbbbGxsbFbA.YA", usNatV1.encode()); + Assertions.assertEquals("BVVVkkkklWA.YA", usNatV1.encode()); + } + + @Test + public void testSetInvalidValues() { + UsNatV1 usNatV1 = new UsNatV1(); + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_NOTICE, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 4); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 0, 0, 1, 2, 0)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(0, 3)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.PERSONAL_DATA_CONSENTS, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + } + @Test + public void testValidateSharing() { + UsNatV1 usNatV1 = new UsNatV1(); + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 1); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 2); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 1); + usNatV1.encode(); + } + + @Test + public void testValidateSale() { + UsNatV1 usNatV1 = new UsNatV1(); + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 1); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 2); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 1); + usNatV1.encode(); + } + + @Test + public void testValidateTargetedAdvertising() { + UsNatV1 usNatV1 = new UsNatV1(); + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usNatV1.encode(); + } + + @Test + public void testValidateMspaServiceProviderMode() { + UsNatV1 usNatV1 = new UsNatV1(); + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 2); + usNatV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usNatV1.encode(); + + + usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); + usNatV1.encode(); + + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 2); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 2); + usNatV1.encode(); + } + + @Test public void testEncode3() { UsNatV1 usNatV1 = new UsNatV1(); @@ -48,20 +570,20 @@ public void testEncode3() { usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT_NOTICE, 1); usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT_NOTICE, 1); usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); - usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 0); - usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 1); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, 1); usNatV1.setFieldValue(UsNatV1Field.SALE_OPT_OUT, 1); usNatV1.setFieldValue(UsNatV1Field.SHARING_OPT_OUT, 1); usNatV1.setFieldValue(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); - usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)); - usNatV1.setFieldValue(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(0, 0)); - usNatV1.setFieldValue(UsNatV1Field.PERSONAL_DATA_CONSENTS, 0); + usNatV1.setFieldValue(UsNatV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0)); + usNatV1.setFieldValue(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, Arrays.asList(2, 1)); + usNatV1.setFieldValue(UsNatV1Field.PERSONAL_DATA_CONSENTS, 1); usNatV1.setFieldValue(UsNatV1Field.MSPA_COVERED_TRANSACTION, 1); usNatV1.setFieldValue(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); - usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usNatV1.setFieldValue(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); usNatV1.setFieldValue(UsNatV1Field.GPC, true); - Assertions.assertEquals("BVQVAAAAAUA.YA", usNatV1.encode()); + Assertions.assertEquals("BVVVkkkklWA.YA", usNatV1.encode()); } @Test @@ -69,50 +591,50 @@ public void testEncodeWithGpcSegmentIncluded() { UsNatV1 usNatV1 = new UsNatV1(); usNatV1.setFieldValue(UsNatV1Field.GPC_SEGMENT_INCLUDED, false); - Assertions.assertEquals("BAAAAAAAAAA", usNatV1.encode()); + Assertions.assertEquals("BAAAAAAAAQA", usNatV1.encode()); } @Test public void testDecode1() throws DecodingException { - UsNatV1 usNatV1 = new UsNatV1("BbbbGxsbFbA.YA"); + UsNatV1 usNatV1 = new UsNatV1("BVVVkkkklWA.YA"); Assertions.assertEquals(1, usNatV1.getSharingNotice()); - Assertions.assertEquals(2, usNatV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usNatV1.getSharingOptOutNotice()); + Assertions.assertEquals(1, usNatV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usNatV1.getSharingOptOutNotice()); Assertions.assertEquals(1, usNatV1.getTargetedAdvertisingOptOutNotice()); - Assertions.assertEquals(2, usNatV1.getSensitiveDataProcessingOptOutNotice()); - Assertions.assertEquals(3, usNatV1.getSensitiveDataLimitUseNotice()); + Assertions.assertEquals(1, usNatV1.getSensitiveDataProcessingOptOutNotice()); + Assertions.assertEquals(1, usNatV1.getSensitiveDataLimitUseNotice()); Assertions.assertEquals(1, usNatV1.getSaleOptOut()); - Assertions.assertEquals(2, usNatV1.getSharingOptOut()); - Assertions.assertEquals(3, usNatV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3), usNatV1.getSensitiveDataProcessing()); - Assertions.assertEquals(Arrays.asList(0, 1), usNatV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usNatV1.getSharingOptOut()); + Assertions.assertEquals(1, usNatV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0), usNatV1.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(2, 1), usNatV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usNatV1.getPersonalDataConsents()); Assertions.assertEquals(1, usNatV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usNatV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usNatV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usNatV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usNatV1.getMspaServiceProviderMode()); Assertions.assertEquals(true, usNatV1.getGpc()); } @Test public void testDecodeWithGpcSegmentExcluded() throws DecodingException { - UsNatV1 usNatV1 = new UsNatV1("BbbbGxsbFbA"); + UsNatV1 usNatV1 = new UsNatV1("BVVVkkkklWA"); Assertions.assertEquals(1, usNatV1.getSharingNotice()); - Assertions.assertEquals(2, usNatV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usNatV1.getSharingOptOutNotice()); + Assertions.assertEquals(1, usNatV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usNatV1.getSharingOptOutNotice()); Assertions.assertEquals(1, usNatV1.getTargetedAdvertisingOptOutNotice()); - Assertions.assertEquals(2, usNatV1.getSensitiveDataProcessingOptOutNotice()); - Assertions.assertEquals(3, usNatV1.getSensitiveDataLimitUseNotice()); + Assertions.assertEquals(1, usNatV1.getSensitiveDataProcessingOptOutNotice()); + Assertions.assertEquals(1, usNatV1.getSensitiveDataLimitUseNotice()); Assertions.assertEquals(1, usNatV1.getSaleOptOut()); - Assertions.assertEquals(2, usNatV1.getSharingOptOut()); - Assertions.assertEquals(3, usNatV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3), usNatV1.getSensitiveDataProcessing()); - Assertions.assertEquals(Arrays.asList(0, 1), usNatV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usNatV1.getSharingOptOut()); + Assertions.assertEquals(1, usNatV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1, 0, 2, 1, 0), usNatV1.getSensitiveDataProcessing()); + Assertions.assertEquals(Arrays.asList(2, 1), usNatV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usNatV1.getPersonalDataConsents()); Assertions.assertEquals(1, usNatV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usNatV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usNatV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usNatV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usNatV1.getMspaServiceProviderMode()); Assertions.assertEquals(false, usNatV1.getGpcSegmentIncluded()); } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java index ac647a6b..d42eaddc 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java @@ -5,6 +5,7 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.UsUtV1Field; public class UsUtV1Test { @@ -12,7 +13,7 @@ public class UsUtV1Test { @Test public void testEncode1() { UsUtV1 usUtV1 = new UsUtV1(); - Assertions.assertEquals("BAAAAAAA", usUtV1.encode()); + Assertions.assertEquals("BAAAAAQA", usUtV1.encode()); } @Test @@ -20,33 +21,373 @@ public void testEncode2() { UsUtV1 usUtV1 = new UsUtV1(); usUtV1.setFieldValue(UsUtV1Field.SHARING_NOTICE, 1); - usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); - usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 1); usUtV1.setFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 1); - usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); - usUtV1.setFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3)); - usUtV1.setFieldValue(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usUtV1.setFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1)); + usUtV1.setFieldValue(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 1); usUtV1.setFieldValue(UsUtV1Field.MSPA_COVERED_TRANSACTION, 1); - usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); - usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + + Assertions.assertEquals("BVVkklWA", usUtV1.encode()); + } + + @Test + public void testSetInvalidValues() { + UsUtV1 usUtV1 = new UsUtV1(); - Assertions.assertEquals("BbWGxvbA", usUtV1.encode()); + try { + usUtV1.setFieldValue(UsUtV1Field.SHARING_NOTICE, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 4); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 0)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + } + @Test + public void testValidateSale() { + UsUtV1 usUtV1 = new UsUtV1(); + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 1); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 0); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 0); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 0); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 1); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 2); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT, 1); + usUtV1.encode(); + } + + @Test + public void testValidateTargetedAdvertising() { + UsUtV1 usUtV1 = new UsUtV1(); + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usUtV1.setFieldValue(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usUtV1.encode(); + } + + @Test + public void testValidateMspaServiceProviderMode() { + UsUtV1 usUtV1 = new UsUtV1(); + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); + usUtV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usUtV1.encode(); + + + usUtV1.setFieldValue(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 0); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 1); + usUtV1.encode(); + + usUtV1.setFieldValue(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usUtV1.setFieldValue(UsUtV1Field.SALE_OPT_OUT_NOTICE, 2); + usUtV1.encode(); + } + @Test public void testDecode1() throws DecodingException { - UsUtV1 usUtV1 = new UsUtV1("BbWGxvbA"); + UsUtV1 usUtV1 = new UsUtV1("BVVkklWA"); Assertions.assertEquals(1, usUtV1.getSharingNotice()); - Assertions.assertEquals(2, usUtV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usUtV1.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usUtV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usUtV1.getTargetedAdvertisingOptOutNotice()); Assertions.assertEquals(1, usUtV1.getSaleOptOut()); - Assertions.assertEquals(2, usUtV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3), usUtV1.getSensitiveDataProcessing()); - Assertions.assertEquals(3, usUtV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usUtV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usUtV1.getSensitiveDataProcessing()); + Assertions.assertEquals(1, usUtV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usUtV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usUtV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usUtV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usUtV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usUtV1.getMspaServiceProviderMode()); } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java index 06b5165f..0a446cd2 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java @@ -7,6 +7,7 @@ import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.UsVaV1Field; public class UsVaV1Test { @@ -14,7 +15,7 @@ public class UsVaV1Test { @Test public void testEncode1() { UsVaV1 usVaV1 = new UsVaV1(); - Assertions.assertEquals("BAAAAAA", usVaV1.encode()); + Assertions.assertEquals("BAAAABA", usVaV1.encode()); } @Test @@ -23,35 +24,368 @@ public void testEncode2() { try { usVaV1.setFieldValue(UsVaV1Field.SHARING_NOTICE, 1); - usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); - usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 3); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 1); - usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); - usVaV1.setFieldValue(UsVaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3)); - usVaV1.setFieldValue(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usVaV1.setFieldValue(UsVaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1)); + usVaV1.setFieldValue(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 1); usVaV1.setFieldValue(UsVaV1Field.MSPA_COVERED_TRANSACTION, 1); - usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); - usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); } catch (InvalidFieldException e) { throw new EncodingException(e); } - Assertions.assertEquals("BbYbG9s", usVaV1.encode()); + Assertions.assertEquals("BVWSSVY", usVaV1.encode()); + } + + @Test + public void testSetInvalidValues() { + UsVaV1 usVaV1 = new UsVaV1(); + + try { + usVaV1.setFieldValue(UsVaV1Field.SHARING_NOTICE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, -1); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 4); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SENSITIVE_DATA_PROCESSING, Arrays.asList(0, 1, 2, 3, 1, 2, 0, 1)); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_COVERED_TRANSACTION, 0); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 3); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + } + + @Test + public void testValidateSale() { + UsVaV1 usVaV1 = new UsVaV1(); + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 1); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 0); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 0); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 0); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 1); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 2); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT, 1); + usVaV1.encode(); + } + + @Test + public void testValidateTargetedAdvertising() { + UsVaV1 usVaV1 = new UsVaV1(); + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 0); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 0); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 1); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 2); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, 2); + usVaV1.setFieldValue(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, 1); + usVaV1.encode(); + } + + @Test + public void testValidateMspaServiceProviderMode() { + UsVaV1 usVaV1 = new UsVaV1(); + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + try { + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); + usVaV1.encode(); + Assertions.fail("Expected ValidationException"); + } catch (ValidationException e) { + + } + + + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 2); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 1); + usVaV1.encode(); + + + usVaV1.setFieldValue(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, 0); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 0); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 1); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 0); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 1); + usVaV1.encode(); + + usVaV1.setFieldValue(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, 2); + usVaV1.setFieldValue(UsVaV1Field.SALE_OPT_OUT_NOTICE, 2); + usVaV1.encode(); } @Test public void testDecode1() throws DecodingException { - UsVaV1 usVaV1 = new UsVaV1("BbYbG9s"); + UsVaV1 usVaV1 = new UsVaV1("BVWSSVY"); Assertions.assertEquals(1, usVaV1.getSharingNotice()); - Assertions.assertEquals(2, usVaV1.getSaleOptOutNotice()); - Assertions.assertEquals(3, usVaV1.getTargetedAdvertisingOptOutNotice()); + Assertions.assertEquals(1, usVaV1.getSaleOptOutNotice()); + Assertions.assertEquals(1, usVaV1.getTargetedAdvertisingOptOutNotice()); Assertions.assertEquals(1, usVaV1.getSaleOptOut()); - Assertions.assertEquals(2, usVaV1.getTargetedAdvertisingOptOut()); - Assertions.assertEquals(Arrays.asList(0, 1, 2, 3, 0, 1, 2, 3), usVaV1.getSensitiveDataProcessing()); - Assertions.assertEquals(3, usVaV1.getKnownChildSensitiveDataConsents()); + Assertions.assertEquals(1, usVaV1.getTargetedAdvertisingOptOut()); + Assertions.assertEquals(Arrays.asList(2, 1, 0, 2, 1, 0, 2, 1), usVaV1.getSensitiveDataProcessing()); + Assertions.assertEquals(1, usVaV1.getKnownChildSensitiveDataConsents()); Assertions.assertEquals(1, usVaV1.getMspaCoveredTransaction()); - Assertions.assertEquals(2, usVaV1.getMspaOptOutOptionMode()); - Assertions.assertEquals(3, usVaV1.getMspaServiceProviderMode()); + Assertions.assertEquals(1, usVaV1.getMspaOptOutOptionMode()); + Assertions.assertEquals(2, usVaV1.getMspaServiceProviderMode()); } } From 5b536dc24c7c669e4cff7423ab6c6cd2aa489285 Mon Sep 17 00:00:00 2001 From: chad Date: Sun, 10 Sep 2023 22:04:40 -0600 Subject: [PATCH 08/36] fix typo --- .../iab/gpp/encoder/datatype/encoder/FixedIntegerEncoder.java | 2 +- .../com/iab/gpp/encoder/datatype/encoder/FixedLongEncoder.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 2c0da692..dfc6802f 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 @@ -23,7 +23,7 @@ public static String encode(int value, int bitStringLength) { if (bitString.length() > bitStringLength) { throw new EncodingException( - "Numberic 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) { 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 4d5a9ab5..c244a601 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 @@ -21,7 +21,7 @@ public static String encode(long value, int bitStringLength) { if (bitString.length() > bitStringLength) { throw new EncodingException( - "Numberic 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) { From 6c705b3eb28021ab53a41a61e3a24b336950e7dc Mon Sep 17 00:00:00 2001 From: chad Date: Sun, 10 Sep 2023 22:08:09 -0600 Subject: [PATCH 09/36] remove redundant validate call --- .../java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java | 1 - 1 file changed, 1 deletion(-) diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java index d8c9918c..44e18bbf 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java @@ -41,7 +41,6 @@ protected EncodableBitStringFields initializeFields() { @Override protected String encodeSegment(EncodableBitStringFields fields) { - validate(); String bitString = bitStringEncoder.encode(fields, getFieldNames()); String encodedString = base64UrlEncoder.encode(bitString); return encodedString; From 909cad2a534a1041ec7c93b2d84393e67e2b9efb Mon Sep 17 00:00:00 2001 From: chad Date: Mon, 11 Sep 2023 07:33:49 -0600 Subject: [PATCH 10/36] default validate --- .../gpp/encoder/segment/AbstractLazilyEncodableSegment.java | 5 ----- .../java/com/iab/gpp/encoder/segment/EncodableSegment.java | 2 +- .../com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java | 5 +++++ .../java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java | 1 - .../java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java | 1 - .../java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java | 1 - .../java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java | 1 - .../java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java | 1 - .../java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java | 1 - .../src/test/java/com/iab/gpp/encoder/GppModelTest.java | 2 +- 10 files changed, 7 insertions(+), 13 deletions(-) diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java index dc2d6c6b..8726e16d 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/AbstractLazilyEncodableSegment.java @@ -22,11 +22,6 @@ public AbstractLazilyEncodableSegment() { protected abstract void decodeSegment(String encodedString, T Fields); - @Override - public void validate() { - - } - public boolean hasField(String fieldName) { return this.fields.containsKey(fieldName); } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java index 457328e7..d2363a82 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/EncodableSegment.java @@ -16,5 +16,5 @@ public interface EncodableSegment { void decode(String encodedString); - void validate(); + default void validate() {}; } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java index 44e18bbf..c0b98045 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java @@ -54,4 +54,9 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } + + @Override + public void validate() { + + } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java index 41999f44..23289f42 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java @@ -82,7 +82,6 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel @Override public void validate() { - super.validate(); Integer sharingOptOutNotice = ((EncodableFixedInteger) fields.get(UsCaV1Field.SHARING_OPT_OUT_NOTICE)).getValue(); Integer sharingOptOut = ((EncodableFixedInteger) fields.get(UsCaV1Field.SHARING_OPT_OUT)).getValue(); Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCaV1Field.SALE_OPT_OUT_NOTICE)).getValue(); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java index 4cbaff8e..62dd3f3e 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java @@ -76,7 +76,6 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel @Override public void validate() { - super.validate(); Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT_NOTICE)).getValue(); Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT)).getValue(); Integer targetedAdvertisingOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java index ec9f6294..70a230ba 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java @@ -84,7 +84,6 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel @Override public void validate() { - super.validate(); Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT_NOTICE)).getValue(); Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT)).getValue(); Integer targetedAdvertisingOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java index e4e6c951..2488bad9 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java @@ -89,7 +89,6 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel @Override public void validate() { - super.validate(); Integer sharingNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.SHARING_NOTICE)).getValue(); Integer sharingOptOutNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.SHARING_OPT_OUT_NOTICE)).getValue(); Integer sharingOptOut = ((EncodableFixedInteger) fields.get(UsNatV1Field.SHARING_OPT_OUT)).getValue(); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java index 63f8e3ae..0a88910c 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java @@ -78,7 +78,6 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel @Override public void validate() { - super.validate(); Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsUtV1Field.SALE_OPT_OUT_NOTICE)).getValue(); Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsUtV1Field.SALE_OPT_OUT)).getValue(); Integer targetedAdvertisingOptOutNotice = diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java index 1a009e52..8e04b968 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java @@ -76,7 +76,6 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel @Override public void validate() { - super.validate(); Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsVaV1Field.SALE_OPT_OUT_NOTICE)).getValue(); Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsVaV1Field.SALE_OPT_OUT)).getValue(); Integer targetedAdvertisingOptOutNotice = diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index 035f33ae..dbcd3d9a 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -369,7 +369,7 @@ public void testDecodeDefaults() { @Test public void testDecodeDefaultsAll() { String gppString = - "DBACOaw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAAA.QA~BAAAAAAA.QA~BAAAAAA~BAAAAAA.QA~BAAAAAAA~BAAAAAAA.QA"; + "DBACOaw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAQA.QA~BAAAAABA.QA~BAAAABA~BAAAAEA.QA~BAAAAAQA~BAAAAAEA.QA"; GppModel gppModel = new GppModel(gppString); Assertions.assertEquals(true, gppModel.hasSection(TcfEuV2.NAME)); From 47874d221d8fe0fa2bcf104d52d4e783133e3149 Mon Sep 17 00:00:00 2001 From: chad Date: Mon, 11 Sep 2023 07:36:51 -0600 Subject: [PATCH 11/36] remove empty validate method from header core segment --- .../java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java index c0b98045..1154d1f6 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java @@ -54,9 +54,5 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } - - @Override - public void validate() { - } } From 97fd395d5fa0cd90a4b5b00366e00508ee116007 Mon Sep 17 00:00:00 2001 From: chad Date: Mon, 11 Sep 2023 07:50:02 -0600 Subject: [PATCH 12/36] fix usct validator --- .../iab/gpp/encoder/segment/UsCtV1CoreSegment.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java index 70a230ba..57b33b09 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java @@ -9,7 +9,6 @@ import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; -import com.iab.gpp.encoder.field.UsCoV1Field; import com.iab.gpp.encoder.field.UsCtV1Field; import com.iab.gpp.encoder.section.UsCtV1; @@ -84,12 +83,12 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel @Override public void validate() { - Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT_NOTICE)).getValue(); - Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT)).getValue(); - Integer targetedAdvertisingOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); - Integer targetedAdvertisingOptOut = ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); - Integer mspaServiceProviderMode = ((EncodableFixedInteger) fields.get(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); - Integer mspaOptOutOptionMode = ((EncodableFixedInteger) fields.get(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCtV1Field.SALE_OPT_OUT_NOTICE)).getValue(); + Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCtV1Field.SALE_OPT_OUT)).getValue(); + Integer targetedAdvertisingOptOutNotice = ((EncodableFixedInteger) fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = ((EncodableFixedInteger) fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = ((EncodableFixedInteger) fields.get(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = ((EncodableFixedInteger) fields.get(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); if (saleOptOutNotice == 0) { if (saleOptOut != 0) { From db78746e79dbb8151614a7ee14be27d3d92dbf94 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 14 Sep 2023 07:46:44 -0600 Subject: [PATCH 13/36] 3.1.1 --- iabgpp-encoder/pom.xml | 2 +- iabgpp-extras-jackson/pom.xml | 4 ++-- iabgpp-extras/pom.xml | 2 +- pom.xml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iabgpp-encoder/pom.xml b/iabgpp-encoder/pom.xml index b6690766..c741e537 100644 --- a/iabgpp-encoder/pom.xml +++ b/iabgpp-encoder/pom.xml @@ -7,7 +7,7 @@ com.iabgpp iabgpp-core - 3.1.1-SNAPSHOT + 3.1.1 iabgpp-encoder diff --git a/iabgpp-extras-jackson/pom.xml b/iabgpp-extras-jackson/pom.xml index b0aaedfc..4956766d 100644 --- a/iabgpp-extras-jackson/pom.xml +++ b/iabgpp-extras-jackson/pom.xml @@ -7,7 +7,7 @@ iabgpp-core com.iabgpp - 3.1.1-SNAPSHOT + 3.1.1 iabgpp-extras-jackson @@ -24,7 +24,7 @@ com.iabgpp iabgpp-extras - 3.1.1-SNAPSHOT + 3.1.1 diff --git a/iabgpp-extras/pom.xml b/iabgpp-extras/pom.xml index a1ac55d1..07e1ff5b 100644 --- a/iabgpp-extras/pom.xml +++ b/iabgpp-extras/pom.xml @@ -7,7 +7,7 @@ com.iabgpp iabgpp-core - 3.1.1-SNAPSHOT + 3.1.1 iabgpp-extras diff --git a/pom.xml b/pom.xml index f0fce412..d8aca0d8 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.iabgpp iabgpp-core - 3.1.1-SNAPSHOT + 3.1.1 IAB GPP Core Library https://github.com/IABTechLabs/iabtcf-java Encode and decode consent information with the IAB GPP v3.0. From 982430586aaa6e5bd8f71fe2bab80b9de7ce5c69 Mon Sep 17 00:00:00 2001 From: chad Date: Thu, 14 Sep 2023 07:46:47 -0600 Subject: [PATCH 14/36] 3.1.2-SNAPSHOT --- iabgpp-encoder/pom.xml | 2 +- iabgpp-extras-jackson/pom.xml | 4 ++-- iabgpp-extras/pom.xml | 2 +- pom.xml | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/iabgpp-encoder/pom.xml b/iabgpp-encoder/pom.xml index c741e537..fe7ebc3b 100644 --- a/iabgpp-encoder/pom.xml +++ b/iabgpp-encoder/pom.xml @@ -7,7 +7,7 @@ com.iabgpp iabgpp-core - 3.1.1 + 3.1.2-SNAPSHOT iabgpp-encoder diff --git a/iabgpp-extras-jackson/pom.xml b/iabgpp-extras-jackson/pom.xml index 4956766d..92075406 100644 --- a/iabgpp-extras-jackson/pom.xml +++ b/iabgpp-extras-jackson/pom.xml @@ -7,7 +7,7 @@ iabgpp-core com.iabgpp - 3.1.1 + 3.1.2-SNAPSHOT iabgpp-extras-jackson @@ -24,7 +24,7 @@ com.iabgpp iabgpp-extras - 3.1.1 + 3.1.2-SNAPSHOT diff --git a/iabgpp-extras/pom.xml b/iabgpp-extras/pom.xml index 07e1ff5b..d82bb0d9 100644 --- a/iabgpp-extras/pom.xml +++ b/iabgpp-extras/pom.xml @@ -7,7 +7,7 @@ com.iabgpp iabgpp-core - 3.1.1 + 3.1.2-SNAPSHOT iabgpp-extras diff --git a/pom.xml b/pom.xml index d8aca0d8..42a5e198 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.iabgpp iabgpp-core - 3.1.1 + 3.1.2-SNAPSHOT IAB GPP Core Library https://github.com/IABTechLabs/iabtcf-java Encode and decode consent information with the IAB GPP v3.0. From 0e67b3c9037860454e06063e7637ebc05ba0ebda Mon Sep 17 00:00:00 2001 From: chad Date: Tue, 3 Oct 2023 15:37:42 -0600 Subject: [PATCH 15/36] tcfca publisher restrictions and disclosed vendors --- .../datatype/EncodableArrayOfRanges.java | 94 +++++++++++ .../EncodableOptimizedFibonacciRange.java | 39 +---- .../EncodableOptimizedFixedRange.java | 40 +---- .../iab/gpp/encoder/datatype/RangeEntry.java | 42 +++++ .../encoder/ArrayOfRangesEntryEncoder.java | 43 +++++ .../OptimizedFibonacciRangeEncoder.java | 56 +++++++ .../encoder/OptimizedFixedRangeEncoder.java | 57 +++++++ .../iab/gpp/encoder/field/TcfCaV1Field.java | 3 + .../AbstractEncodableBitStringSection.java | 12 +- ...actEncodableSegmentedBitStringSection.java | 2 + .../com/iab/gpp/encoder/section/TcfCaV1.java | 34 +++- .../com/iab/gpp/encoder/GppModelTest.java | 9 +- .../datatype/EncodableArrayOfRangesTest.java | 158 ++++++++++++++++++ .../iab/gpp/encoder/section/TcfCaV1Test.java | 42 ++++- 14 files changed, 545 insertions(+), 86 deletions(-) create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRanges.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/RangeEntry.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/ArrayOfRangesEntryEncoder.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFibonacciRangeEncoder.java create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFixedRangeEncoder.java create mode 100644 iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRangesTest.java diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRanges.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRanges.java new file mode 100644 index 00000000..32ec28a6 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRanges.java @@ -0,0 +1,94 @@ +package com.iab.gpp.encoder.datatype; + +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; +import com.iab.gpp.encoder.datatype.encoder.OptimizedFixedRangeEncoder; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; + +public class EncodableArrayOfRanges extends AbstractEncodableBitStringDataType> { + + private int keyBitStringLength; + private int typeBitStringLength; + + protected EncodableArrayOfRanges(int keyBitStringLength, int typeBitStringLength) { + super(); + this.keyBitStringLength = keyBitStringLength; + this.typeBitStringLength = typeBitStringLength; + } + + public EncodableArrayOfRanges(int keyBitStringLength, int typeBitStringLength, List value) { + super(); + this.keyBitStringLength = keyBitStringLength; + this.typeBitStringLength = typeBitStringLength; + setValue(value); + } + + @Override + public String encode() throws EncodingException { + List entries = this.value; + + StringBuilder sb = new StringBuilder(); + sb.append(FixedIntegerEncoder.encode(entries.size(), 12)); + for (RangeEntry entry : entries) { + sb.append(FixedIntegerEncoder.encode(entry.getKey(), keyBitStringLength)) + .append(FixedIntegerEncoder.encode(entry.getType(), typeBitStringLength)) + .append(OptimizedFixedRangeEncoder.encode(entry.getIds())); + } + + return sb.toString(); + } + + @Override + public void decode(String bitString) throws DecodingException { + List entries = new ArrayList<>(); + + int size = FixedIntegerEncoder.decode(bitString.substring(0, 12)); + int index = 12; + for (int i = 0; i < size; i++) { + int key = FixedIntegerEncoder.decode(bitString.substring(index, index + keyBitStringLength)); + index += keyBitStringLength; + + int type = FixedIntegerEncoder.decode(bitString.substring(index, index + typeBitStringLength)); + index += typeBitStringLength; + + String substring = new EncodableOptimizedFixedRange().substring(bitString, index); + List ids = OptimizedFixedRangeEncoder.decode(substring); + index += substring.length(); + + entries.add(new RangeEntry(key, type, ids)); + } + + this.value = entries; + } + + @Override + public String substring(String bitString, int fromIndex) throws DecodingException { + StringBuilder sb = new StringBuilder(); + sb.append(bitString.substring(fromIndex, fromIndex + 12)); + + int size = FixedIntegerEncoder.decode(sb.toString()); + + int index = fromIndex + sb.length(); + for (int i = 0; i < size; i++) { + sb.append(bitString.substring(index, index + 8)); + index += 8; + + String substring = null; + int max = FixedIntegerEncoder.decode(bitString.substring(index, index + 16)); + if (bitString.charAt(index + 16) == '1') { + substring = bitString.substring(index, index + 17) + + new EncodableFixedIntegerRange().substring(bitString, index + 17); + } else { + substring = bitString.substring(index, index + 17 + max); + } + index += substring.length(); + + sb.append(substring); + } + + return sb.toString(); + } + +} 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 d32dcc49..fe111de2 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 @@ -3,9 +3,8 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; -import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerRangeEncoder; -import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; +import com.iab.gpp.encoder.datatype.encoder.OptimizedFibonacciRangeEncoder; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; @@ -21,43 +20,11 @@ public EncodableOptimizedFibonacciRange(List value) { } public String encode() 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 = this.value.size() > 0 ? this.value.get(this.value.size() - 1) : 0; - String rangeBitString = FibonacciIntegerRangeEncoder.encode(this.value); - int rangeLength = rangeBitString.length(); - int bitFieldLength = max; - - if (rangeLength <= bitFieldLength) { - return FixedIntegerEncoder.encode(max, 16) + "1" + rangeBitString; - } else { - List bits = new ArrayList<>(); - int index = 0; - for (int i = 0; i < max; i++) { - if (i == this.value.get(index) - 1) { - bits.add(true); - index++; - } else { - bits.add(false); - } - } - return FixedIntegerEncoder.encode(max, 16) + "0" + FixedBitfieldEncoder.encode(bits, bitFieldLength); - } + return OptimizedFibonacciRangeEncoder.encode(this.value); } public void decode(String bitString) throws DecodingException { - if (bitString.charAt(16) == '1') { - this.value = 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); - } - } - this.value = value; - } + this.value = OptimizedFibonacciRangeEncoder.decode(bitString); } public String substring(String bitString, int fromIndex) throws DecodingException { 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 d3250f07..b37a23a7 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 @@ -3,9 +3,8 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; -import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; -import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; +import com.iab.gpp.encoder.datatype.encoder.OptimizedFixedRangeEncoder; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; @@ -21,44 +20,11 @@ public EncodableOptimizedFixedRange(List value) { } public String encode() 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 = this.value.size() > 0 ? this.value.get(this.value.size() - 1) : 0; - String rangeBitString = FixedIntegerRangeEncoder.encode(this.value); - int rangeLength = rangeBitString.length(); - int bitFieldLength = max; - - if (rangeLength <= bitFieldLength) { - return FixedIntegerEncoder.encode(max, 16) + "1" + rangeBitString; - } else { - List bits = new ArrayList<>(); - int index = 0; - for (int i = 0; i < max; i++) { - if (i == this.value.get(index) - 1) { - bits.add(true); - index++; - } else { - bits.add(false); - } - } - - return FixedIntegerEncoder.encode(max, 16) + "0" + FixedBitfieldEncoder.encode(bits, bitFieldLength); - } + return OptimizedFixedRangeEncoder.encode(this.value); } public void decode(String bitString) throws DecodingException { - if (bitString.charAt(16) == '1') { - this.value = 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); - } - } - this.value = value; - } + this.value = OptimizedFixedRangeEncoder.decode(bitString); } public String substring(String bitString, int fromIndex) throws DecodingException { 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 new file mode 100644 index 00000000..0237ed18 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/RangeEntry.java @@ -0,0 +1,42 @@ +package com.iab.gpp.encoder.datatype; + +import java.util.List; + +public class RangeEntry { + + private int key; + private int type; + private List ids; + + public RangeEntry(int key, int type, List ids) { + super(); + this.key = key; + this.type = type; + this.ids = ids; + } + + public int getKey() { + return key; + } + + public void setKey(int key) { + this.key = key; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public List getIds() { + return ids; + } + + public void setIds(List ids) { + this.ids = ids; + } + +} 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 new file mode 100644 index 00000000..de1449b3 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/ArrayOfRangesEntryEncoder.java @@ -0,0 +1,43 @@ +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/OptimizedFibonacciRangeEncoder.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFibonacciRangeEncoder.java new file mode 100644 index 00000000..3492fbcc --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFibonacciRangeEncoder.java @@ -0,0 +1,56 @@ +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; + +public class OptimizedFibonacciRangeEncoder { + + private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE); + + public static String encode(List 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); + int rangeLength = rangeBitString.length(); + int bitFieldLength = max; + + if (rangeLength <= bitFieldLength) { + return FixedIntegerEncoder.encode(max, 16) + "1" + rangeBitString; + } else { + List bits = new ArrayList<>(); + int index = 0; + for (int i = 0; i < max; i++) { + if (i == value.get(index) - 1) { + bits.add(true); + index++; + } else { + bits.add(false); + } + } + 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) { + throw new DecodingException("Undecodable FibonacciIntegerRange '" + bitString + "'"); + } + + if (bitString.charAt(16) == '1') { + 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); + } + } + 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 new file mode 100644 index 00000000..73fb5e68 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/encoder/OptimizedFixedRangeEncoder.java @@ -0,0 +1,57 @@ +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; + +public class OptimizedFixedRangeEncoder { + + private static Pattern BITSTRING_VERIFICATION_PATTERN = Pattern.compile("^[0-1]*$", Pattern.CASE_INSENSITIVE); + + public static String encode(List 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); + int rangeLength = rangeBitString.length(); + int bitFieldLength = max; + + if (rangeLength <= bitFieldLength) { + return FixedIntegerEncoder.encode(max, 16) + "1" + rangeBitString; + } else { + List bits = new ArrayList<>(); + int index = 0; + for (int i = 0; i < max; i++) { + if (i == value.get(index) - 1) { + bits.add(true); + index++; + } else { + bits.add(false); + } + } + + 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) { + throw new DecodingException("Undecodable FixedIntegerRange '" + bitString + "'"); + } + + if (bitString.charAt(16) == '1') { + 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); + } + } + return value; + } + } +} 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 86c91dff..2be571f3 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 @@ -17,6 +17,7 @@ public class TcfCaV1Field { 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 String PUB_PURPOSES_SEGMENT_TYPE = "PubPurposesSegmentType"; public static String PUB_PURPOSES_EXPRESS_CONSENT = "PubPurposesExpressConsent"; @@ -25,4 +26,6 @@ public class TcfCaV1Field { public static String CUSTOM_PURPOSES_EXPRESS_CONSENT = "CustomPurposesExpressConsent"; public static String CUSTOM_PURPOSES_IMPLIED_CONSENT = "CustomPurposesImpliedConsent"; + public static String DISCLOSED_VENDORS_SEGMENT_TYPE = "DisclosedVendorsSegmentType"; + public static String DISCLOSED_VENDORS = "DisclosedVendors"; } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java index 5b8f0b7c..642583c3 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java @@ -57,10 +57,14 @@ public void decodeFromBitString(String bitString) throws DecodingException { for (int i = 0; i < this.fieldOrder.length; i++) { String fieldName = this.fieldOrder[i]; if (this.fields.containsKey(fieldName)) { - AbstractEncodableBitStringDataType field = this.fields.get(fieldName); - String substring = field.substring(bitString, index); - field.decode(substring); - index += substring.length(); + try { + AbstractEncodableBitStringDataType field = this.fields.get(fieldName); + String substring = field.substring(bitString, index); + field.decode(substring); + index += substring.length(); + } catch (StringIndexOutOfBoundsException e) { + continue; + } } else { throw new DecodingException("Field not found: '" + fieldName + "'"); } 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 index d9339189..11c9d789 100644 --- 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 @@ -75,6 +75,8 @@ public void decodeSegmentsFromBitStrings(List segmentBitStrings) throws String substring = field.substring(segmentBitString, index); field.decode(substring); index += substring.length(); + } catch (StringIndexOutOfBoundsException e) { + continue; } catch (Exception e) { throw new DecodingException("Unable to decode " + fieldName, e); } 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 ec3b4891..31bd1914 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 @@ -8,6 +8,7 @@ import java.util.List; import java.util.function.IntSupplier; import java.util.stream.Collectors; +import com.iab.gpp.encoder.datatype.EncodableArrayOfRanges; import com.iab.gpp.encoder.datatype.EncodableBoolean; import com.iab.gpp.encoder.datatype.EncodableDatetime; import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; @@ -67,6 +68,7 @@ private void initFields() { false, false, false, false, false, false, false, false, false, false, false, false, false, false))); fields.put(TcfCaV1Field.VENDOR_EXPRESS_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); fields.put(TcfCaV1Field.VENDOR_IMPLIED_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); + fields.put(TcfCaV1Field.PUB_RESTRICTIONS, new EncodableArrayOfRanges(6, 2, new ArrayList<>())); // publisher purposes segment fields.put(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); @@ -95,6 +97,12 @@ public int getAsInt() { fields.put(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT, new EncodableFlexibleBitfield(getLengthSupplier, new ArrayList<>())); + + // disclosed vendors segment + fields.put(TcfCaV1Field.DISCLOSED_VENDORS_SEGMENT_TYPE, new EncodableFixedInteger(3, 1)); + fields.put(TcfCaV1Field.DISCLOSED_VENDORS, new EncodableOptimizedFixedRange(new ArrayList<>())); + + //@formatter:off String[] coreSegment = new String[] { TcfCaV1Field.VERSION, @@ -111,7 +119,8 @@ public int getAsInt() { TcfCaV1Field.PURPOSES_EXPRESS_CONSENT, TcfCaV1Field.PURPOSES_IMPLIED_CONSENT, TcfCaV1Field.VENDOR_EXPRESS_CONSENT, - TcfCaV1Field.VENDOR_IMPLIED_CONSENT + TcfCaV1Field.VENDOR_IMPLIED_CONSENT, + TcfCaV1Field.PUB_RESTRICTIONS }; String[] publisherPurposesSegment = new String[] { @@ -123,9 +132,15 @@ public int getAsInt() { TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT, }; + String[] disclosedVendorsSegment = new String[] { + TcfCaV1Field.DISCLOSED_VENDORS_SEGMENT_TYPE, + TcfCaV1Field.DISCLOSED_VENDORS + }; + segments = new String[][] { coreSegment, - publisherPurposesSegment + publisherPurposesSegment, + disclosedVendorsSegment }; //@formatter:on } @@ -138,6 +153,9 @@ public String encode() throws EncodingException { encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(0))); if (segmentBitStrings.size() >= 2) { encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(1))); + if (segmentBitStrings.size() >= 3 && !this.getDisclosedVendors().isEmpty()) { + encodedSegments.add(base64UrlEncoder.encode(segmentBitStrings.get(2))); + } } } @@ -161,6 +179,10 @@ public void decode(String encodedSection) throws DecodingException { segmentBitStrings[0] = segmentBitString; break; } + case "001": { + segmentBitStrings[2] = segmentBitString; + break; + } case "011": { segmentBitStrings[1] = segmentBitString; break; @@ -288,4 +310,12 @@ public List getCustomPurposesImpliedConsent() { return (List) this.fields.get(TcfCaV1Field.CUSTOM_PURPOSES_IMPLIED_CONSENT).getValue(); } + public Integer getDisclosedVendorsSegmentType() { + return (Integer) this.fields.get(TcfCaV1Field.DISCLOSED_VENDORS_SEGMENT_TYPE).getValue(); + } + + @SuppressWarnings("unchecked") + public List getDisclosedVendors() { + return (List) this.fields.get(TcfCaV1Field.DISCLOSED_VENDORS).getValue(); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index a28858af..7dcfb79c 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -4,7 +4,6 @@ import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; @@ -18,8 +17,8 @@ import com.iab.gpp.encoder.field.UsCtV1Field; import com.iab.gpp.encoder.field.UsNatV1Field; import com.iab.gpp.encoder.field.UsUtV1Field; -import com.iab.gpp.encoder.field.UspV1Field; import com.iab.gpp.encoder.field.UsVaV1Field; +import com.iab.gpp.encoder.field.UspV1Field; import com.iab.gpp.encoder.section.TcfCaV1; import com.iab.gpp.encoder.section.TcfEuV2; import com.iab.gpp.encoder.section.UsCaV1; @@ -27,8 +26,8 @@ import com.iab.gpp.encoder.section.UsCtV1; import com.iab.gpp.encoder.section.UsNatV1; import com.iab.gpp.encoder.section.UsUtV1; -import com.iab.gpp.encoder.section.UspV1; import com.iab.gpp.encoder.section.UsVaV1; +import com.iab.gpp.encoder.section.UspV1; public class GppModelTest { @@ -111,7 +110,7 @@ public void testEncodeDefaultAll() throws EncodingException, InvalidFieldExcepti String gppString = gppModel.encode(); Assertions.assertEquals( - "DBACOaw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAAA.QA~BAAAAAAA.QA~BAAAAAA~BAAAAAA.QA~BAAAAAAA~BAAAAAAA.QA", + "DBACOaw~CPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA~1---~BAAAAAAAAAA.QA~BAAAAAAA.QA~BAAAAAA~BAAAAAA.QA~BAAAAAAA~BAAAAAAA.QA", gppString); } @@ -339,7 +338,7 @@ public void testEncodeUspV1AndTcfEuV2AndTcfCaV1() String gppString = gppModel.encode(); Assertions.assertEquals( - "DBACOeA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACAC.fHHHA4444ao~1YNN", + "DBACOeA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACACAAA.fHHHA4444ao~1YNN", gppString); Assertions.assertEquals(4, gppString.split("~").length); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRangesTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRangesTest.java new file mode 100644 index 00000000..897db600 --- /dev/null +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRangesTest.java @@ -0,0 +1,158 @@ +package com.iab.gpp.encoder.datatype; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; + +public class EncodableArrayOfRangesTest { + + @Test + public void testEncode1() throws EncodingException { + List value = new ArrayList<>(); + EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2, value); + Assertions.assertEquals("000000000000", + encodableArrayOfRanges.encode()); + } + + @Test + public void testEncode2() throws EncodingException { + List value = new ArrayList<>(); + value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); + EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2, value); + Assertions.assertEquals("0000000000010001011000000000001100000000000000001000000000001000000000000000000000001", + encodableArrayOfRanges.encode()); + } + + @Test + public void testEncode3() throws EncodingException { + List value = new ArrayList<>(); + value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); + value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); + EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2, value); + Assertions.assertEquals("00000000001000010110000000000011000000000000000010000000000010000000000000000000000010001011000000000000111100000000000000000001000000000001", + encodableArrayOfRanges.encode()); + } + + @Test + public void testEncode4() throws EncodingException { + List value = new ArrayList<>(); + value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); + value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); + value.add(new RangeEntry(5, 2, Arrays.asList(28))); + EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2, value); + Assertions.assertEquals("0000000000110001011000000000001100000000000000001000000000001000000000000000000000001000101100000000000011110000000000000000000100000000000100010110000000000001110000000000000000000000000000001", + encodableArrayOfRanges.encode()); + } + + @Test + public void testEncode5() throws EncodingException { + List value = new ArrayList<>(); + value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); + value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); + value.add(new RangeEntry(5, 2, Arrays.asList(28))); + value.add(new RangeEntry(5, 2, Arrays.asList(29))); + EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2, value); + Assertions.assertEquals("0000000001000001011000000000001100000000000000001000000000001000000000000000000000001000101100000000000011110000000000000000000100000000000100010110000000000001110000000000000000000000000000001000101100000000000011101100000000000100000000000011101", + encodableArrayOfRanges.encode()); + } + + @Test + public void testDecode1() throws DecodingException { + EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2); + encodableArrayOfRanges.decode("000000000000"); + Assertions.assertTrue(encodableArrayOfRanges.getValue().isEmpty()); + } + + @Test + public void testDecode2() throws DecodingException { + EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2); + encodableArrayOfRanges.decode("0000000000010001011000000000001100000000000000001000000000001000000000000000000000001"); + Assertions.assertEquals(1, encodableArrayOfRanges.getValue().size()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); + Assertions.assertEquals(Arrays.asList(12, 24, 48), encodableArrayOfRanges.getValue().get(0).getIds()); + } + + @Test + public void testDecode3() throws DecodingException { + EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2); + encodableArrayOfRanges.decode("00000000001000010110000000000011000000000000000010000000000010000000000000000000000010001011000000000000111100000000000000000001000000000001"); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().size()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); + Assertions.assertEquals(encodableArrayOfRanges.getValue().get(0).getIds(), Arrays.asList(12, 24, 48)); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(1).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(1).getType()); + Assertions.assertEquals(encodableArrayOfRanges.getValue().get(1).getIds(), Arrays.asList(18, 30)); + } + + @Test + public void testDecode4() throws DecodingException { + EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2); + encodableArrayOfRanges.decode("0000000000110001011000000000001100000000000000001000000000001000000000000000000000001000101100000000000011110000000000000000000100000000000100010110000000000001110000000000000000000000000000001"); + Assertions.assertEquals(3, encodableArrayOfRanges.getValue().size()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); + Assertions.assertEquals(encodableArrayOfRanges.getValue().get(0).getIds(), Arrays.asList(12, 24, 48)); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(1).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(1).getType()); + Assertions.assertEquals(encodableArrayOfRanges.getValue().get(1).getIds(), Arrays.asList(18, 30)); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(2).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(2).getType()); + Assertions.assertEquals(encodableArrayOfRanges.getValue().get(2).getIds(), Arrays.asList(28)); + } + + @Test + public void testDecode5() throws DecodingException { + EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2); + encodableArrayOfRanges.decode("0000000001000001011000000000001100000000000000001000000000001000000000000000000000001000101100000000000011110000000000000000000100000000000100010110000000000001110000000000000000000000000000001000101100000000000011101100000000000100000000000011101"); + Assertions.assertEquals(4, encodableArrayOfRanges.getValue().size()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); + Assertions.assertEquals(Arrays.asList(12, 24, 48), encodableArrayOfRanges.getValue().get(0).getIds()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(1).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(1).getType()); + Assertions.assertEquals(Arrays.asList(18, 30), encodableArrayOfRanges.getValue().get(1).getIds()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(2).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(2).getType()); + Assertions.assertEquals(Arrays.asList(28), encodableArrayOfRanges.getValue().get(2).getIds()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(3).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(3).getType()); + Assertions.assertEquals(Arrays.asList(29), encodableArrayOfRanges.getValue().get(3).getIds()); + } + + @Test + public void testSubstring1() throws DecodingException { + Assertions.assertEquals("000000000000", new EncodableArrayOfRanges(6, 2).substring( + "01010100000000000011111111000000000001110000000000000000000000000000001000000000000000000000000000000", 6)); + } + + @Test + public void testSubstring2() throws DecodingException { + Assertions.assertEquals("00000000000111111111000000000001110000000000000000000000000000001", + new EncodableArrayOfRanges(6, 2).substring( + "01010100000000000111111111000000000001110000000000000000000000000000001000000000000000000000000000000", + 6)); + } + + @Test + public void testSubstring3() throws DecodingException { + Assertions.assertEquals("000000000001111111110000000000011101100000000000100000000000011101", + new EncodableArrayOfRanges(6, 2).substring( + "01010100000000000111111111000000000001110110000000000010000000000001110100000000000000000000000000000", + 6)); + } + + @Test + public void testSubstring4() throws DecodingException { + Assertions.assertEquals( + "0000000001000001011100000000001100000000000000001000000000001000000000000000000000001000101110000000000011110000000000000000000100000000000100010111000000000001110000000000000000000000000000001000101110000000000011101100000000000100000000000011101", + new EncodableArrayOfRanges(6, 2).substring( + "0101010000000001000001011100000000001100000000000000001000000000001000000000000000000000001000101110000000000011110000000000000000000100000000000100010111000000000001110000000000000000000000000000001000101110000000000011101100000000000100000000000011101010101", + 6)); + } +} diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java index 49b204d2..2940afdd 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java @@ -3,9 +3,12 @@ import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import com.iab.gpp.encoder.datatype.RangeEntry; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; @@ -19,7 +22,7 @@ public void testEncode1() throws EncodingException, InvalidFieldException { TcfCaV1 tcfCaV1 = new TcfCaV1(); tcfCaV1.setFieldValue(TcfCaV1Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); tcfCaV1.setFieldValue(TcfCaV1Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); - Assertions.assertEquals("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA", tcfCaV1.encode()); + Assertions.assertEquals("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA", tcfCaV1.encode()); } @Test @@ -53,7 +56,34 @@ public void testEncode2() throws EncodingException, InvalidFieldException { tcfCaV1.setFieldValue(TcfCaV1Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); tcfCaV1.setFieldValue(TcfCaV1Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); - Assertions.assertEquals("BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACAC.fHHHA4444ao", tcfCaV1.encode()); + Assertions.assertEquals("BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACACAAA.fHHHA4444ao", tcfCaV1.encode()); + } + + @Test + public void testEncode3() throws EncodingException, InvalidFieldException { + + TcfCaV1 tcfCaV1 = new TcfCaV1(); + tcfCaV1.setFieldValue(TcfCaV1Field.DISCLOSED_VENDORS, Arrays.asList(1, 2, 3, 5, 6, 7, 10, 11, 12)); + + tcfCaV1.setFieldValue(TcfCaV1Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); + tcfCaV1.setFieldValue(TcfCaV1Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); + + Assertions.assertEquals("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAAAA.YAAAAAAAAAA.IAGO5w", tcfCaV1.encode()); + } + + @Test + public void testEncode4() throws EncodingException, InvalidFieldException { + + List pubRestrictions = new ArrayList<>(); + pubRestrictions.add(new RangeEntry(1, 1, Arrays.asList(1, 2, 3, 5, 6, 7, 9))); + + TcfCaV1 tcfCaV1 = new TcfCaV1(); + tcfCaV1.setFieldValue(TcfCaV1Field.PUB_RESTRICTIONS, pubRestrictions); + + tcfCaV1.setFieldValue(TcfCaV1Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); + tcfCaV1.setFieldValue(TcfCaV1Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); + + Assertions.assertEquals("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAACCgAS7o.YAAAAAAAAAA", tcfCaV1.encode()); } @Test @@ -136,4 +166,12 @@ public void testDecode2() throws DecodingException { Assertions.assertEquals(5, tcfCaV1.getId()); Assertions.assertEquals(3, tcfCaV1.getPubPurposesSegmentType()); } + + @Test + public void testDecode3() throws DecodingException { + TcfCaV1 tcfCaV1 = new TcfCaV1("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAA.YAAAAAAAAAA.IAGO5w"); + + Assertions.assertEquals(1, tcfCaV1.getDisclosedVendorsSegmentType()); + Assertions.assertEquals(Arrays.asList(1, 2, 3, 5, 6, 7, 10, 11, 12), tcfCaV1.getDisclosedVendors()); + } } From 8af6c08104c8270e06b6ab2090452da879d818e6 Mon Sep 17 00:00:00 2001 From: chad Date: Sat, 7 Oct 2023 11:28:08 -0600 Subject: [PATCH 16/36] deprecate multi-state usp* methods --- .../java/com/iab/gpp/encoder/GppModel.java | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) 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 9877500a..7e3305c6 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 @@ -18,8 +18,8 @@ import com.iab.gpp.encoder.section.UsCtV1; import com.iab.gpp.encoder.section.UsNatV1; import com.iab.gpp.encoder.section.UsUtV1; -import com.iab.gpp.encoder.section.UspV1; import com.iab.gpp.encoder.section.UsVaV1; +import com.iab.gpp.encoder.section.UspV1; public class GppModel { private Map sections = new HashMap<>(); @@ -160,26 +160,80 @@ public UspV1 getUspV1Section() { return (UspV1) getSection(UspV1.NAME); } + /** + * @deprecated + * Use {@link #getUsNatV1Section()} instead. + */ + @Deprecated + public UsNatV1 getUspNatV1Section() { + return (UsNatV1) getSection(UsNatV1.NAME); + } + public UsNatV1 getUsNatV1Section() { return (UsNatV1) getSection(UsNatV1.NAME); } + /** + * @deprecated + * Use {@link #getUsCaV1Section()} instead. + */ + @Deprecated + public UsCaV1 getUspCaV1Section() { + return (UsCaV1) getSection(UsCaV1.NAME); + } + public UsCaV1 getUsCaV1Section() { return (UsCaV1) getSection(UsCaV1.NAME); } + /** + * @deprecated + * Use {@link #getUsVaV1Section()} instead. + */ + @Deprecated + public UsVaV1 getUspVaV1Section() { + return (UsVaV1) getSection(UsVaV1.NAME); + } + public UsVaV1 getUsVaV1Section() { return (UsVaV1) getSection(UsVaV1.NAME); } + /** + * @deprecated + * Use {@link #getUsCoV1Section()} instead. + */ + @Deprecated + public UsCoV1 getUspCoV1Section() { + return (UsCoV1) getSection(UsCoV1.NAME); + } + public UsCoV1 getUsCoV1Section() { return (UsCoV1) getSection(UsCoV1.NAME); } + /** + * @deprecated + * Use {@link #getUsUtV1Section()} instead. + */ + @Deprecated + public UsUtV1 getUspUtV1Section() { + return (UsUtV1) getSection(UsUtV1.NAME); + } + public UsUtV1 getUsUtV1Section() { return (UsUtV1) getSection(UsUtV1.NAME); } + /** + * @deprecated + * Use {@link #getUsCtV1Section()} instead. + */ + @Deprecated + public UsCtV1 getUspCtV1Section() { + return (UsCtV1) getSection(UsCtV1.NAME); + } + public UsCtV1 getUsCtV1Section() { return (UsCtV1) getSection(UsCtV1.NAME); } From aa2bfc2d817bc5a4b4c132821c04ecdd8d2e341c Mon Sep 17 00:00:00 2001 From: chad Date: Sat, 7 Oct 2023 12:44:52 -0600 Subject: [PATCH 17/36] substring error handling --- .../AbstractEncodableBitStringDataType.java | 14 +- .../datatype/EncodableArrayOfRanges.java | 125 ++++++++++-------- .../encoder/datatype/EncodableBoolean.java | 29 +++- .../encoder/datatype/EncodableDatetime.java | 32 ++++- .../datatype/EncodableFibonacciInteger.java | 40 ++++-- .../EncodableFibonacciIntegerRange.java | 46 +++++-- .../datatype/EncodableFixedBitfield.java | 35 ++++- .../datatype/EncodableFixedInteger.java | 33 ++++- .../datatype/EncodableFixedIntegerList.java | 31 ++++- .../datatype/EncodableFixedIntegerRange.java | 46 +++++-- .../datatype/EncodableFixedString.java | 30 ++++- .../datatype/EncodableFlexibleBitfield.java | 30 ++++- .../EncodableOptimizedFibonacciRange.java | 39 ++++-- .../EncodableOptimizedFixedRange.java | 39 ++++-- .../encoder/datatype/SubstringException.java | 18 +++ .../AbstractEncodableBitStringSection.java | 13 +- ...actEncodableSegmentedBitStringSection.java | 42 +++--- .../com/iab/gpp/encoder/section/TcfCaV1.java | 2 +- .../com/iab/gpp/encoder/GppModelTest.java | 17 ++- .../datatype/EncodableArrayOfRangesTest.java | 8 +- .../datatype/EncodableBooleanTest.java | 4 +- .../datatype/EncodableDatetimeTest.java | 4 +- .../EncodableFibonacciIntegerRangeTest.java | 2 +- .../EncodableFibonacciIntegerTest.java | 2 +- .../datatype/EncodableFixedBitfieldTest.java | 4 +- .../EncodableFixedIntegerListTest.java | 4 +- .../EncodableFixedIntegerRangeTest.java | 9 +- .../datatype/EncodableFixedIntegerTest.java | 4 +- .../datatype/EncodableFixedStringTest.java | 4 +- .../EncodableOptimizedFixedRangeTest.java | 4 +- .../iab/gpp/encoder/section/HeaderV1Test.java | 7 + .../iab/gpp/encoder/section/TcfCaV1Test.java | 7 + .../iab/gpp/encoder/section/TcfEuV2Test.java | 7 + .../iab/gpp/encoder/section/UsCaV1Test.java | 7 + .../iab/gpp/encoder/section/UsCoV1Test.java | 7 + .../iab/gpp/encoder/section/UsCtV1Test.java | 7 + .../iab/gpp/encoder/section/UsNatV1Test.java | 7 + .../iab/gpp/encoder/section/UsUtV1Test.java | 7 + .../iab/gpp/encoder/section/UsVaV1Test.java | 7 + 39 files changed, 561 insertions(+), 212 deletions(-) create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/SubstringException.java 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 27359760..a26691ad 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 @@ -4,10 +4,12 @@ import com.iab.gpp.encoder.error.EncodingException; public abstract class AbstractEncodableBitStringDataType { + // this if for backwards compatibility with the newer fields + protected boolean hardFailIfMissing = true; protected T value; - protected AbstractEncodableBitStringDataType() { - + protected AbstractEncodableBitStringDataType(boolean hardFailIfMissing) { + this.hardFailIfMissing = hardFailIfMissing; } public boolean hasValue() { @@ -23,9 +25,15 @@ public void setValue(Object value) { this.value = (T) value; } + public boolean getHardFailIfMissing() { + return this.hardFailIfMissing; + } + public abstract String encode() throws EncodingException; public abstract void decode(String bitString) throws DecodingException; - public abstract String substring(String bitString, int fromIndex) throws DecodingException; + public abstract String substring(String bitString, int fromIndex) throws SubstringException; + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRanges.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRanges.java index 32ec28a6..3c5237a0 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRanges.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRanges.java @@ -13,13 +13,20 @@ public class EncodableArrayOfRanges extends AbstractEncodableBitStringDataType value) { - super(); + super(true); + this.keyBitStringLength = keyBitStringLength; + this.typeBitStringLength = typeBitStringLength; + setValue(value); + } + + public EncodableArrayOfRanges(int keyBitStringLength, int typeBitStringLength, List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); this.keyBitStringLength = keyBitStringLength; this.typeBitStringLength = typeBitStringLength; setValue(value); @@ -27,68 +34,80 @@ public EncodableArrayOfRanges(int keyBitStringLength, int typeBitStringLength, L @Override public String encode() throws EncodingException { - List entries = this.value; - - StringBuilder sb = new StringBuilder(); - sb.append(FixedIntegerEncoder.encode(entries.size(), 12)); - for (RangeEntry entry : entries) { - sb.append(FixedIntegerEncoder.encode(entry.getKey(), keyBitStringLength)) - .append(FixedIntegerEncoder.encode(entry.getType(), typeBitStringLength)) - .append(OptimizedFixedRangeEncoder.encode(entry.getIds())); + try { + List entries = this.value; + + StringBuilder sb = new StringBuilder(); + sb.append(FixedIntegerEncoder.encode(entries.size(), 12)); + for (RangeEntry entry : entries) { + sb.append(FixedIntegerEncoder.encode(entry.getKey(), keyBitStringLength)) + .append(FixedIntegerEncoder.encode(entry.getType(), typeBitStringLength)) + .append(OptimizedFixedRangeEncoder.encode(entry.getIds())); + } + + return sb.toString(); + } catch (Exception e) { + throw new EncodingException(e); } - - return sb.toString(); } @Override public void decode(String bitString) throws DecodingException { - List entries = new ArrayList<>(); - - int size = FixedIntegerEncoder.decode(bitString.substring(0, 12)); - int index = 12; - for (int i = 0; i < size; i++) { - int key = FixedIntegerEncoder.decode(bitString.substring(index, index + keyBitStringLength)); - index += keyBitStringLength; - - int type = FixedIntegerEncoder.decode(bitString.substring(index, index + typeBitStringLength)); - index += typeBitStringLength; - - String substring = new EncodableOptimizedFixedRange().substring(bitString, index); - List ids = OptimizedFixedRangeEncoder.decode(substring); - index += substring.length(); - - entries.add(new RangeEntry(key, type, ids)); + try { + List entries = new ArrayList<>(); + + int size = FixedIntegerEncoder.decode(bitString.substring(0, 12)); + int index = 12; + for (int i = 0; i < size; i++) { + int key = FixedIntegerEncoder.decode(bitString.substring(index, index + keyBitStringLength)); + index += keyBitStringLength; + + int type = FixedIntegerEncoder.decode(bitString.substring(index, index + typeBitStringLength)); + index += typeBitStringLength; + + String substring = new EncodableOptimizedFixedRange().substring(bitString, index); + List ids = OptimizedFixedRangeEncoder.decode(substring); + index += substring.length(); + + entries.add(new RangeEntry(key, type, ids)); + } + + this.value = entries; + } catch (Exception e) { + throw new DecodingException(e); } - - this.value = entries; } @Override - public String substring(String bitString, int fromIndex) throws DecodingException { - StringBuilder sb = new StringBuilder(); - sb.append(bitString.substring(fromIndex, fromIndex + 12)); - - int size = FixedIntegerEncoder.decode(sb.toString()); - - int index = fromIndex + sb.length(); - for (int i = 0; i < size; i++) { - sb.append(bitString.substring(index, index + 8)); - index += 8; - - String substring = null; - int max = FixedIntegerEncoder.decode(bitString.substring(index, index + 16)); - if (bitString.charAt(index + 16) == '1') { - substring = bitString.substring(index, index + 17) - + new EncodableFixedIntegerRange().substring(bitString, index + 17); - } else { - substring = bitString.substring(index, index + 17 + max); + public String substring(String 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(); + for (int i = 0; i < size; i++) { + sb.append(bitString.substring(index, index + 8)); + index += 8; + + String substring = null; + int max = FixedIntegerEncoder.decode(bitString.substring(index, index + 16)); + if (bitString.charAt(index + 16) == '1') { + substring = bitString.substring(index, index + 17) + + new EncodableFixedIntegerRange().substring(bitString, index + 17); + } else { + substring = bitString.substring(index, index + 17 + max); + } + index += substring.length(); + + sb.append(substring); } - index += substring.length(); - - sb.append(substring); + + return sb.toString(); + } catch (Exception e) { + throw new SubstringException(e); } - - return sb.toString(); } } 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 09d47ac7..c90ec06b 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 @@ -7,24 +7,41 @@ public class EncodableBoolean extends AbstractEncodableBitStringDataType { protected EncodableBoolean() { - super(); + super(true); } public EncodableBoolean(Boolean value) { - super(); + super(true); + setValue(value); + } + + public EncodableBoolean(Boolean value, boolean hardFailIfMissing) { + super(hardFailIfMissing); setValue(value); } public String encode() throws EncodingException { - return BooleanEncoder.encode(this.value); + try { + return BooleanEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); + } } public void decode(String bitString) throws DecodingException { - this.value = BooleanEncoder.decode(bitString); + try { + this.value = BooleanEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { + public String substring(String bitString, int fromIndex) throws SubstringException { // TODO: validate - return bitString.substring(fromIndex, fromIndex + 1); + try { + return bitString.substring(fromIndex, fromIndex + 1); + } catch (Exception e) { + throw new SubstringException(e); + } } } 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 f146d0aa..699228a8 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 @@ -3,28 +3,46 @@ import java.time.ZonedDateTime; 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 { protected EncodableDatetime() { - super(); + super(true); } public EncodableDatetime(ZonedDateTime value) { - super(); + super(true); setValue(value); } - public String encode() { - return DatetimeEncoder.encode(this.value); + public EncodableDatetime(ZonedDateTime value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + setValue(value); + } + + public String encode() throws EncodingException { + try { + return DatetimeEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); + } } public void decode(String bitString) throws DecodingException { - this.value = DatetimeEncoder.decode(bitString); + try { + this.value = DatetimeEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { + public String substring(String bitString, int fromIndex) throws SubstringException { // TODO: validate - return bitString.substring(fromIndex, fromIndex + 36); + try { + return bitString.substring(fromIndex, fromIndex + 36); + } catch (Exception e) { + throw new SubstringException(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 5d4e1783..4fc36230 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 @@ -2,32 +2,50 @@ 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 { protected EncodableFibonacciInteger() { - super(); + super(true); } public EncodableFibonacciInteger(Integer value) { - super(); + super(true); setValue(value); } - public String encode() { - return FibonacciIntegerEncoder.encode(this.value); + public EncodableFibonacciInteger(Integer value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + setValue(value); + } + + public String encode() throws EncodingException { + try { + return FibonacciIntegerEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); + } } public void decode(String bitString) throws DecodingException { - this.value = FibonacciIntegerEncoder.decode(bitString); + try { + this.value = FibonacciIntegerEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { - int index = bitString.indexOf("11", fromIndex); - if (index > 0) { - return bitString.substring(fromIndex, index + 2); - } else { - return bitString; + public String substring(String bitString, int fromIndex) throws SubstringException { + try { + int index = bitString.indexOf("11", fromIndex); + if (index > 0) { + return bitString.substring(fromIndex, index + 2); + } else { + return bitString; + } + } catch (Exception e) { + throw new SubstringException(e); } } } 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 eaff0382..e26c623b 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 @@ -6,38 +6,56 @@ import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerRangeEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class EncodableFibonacciIntegerRange extends AbstractEncodableBitStringDataType> { protected EncodableFibonacciIntegerRange() { - super(); + super(true); } public EncodableFibonacciIntegerRange(List value) { - super(); + super(true); setValue(value); } - public String encode() { - return FibonacciIntegerRangeEncoder.encode(this.value); + public EncodableFibonacciIntegerRange(List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + setValue(value); + } + + public String encode() throws EncodingException { + try { + return FibonacciIntegerRangeEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); + } } public void decode(String bitString) throws DecodingException { - this.value = FibonacciIntegerRangeEncoder.decode(bitString); + try { + this.value = FibonacciIntegerRangeEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) throws DecodingException { + public String substring(String bitString, int fromIndex) throws SubstringException { // TODO: add some validation - int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, 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; - } else { - index = bitString.indexOf("11", index + 1) + 2; + try { + int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, 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; + } else { + index = bitString.indexOf("11", index + 1) + 2; + } } + return bitString.substring(fromIndex, index); + } catch (Exception e) { + throw new SubstringException(e); } - return bitString.substring(fromIndex, index); } @SuppressWarnings("unchecked") 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 e0ae9b8e..ce04f0d3 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 @@ -11,27 +11,50 @@ public class EncodableFixedBitfield extends AbstractEncodableBitStringDataType value) { - super(); + 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() throws EncodingException { - return FixedBitfieldEncoder.encode(this.value, this.numElements); + try { + return FixedBitfieldEncoder.encode(this.value, this.numElements); + } catch (Exception e) { + throw new EncodingException(e); + } } public void decode(String bitString) throws DecodingException { - this.value = FixedBitfieldEncoder.decode(bitString); + try { + this.value = FixedBitfieldEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { + public String substring(String bitString, int fromIndex) throws SubstringException { // TODO: validate - return bitString.substring(fromIndex, fromIndex + this.numElements); + try { + return bitString.substring(fromIndex, fromIndex + this.numElements); + } catch (Exception e) { + throw new SubstringException(e); + } } @SuppressWarnings("unchecked") 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 8b0fcb7e..81157939 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 @@ -2,32 +2,51 @@ 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 { private int bitStringLength; protected EncodableFixedInteger(int bitStringLength) { - super(); + super(true); this.bitStringLength = bitStringLength; } public EncodableFixedInteger(int bitStringLength, Integer value) { - super(); + super(true); this.bitStringLength = bitStringLength; setValue(value); } - public String encode() { - return FixedIntegerEncoder.encode(this.value, this.bitStringLength); + public EncodableFixedInteger(int bitStringLength, Integer value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + this.bitStringLength = bitStringLength; + setValue(value); + } + + public String encode() throws EncodingException { + try { + return FixedIntegerEncoder.encode(this.value, this.bitStringLength); + } catch (Exception e) { + throw new EncodingException(e); + } } public void decode(String bitString) throws DecodingException { - this.value = FixedIntegerEncoder.decode(bitString); + try { + this.value = FixedIntegerEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { + public String substring(String bitString, int fromIndex) throws SubstringException { // TODO: validate - return bitString.substring(fromIndex, fromIndex + this.bitStringLength); + try { + return bitString.substring(fromIndex, fromIndex + this.bitStringLength); + } catch (Exception e) { + throw new SubstringException(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 ccaca886..80c1c228 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 @@ -12,29 +12,48 @@ public class EncodableFixedIntegerList extends AbstractEncodableBitStringDataTyp private int numElements; protected EncodableFixedIntegerList(int elementBitStringLength, int numElements) { - super(); + super(true); this.elementBitStringLength = elementBitStringLength; this.numElements = numElements; } public EncodableFixedIntegerList(int elementBitStringLength, List value) { - super(); + super(true); + this.elementBitStringLength = elementBitStringLength; + this.numElements = value.size(); + setValue(value); + } + + public EncodableFixedIntegerList(int elementBitStringLength, List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); this.elementBitStringLength = elementBitStringLength; this.numElements = value.size(); setValue(value); } public String encode() throws EncodingException { - return FixedIntegerListEncoder.encode(this.value, this.elementBitStringLength, this.numElements); + try { + return FixedIntegerListEncoder.encode(this.value, this.elementBitStringLength, this.numElements); + } catch (Exception e) { + throw new EncodingException(e); + } } public void decode(String bitString) throws DecodingException { - this.value = FixedIntegerListEncoder.decode(bitString, this.elementBitStringLength, this.numElements); + try { + this.value = FixedIntegerListEncoder.decode(bitString, this.elementBitStringLength, this.numElements); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { + public String substring(String bitString, int fromIndex) throws SubstringException { // TODO: validate - return bitString.substring(fromIndex, fromIndex + (this.elementBitStringLength * numElements)); + try { + return bitString.substring(fromIndex, fromIndex + (this.elementBitStringLength * numElements)); + } catch (Exception e) { + throw new SubstringException(e); + } } @SuppressWarnings("unchecked") 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 e43751af..a7a5ca61 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 @@ -6,38 +6,56 @@ import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class EncodableFixedIntegerRange extends AbstractEncodableBitStringDataType> { protected EncodableFixedIntegerRange() { - super(); + super(true); } public EncodableFixedIntegerRange(List value) { - super(); + super(true); setValue(value); } - public String encode() { - return FixedIntegerRangeEncoder.encode(this.value); + public EncodableFixedIntegerRange(List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + setValue(value); + } + + public String encode() throws EncodingException { + try { + return FixedIntegerRangeEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); + } } public void decode(String bitString) throws DecodingException { - this.value = FixedIntegerRangeEncoder.decode(bitString); + try { + this.value = FixedIntegerRangeEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) throws DecodingException { + public String substring(String bitString, int fromIndex) throws SubstringException { // TODO: add some validation - int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 12)); - int index = fromIndex + 12; - for (int i = 0; i < count; i++) { - if (bitString.charAt(index) == '1') { - index += 33; - } else { - index += 17; + try { + int count = FixedIntegerEncoder.decode(bitString.substring(fromIndex, fromIndex + 12)); + int index = fromIndex + 12; + for (int i = 0; i < count; i++) { + if (bitString.charAt(index) == '1') { + index += 33; + } else { + index += 17; + } } + return bitString.substring(fromIndex, index); + } catch (Exception e) { + throw new SubstringException(e); } - return bitString.substring(fromIndex, index); } @SuppressWarnings("unchecked") 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 ed736fc2..6311cffa 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 @@ -9,26 +9,44 @@ public class EncodableFixedString extends AbstractEncodableBitStringDataType value) { - super(); + super(true); + this.getLengthSupplier = getLengthSupplier; + this.setValue(value); + } + + public EncodableFlexibleBitfield(IntSupplier getLengthSupplier, List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); this.getLengthSupplier = getLengthSupplier; this.setValue(value); } public String encode() throws EncodingException { - return FixedBitfieldEncoder.encode(this.value, this.getLengthSupplier.getAsInt()); + try { + return FixedBitfieldEncoder.encode(this.value, this.getLengthSupplier.getAsInt()); + } catch (Exception e) { + throw new EncodingException(e); + } } public void decode(String bitString) throws DecodingException { - this.value = FixedBitfieldEncoder.decode(bitString); + try { + this.value = FixedBitfieldEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) { + public String substring(String bitString, int fromIndex) throws SubstringException { // TODO: validate - return bitString.substring(fromIndex, fromIndex + this.getLengthSupplier.getAsInt()); + try { + return bitString.substring(fromIndex, fromIndex + this.getLengthSupplier.getAsInt()); + } catch (Exception e) { + throw new SubstringException(e); + } } @SuppressWarnings("unchecked") 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 fe111de2..2cc7bb62 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 @@ -11,29 +11,46 @@ public class EncodableOptimizedFibonacciRange extends AbstractEncodableBitStringDataType> { protected EncodableOptimizedFibonacciRange() { - super(); + super(true); } public EncodableOptimizedFibonacciRange(List value) { - super(); + super(true); + setValue(value); + } + + public EncodableOptimizedFibonacciRange(List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); setValue(value); } public String encode() throws EncodingException { - return OptimizedFibonacciRangeEncoder.encode(this.value); + try { + return OptimizedFibonacciRangeEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); + } } public void decode(String bitString) throws DecodingException { - this.value = OptimizedFibonacciRangeEncoder.decode(bitString); + try { + this.value = OptimizedFibonacciRangeEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) throws DecodingException { - 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)); - } else { - return bitString.substring(fromIndex, fromIndex + 17 + max); + public String substring(String 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)); + } else { + return bitString.substring(fromIndex, fromIndex + 17 + max); + } + } catch (Exception e) { + throw new SubstringException(e); } } 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 b37a23a7..46b8c8a0 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 @@ -11,29 +11,46 @@ public class EncodableOptimizedFixedRange extends AbstractEncodableBitStringDataType> { protected EncodableOptimizedFixedRange() { - super(); + super(true); } public EncodableOptimizedFixedRange(List value) { - super(); + super(true); + setValue(value); + } + + public EncodableOptimizedFixedRange(List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); setValue(value); } public String encode() throws EncodingException { - return OptimizedFixedRangeEncoder.encode(this.value); + try { + return OptimizedFixedRangeEncoder.encode(this.value); + } catch (Exception e) { + throw new EncodingException(e); + } } public void decode(String bitString) throws DecodingException { - this.value = OptimizedFixedRangeEncoder.decode(bitString); + try { + this.value = OptimizedFixedRangeEncoder.decode(bitString); + } catch (Exception e) { + throw new DecodingException(e); + } } - public String substring(String bitString, int fromIndex) throws DecodingException { - 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); - } else { - return bitString.substring(fromIndex, fromIndex + 17 + max); + public String substring(String 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); + } else { + return bitString.substring(fromIndex, fromIndex + 17 + max); + } + } catch (Exception e) { + throw new SubstringException(e); } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/SubstringException.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/SubstringException.java new file mode 100644 index 00000000..e9df8ca6 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/SubstringException.java @@ -0,0 +1,18 @@ +package com.iab.gpp.encoder.datatype; + +public class SubstringException extends Exception { + + private static final long serialVersionUID = 1825100490468259890L; + + public SubstringException(String msg) { + super(msg); + } + + public SubstringException(Exception e) { + super(e); + } + + public SubstringException(String msg, Exception e) { + super(msg, e); + } +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java index 642583c3..f6637dad 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java @@ -2,6 +2,7 @@ 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; @@ -57,13 +58,19 @@ public void decodeFromBitString(String bitString) throws DecodingException { for (int i = 0; i < this.fieldOrder.length; i++) { String fieldName = this.fieldOrder[i]; if (this.fields.containsKey(fieldName)) { + AbstractEncodableBitStringDataType field = this.fields.get(fieldName); try { - AbstractEncodableBitStringDataType field = this.fields.get(fieldName); String substring = field.substring(bitString, index); field.decode(substring); index += substring.length(); - } catch (StringIndexOutOfBoundsException e) { - continue; + } 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 + "'"); 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 index 11c9d789..eb5d5459 100644 --- 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 @@ -4,6 +4,7 @@ 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; @@ -64,30 +65,37 @@ public List encodeSegmentsToBitStrings() throws EncodingException { public void decodeSegmentsFromBitStrings(List segmentBitStrings) throws DecodingException { for (int i = 0; i < this.segments.length && i < segmentBitStrings.size(); i++) { - String segmentBitString = segmentBitStrings.get(i); - if (segmentBitString != null && segmentBitString.length() > 0) { - int index = 0; - 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); - String substring = field.substring(segmentBitString, index); - field.decode(substring); - index += substring.length(); - } catch (StringIndexOutOfBoundsException e) { - continue; - } catch (Exception e) { + 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; } - } else { - throw new DecodingException("Field not found: '" + fieldName + "'"); + } 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; 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 31bd1914..52e9a7c1 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 @@ -68,7 +68,7 @@ private void initFields() { false, false, false, false, false, false, false, false, false, false, false, false, false, false))); fields.put(TcfCaV1Field.VENDOR_EXPRESS_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); fields.put(TcfCaV1Field.VENDOR_IMPLIED_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); - fields.put(TcfCaV1Field.PUB_RESTRICTIONS, new EncodableArrayOfRanges(6, 2, new ArrayList<>())); + fields.put(TcfCaV1Field.PUB_RESTRICTIONS, new EncodableArrayOfRanges(6, 2, new ArrayList<>(), false)); // publisher purposes segment fields.put(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index 7dcfb79c..f8b9c3a5 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -60,12 +60,16 @@ public void testEncodeDefault() throws EncodingException, LazyDecodingException @Test public void testDecodingException() { - try { - GppModel gppModel = new GppModel("invalid gpp string"); - Assertions.fail("Expected LazyDecodingException"); - } catch (DecodingException e) { - - } + Assertions.assertThrows(DecodingException.class, () -> { + new GppModel("invalid gpp string"); + }); + } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new GppModel("z"); + }); } @Test @@ -672,4 +676,5 @@ public void testConsistency() throws InvalidFieldException, EncodingException, D decodedModel.getFieldValue(TcfEuV2.NAME, TcfEuV2Field.VENDOR_CONSENTS)); } + } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRangesTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRangesTest.java index 897db600..4893901f 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRangesTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRangesTest.java @@ -126,13 +126,13 @@ public void testDecode5() throws DecodingException { } @Test - public void testSubstring1() throws DecodingException { + public void testSubstring1() throws DecodingException, SubstringException { Assertions.assertEquals("000000000000", new EncodableArrayOfRanges(6, 2).substring( "01010100000000000011111111000000000001110000000000000000000000000000001000000000000000000000000000000", 6)); } @Test - public void testSubstring2() throws DecodingException { + public void testSubstring2() throws DecodingException, SubstringException { Assertions.assertEquals("00000000000111111111000000000001110000000000000000000000000000001", new EncodableArrayOfRanges(6, 2).substring( "01010100000000000111111111000000000001110000000000000000000000000000001000000000000000000000000000000", @@ -140,7 +140,7 @@ public void testSubstring2() throws DecodingException { } @Test - public void testSubstring3() throws DecodingException { + public void testSubstring3() throws DecodingException, SubstringException { Assertions.assertEquals("000000000001111111110000000000011101100000000000100000000000011101", new EncodableArrayOfRanges(6, 2).substring( "01010100000000000111111111000000000001110110000000000010000000000001110100000000000000000000000000000", @@ -148,7 +148,7 @@ public void testSubstring3() throws DecodingException { } @Test - public void testSubstring4() throws DecodingException { + public void testSubstring4() throws DecodingException, SubstringException { Assertions.assertEquals( "0000000001000001011100000000001100000000000000001000000000001000000000000000000000001000101110000000000011110000000000000000000100000000000100010111000000000001110000000000000000000000000000001000101110000000000011101100000000000100000000000011101", new EncodableArrayOfRanges(6, 2).substring( diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableBooleanTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableBooleanTest.java index 3ea44dbb..d015acd1 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableBooleanTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableBooleanTest.java @@ -6,13 +6,13 @@ public class EncodableBooleanTest { @Test - public void testSubstring1() { + public void testSubstring1() throws SubstringException { Assertions.assertEquals("000000000000000000000000000000000000", new EncodableDatetime().substring("10000000000000000000000000000000000001", 1)); } @Test - public void testSubstring2() { + public void testSubstring2() throws SubstringException { Assertions.assertEquals("111111111111111111111111111111111111", new EncodableDatetime().substring("01111111111111111111111111111111111110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableDatetimeTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableDatetimeTest.java index d7a6a759..43d271ba 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableDatetimeTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableDatetimeTest.java @@ -7,13 +7,13 @@ public class EncodableDatetimeTest { @Test - public void testSubstring1() throws DecodingException { + public void testSubstring1() throws DecodingException, SubstringException { Assertions.assertEquals("000000000000000000000000000000000000", new EncodableDatetime().substring("10000000000000000000000000000000000001", 1)); } @Test - public void testSubstring2() throws DecodingException { + public void testSubstring2() throws DecodingException, SubstringException { Assertions.assertEquals("111111111111111111111111111111111111", new EncodableDatetime().substring("01111111111111111111111111111111111110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRangeTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRangeTest.java index faac8ddc..765d5154 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRangeTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerRangeTest.java @@ -7,7 +7,7 @@ public class EncodableFibonacciIntegerRangeTest { @Test - public void testSubstring1() throws DecodingException { + public void testSubstring1() throws DecodingException, SubstringException { Assertions.assertEquals("0000000000100001110110011", new EncodableFibonacciIntegerRange().substring("100000000001000011101100110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerTest.java index bb982c7f..61dd7d0a 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFibonacciIntegerTest.java @@ -7,7 +7,7 @@ public class EncodableFibonacciIntegerTest { @Test - public void testSubstring1() throws DecodingException { + public void testSubstring1() throws DecodingException, SubstringException { Assertions.assertEquals("0011", new EncodableFibonacciInteger().substring("100111", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfieldTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfieldTest.java index f448f433..89ad98af 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfieldTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedBitfieldTest.java @@ -6,12 +6,12 @@ public class EncodableFixedBitfieldTest { @Test - public void testSubstring1() { + public void testSubstring1() throws SubstringException { Assertions.assertEquals("000", new EncodableFixedBitfield(3).substring("10001", 1)); } @Test - public void testSubstring2() { + public void testSubstring2() throws SubstringException { Assertions.assertEquals("111", new EncodableFixedBitfield(3).substring("01110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerListTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerListTest.java index 9d33e1da..7146cc01 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerListTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerListTest.java @@ -6,12 +6,12 @@ public class EncodableFixedIntegerListTest { @Test - public void testSubstring1() { + public void testSubstring1() throws SubstringException { Assertions.assertEquals("1000", new EncodableFixedIntegerList(2, 2).substring("10001", 0)); } @Test - public void testSubstring2() { + public void testSubstring2() throws SubstringException { Assertions.assertEquals("1110", new EncodableFixedIntegerList(2, 2).substring("01110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRangeTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRangeTest.java index 51a16c39..0982aa40 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRangeTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerRangeTest.java @@ -4,32 +4,33 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; public class EncodableFixedIntegerRangeTest { @Test - public void testSubstring1() throws DecodingException { + public void testSubstring1() throws DecodingException, SubstringException { Assertions.assertEquals("00000000001000000000000000011100000000000001010000000000001000", new EncodableFixedIntegerRange().substring("1000000000010000000000000000111000000000000010100000000000010001", 1)); } @Test - public void testSubstring2() throws DecodingException { + public void testSubstring2() throws DecodingException, SubstringException { Assertions.assertEquals("00000000000100000000000011101", new EncodableFixedIntegerRange().substring( "000010001111010010000110111111111100000000001111010010000110111111111100000000000000000000000000000000000000000100001101000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110110000000000010000000000001110100000000000000000000000000000", 230)); } @Test - public void testEncode1() { + public void testEncode1() throws EncodingException { EncodableFixedIntegerRange encodableFixedIntegerRange = new EncodableFixedIntegerRange(); encodableFixedIntegerRange.setValue(Arrays.asList(28)); Assertions.assertEquals("00000000000100000000000011100", encodableFixedIntegerRange.encode()); } @Test - public void testEncode2() { + public void testEncode2() throws EncodingException { EncodableFixedIntegerRange encodableFixedIntegerRange = new EncodableFixedIntegerRange(); encodableFixedIntegerRange.setValue(Arrays.asList(29)); Assertions.assertEquals("00000000000100000000000011101", encodableFixedIntegerRange.encode()); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerTest.java index 1236da01..709fd156 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedIntegerTest.java @@ -6,12 +6,12 @@ public class EncodableFixedIntegerTest { @Test - public void testSubstring1() { + public void testSubstring1() throws SubstringException { Assertions.assertEquals("000", new EncodableFixedInteger(3).substring("10001", 1)); } @Test - public void testSubstring2() { + public void testSubstring2() throws SubstringException { Assertions.assertEquals("111", new EncodableFixedInteger(3).substring("01110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedStringTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedStringTest.java index a9014d8e..969a6c15 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedStringTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableFixedStringTest.java @@ -6,12 +6,12 @@ public class EncodableFixedStringTest { @Test - public void testSubstring1() { + public void testSubstring1() throws SubstringException { Assertions.assertEquals("000000000000", new EncodableFixedString(2).substring("10000000000001", 1)); } @Test - public void testSubstring2() { + public void testSubstring2() throws SubstringException { Assertions.assertEquals("111111111111", new EncodableFixedString(2).substring("01111111111110", 1)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRangeTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRangeTest.java index 73af6f6e..8210dd22 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRangeTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableOptimizedFixedRangeTest.java @@ -60,14 +60,14 @@ public void testDecode4() throws DecodingException { } @Test - public void testSubstring1() throws DecodingException { + public void testSubstring1() throws DecodingException, SubstringException { Assertions.assertEquals("000000000001110000000000000000000000000000001", encodableOptimizedFixedRange.substring( "000010001111010010000110111111111100000000001111010010000110111111111100000000000000000000000000000000000000000100001101000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110000000000000000000000000000001000000000000000000000000000000", 213)); } @Test - public void testSubstring2() throws DecodingException { + public void testSubstring2() throws DecodingException, SubstringException { Assertions.assertEquals("0000000000011101100000000000100000000000011101", encodableOptimizedFixedRange.substring( "000010001111010010000110111111111100000000001111010010000110111111111100000000000000000000000000000000000000000100001101000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000001110110000000000010000000000001110100000000000000000000000000000", 213)); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/HeaderV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/HeaderV1Test.java index 4c74ec5a..47dcbcbf 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/HeaderV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/HeaderV1Test.java @@ -102,4 +102,11 @@ public void testDecode3() throws DecodingException { Assertions.assertEquals(headerV1.getFieldValue("Version"), headerV1.getVersion()); Assertions.assertEquals(headerV1.getFieldValue("SectionIds"), headerV1.getSectionsIds()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new HeaderV1("z"); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java index 2940afdd..deed8e64 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java @@ -174,4 +174,11 @@ public void testDecode3() throws DecodingException { Assertions.assertEquals(1, tcfCaV1.getDisclosedVendorsSegmentType()); Assertions.assertEquals(Arrays.asList(1, 2, 3, 5, 6, 7, 10, 11, 12), tcfCaV1.getDisclosedVendors()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new TcfCaV1("z"); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java index 20eb2a7b..ee7145a9 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java @@ -348,4 +348,11 @@ public void testDecode6() throws DecodingException { Assertions.assertEquals(Arrays.asList(2, 6, 8, 12, 18, 23, 37, 42), tcfEuV2.getFieldValue("VendorLegitimateInterests")); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new TcfEuV2("z"); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java index 1a10fa9e..e34d90e7 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCaV1Test.java @@ -101,4 +101,11 @@ public void testDecodeWithGpcSegmentExcluded() throws DecodingException { Assertions.assertEquals(2, usCaV1.getMspaServiceProviderMode()); Assertions.assertEquals(false, usCaV1.getGpcSegmentIncluded()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsCaV1("z"); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java index 9c730803..9161db4e 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCoV1Test.java @@ -76,4 +76,11 @@ public void testDecodeWithGpcSegmentExcluded() throws DecodingException { Assertions.assertEquals(3, usCoV1.getMspaServiceProviderMode()); Assertions.assertEquals(false, usCoV1.getGpcSegmentIncluded()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsCoV1("z"); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java index 2053e24c..570c24d4 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsCtV1Test.java @@ -76,4 +76,11 @@ public void testDecodeWithGpcSegmentExcluded() throws DecodingException { Assertions.assertEquals(3, usCtV1.getMspaServiceProviderMode()); Assertions.assertEquals(false, usCtV1.getGpcSegmentIncluded()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsCtV1("z"); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java index f0707542..bb1f841c 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsNatV1Test.java @@ -117,4 +117,11 @@ public void testDecodeWithGpcSegmentExcluded() throws DecodingException { Assertions.assertEquals(3, usNatV1.getMspaServiceProviderMode()); Assertions.assertEquals(false, usNatV1.getGpcSegmentIncluded()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsNatV1("z"); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java index f26808a6..b589b4d0 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsUtV1Test.java @@ -51,4 +51,11 @@ public void testDecode1() throws DecodingException { Assertions.assertEquals(2, usUtV1.getMspaOptOutOptionMode()); Assertions.assertEquals(3, usUtV1.getMspaServiceProviderMode()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsUtV1("z"); + }); + } } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java index e65bec8c..44641402 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/UsVaV1Test.java @@ -54,4 +54,11 @@ public void testDecode1() throws DecodingException { Assertions.assertEquals(2, usVaV1.getMspaOptOutOptionMode()); Assertions.assertEquals(3, usVaV1.getMspaServiceProviderMode()); } + + @Test() + public void testDecodeGarbage() { + Assertions.assertThrows(DecodingException.class, () -> { + new UsVaV1("z"); + }); + } } From 080eb5d2c3f46ae28c79152311033d94028fe0d1 Mon Sep 17 00:00:00 2001 From: chad Date: Sat, 7 Oct 2023 13:50:23 -0600 Subject: [PATCH 18/36] remove deprecated usp methods --- .../java/com/iab/gpp/encoder/GppModel.java | 54 ------------------- 1 file changed, 54 deletions(-) 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 c9dea9c0..494f9bdd 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 @@ -209,80 +209,26 @@ public UspV1 getUspV1Section() { return (UspV1) getSection(UspV1.NAME); } - /** - * @deprecated - * Use {@link #getUsNatV1Section()} instead. - */ - @Deprecated - public UsNatV1 getUspNatV1Section() { - return (UsNatV1) getSection(UsNatV1.NAME); - } - public UsNatV1 getUsNatV1Section() { return (UsNatV1) getSection(UsNatV1.NAME); } - /** - * @deprecated - * Use {@link #getUsCaV1Section()} instead. - */ - @Deprecated - public UsCaV1 getUspCaV1Section() { - return (UsCaV1) getSection(UsCaV1.NAME); - } - public UsCaV1 getUsCaV1Section() { return (UsCaV1) getSection(UsCaV1.NAME); } - /** - * @deprecated - * Use {@link #getUsVaV1Section()} instead. - */ - @Deprecated - public UsVaV1 getUspVaV1Section() { - return (UsVaV1) getSection(UsVaV1.NAME); - } - public UsVaV1 getUsVaV1Section() { return (UsVaV1) getSection(UsVaV1.NAME); } - /** - * @deprecated - * Use {@link #getUsCoV1Section()} instead. - */ - @Deprecated - public UsCoV1 getUspCoV1Section() { - return (UsCoV1) getSection(UsCoV1.NAME); - } - public UsCoV1 getUsCoV1Section() { return (UsCoV1) getSection(UsCoV1.NAME); } - /** - * @deprecated - * Use {@link #getUsUtV1Section()} instead. - */ - @Deprecated - public UsUtV1 getUspUtV1Section() { - return (UsUtV1) getSection(UsUtV1.NAME); - } - public UsUtV1 getUsUtV1Section() { return (UsUtV1) getSection(UsUtV1.NAME); } - /** - * @deprecated - * Use {@link #getUsCtV1Section()} instead. - */ - @Deprecated - public UsCtV1 getUspCtV1Section() { - return (UsCtV1) getSection(UsCtV1.NAME); - } - public UsCtV1 getUsCtV1Section() { return (UsCtV1) getSection(UsCtV1.NAME); } From a3f0f1cdc6951b55a19af58ff7eff56aa6ee5116 Mon Sep 17 00:00:00 2001 From: chad Date: Sat, 7 Oct 2023 13:51:41 -0600 Subject: [PATCH 19/36] remove deprecated usp methods --- .../java/com/iab/gpp/encoder/GppModel.java | 54 ------------------- 1 file changed, 54 deletions(-) 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 7e3305c6..4f294a73 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 @@ -160,80 +160,26 @@ public UspV1 getUspV1Section() { return (UspV1) getSection(UspV1.NAME); } - /** - * @deprecated - * Use {@link #getUsNatV1Section()} instead. - */ - @Deprecated - public UsNatV1 getUspNatV1Section() { - return (UsNatV1) getSection(UsNatV1.NAME); - } - public UsNatV1 getUsNatV1Section() { return (UsNatV1) getSection(UsNatV1.NAME); } - /** - * @deprecated - * Use {@link #getUsCaV1Section()} instead. - */ - @Deprecated - public UsCaV1 getUspCaV1Section() { - return (UsCaV1) getSection(UsCaV1.NAME); - } - public UsCaV1 getUsCaV1Section() { return (UsCaV1) getSection(UsCaV1.NAME); } - /** - * @deprecated - * Use {@link #getUsVaV1Section()} instead. - */ - @Deprecated - public UsVaV1 getUspVaV1Section() { - return (UsVaV1) getSection(UsVaV1.NAME); - } - public UsVaV1 getUsVaV1Section() { return (UsVaV1) getSection(UsVaV1.NAME); } - /** - * @deprecated - * Use {@link #getUsCoV1Section()} instead. - */ - @Deprecated - public UsCoV1 getUspCoV1Section() { - return (UsCoV1) getSection(UsCoV1.NAME); - } - public UsCoV1 getUsCoV1Section() { return (UsCoV1) getSection(UsCoV1.NAME); } - /** - * @deprecated - * Use {@link #getUsUtV1Section()} instead. - */ - @Deprecated - public UsUtV1 getUspUtV1Section() { - return (UsUtV1) getSection(UsUtV1.NAME); - } - public UsUtV1 getUsUtV1Section() { return (UsUtV1) getSection(UsUtV1.NAME); } - /** - * @deprecated - * Use {@link #getUsCtV1Section()} instead. - */ - @Deprecated - public UsCtV1 getUspCtV1Section() { - return (UsCtV1) getSection(UsCtV1.NAME); - } - public UsCtV1 getUsCtV1Section() { return (UsCtV1) getSection(UsCtV1.NAME); } From 46323b7f8f029daed03464295ad839abd89fee4c Mon Sep 17 00:00:00 2001 From: chad Date: Sat, 7 Oct 2023 13:55:15 -0600 Subject: [PATCH 20/36] remove deprecated usp methods --- .../java/com/iab/gpp/encoder/GppModel.java | 54 ------------------- 1 file changed, 54 deletions(-) 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 7e3305c6..4f294a73 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 @@ -160,80 +160,26 @@ public UspV1 getUspV1Section() { return (UspV1) getSection(UspV1.NAME); } - /** - * @deprecated - * Use {@link #getUsNatV1Section()} instead. - */ - @Deprecated - public UsNatV1 getUspNatV1Section() { - return (UsNatV1) getSection(UsNatV1.NAME); - } - public UsNatV1 getUsNatV1Section() { return (UsNatV1) getSection(UsNatV1.NAME); } - /** - * @deprecated - * Use {@link #getUsCaV1Section()} instead. - */ - @Deprecated - public UsCaV1 getUspCaV1Section() { - return (UsCaV1) getSection(UsCaV1.NAME); - } - public UsCaV1 getUsCaV1Section() { return (UsCaV1) getSection(UsCaV1.NAME); } - /** - * @deprecated - * Use {@link #getUsVaV1Section()} instead. - */ - @Deprecated - public UsVaV1 getUspVaV1Section() { - return (UsVaV1) getSection(UsVaV1.NAME); - } - public UsVaV1 getUsVaV1Section() { return (UsVaV1) getSection(UsVaV1.NAME); } - /** - * @deprecated - * Use {@link #getUsCoV1Section()} instead. - */ - @Deprecated - public UsCoV1 getUspCoV1Section() { - return (UsCoV1) getSection(UsCoV1.NAME); - } - public UsCoV1 getUsCoV1Section() { return (UsCoV1) getSection(UsCoV1.NAME); } - /** - * @deprecated - * Use {@link #getUsUtV1Section()} instead. - */ - @Deprecated - public UsUtV1 getUspUtV1Section() { - return (UsUtV1) getSection(UsUtV1.NAME); - } - public UsUtV1 getUsUtV1Section() { return (UsUtV1) getSection(UsUtV1.NAME); } - /** - * @deprecated - * Use {@link #getUsCtV1Section()} instead. - */ - @Deprecated - public UsCtV1 getUspCtV1Section() { - return (UsCtV1) getSection(UsCtV1.NAME); - } - public UsCtV1 getUsCtV1Section() { return (UsCtV1) getSection(UsCtV1.NAME); } From 38bd1538417130b39fb170dc2fe91ee5fedc7a53 Mon Sep 17 00:00:00 2001 From: chad Date: Sun, 8 Oct 2023 08:42:52 -0600 Subject: [PATCH 21/36] cleanup validators --- .../AbstractEncodableBitStringDataType.java | 11 +- .../encoder/datatype/EncodableDatetime.java | 6 - .../datatype/EncodableFibonacciInteger.java | 6 - .../EncodableFibonacciIntegerRange.java | 6 - .../datatype/EncodableFixedInteger.java | 12 -- .../datatype/EncodableFixedIntegerList.java | 14 -- .../datatype/EncodableFixedIntegerRange.java | 6 - .../datatype/EncodableFixedString.java | 12 -- .../EncodableOptimizedFibonacciRange.java | 6 - .../EncodableOptimizedFixedRange.java | 6 - .../encoder/segment/UsCaV1CoreSegment.java | 136 +++++++------- .../encoder/segment/UsCoV1CoreSegment.java | 89 ++++++---- .../encoder/segment/UsCtV1CoreSegment.java | 98 +++++----- .../encoder/segment/UsNatV1CoreSegment.java | 167 ++++++++++-------- .../encoder/segment/UsUtV1CoreSegment.java | 53 +++--- .../encoder/segment/UsVaV1CoreSegment.java | 51 ++++-- 16 files changed, 343 insertions(+), 336 deletions(-) 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 b286f397..827cf102 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 @@ -10,15 +10,12 @@ public abstract class AbstractEncodableBitStringDataType implements Encodable protected T value; protected AbstractEncodableBitStringDataType() { - this.validator = v -> true; + } - protected AbstractEncodableBitStringDataType(Predicate validator) { - this.validator = validator; - } - - public void setValidator(Predicate validator) { + public AbstractEncodableBitStringDataType withValidator(Predicate validator) { this.validator = validator; + return this; } public boolean hasValue() { @@ -32,7 +29,7 @@ public T getValue() { @SuppressWarnings("unchecked") public void setValue(Object value) { T v = (T) value; - if (validator.test(v)) { + if (validator == null || validator.test(v)) { this.value = v; } else { if (v instanceof Collection) { 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 9404b31b..44530bb2 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,7 +1,6 @@ package com.iab.gpp.encoder.datatype; import java.time.ZonedDateTime; -import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.DatetimeEncoder; public class EncodableDatetime extends AbstractEncodableBitStringDataType { @@ -14,11 +13,6 @@ public EncodableDatetime(ZonedDateTime value) { super(); setValue(value); } - - public EncodableDatetime(ZonedDateTime value, Predicate validator) { - super(validator); - setValue(value); - } public String encode() { return DatetimeEncoder.encode(this.value); 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 6f49714e..dc413368 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,6 +1,5 @@ package com.iab.gpp.encoder.datatype; -import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerEncoder; public class EncodableFibonacciInteger extends AbstractEncodableBitStringDataType { @@ -14,11 +13,6 @@ public EncodableFibonacciInteger(Integer value) { setValue(value); } - public EncodableFibonacciInteger(Integer value, Predicate validator) { - super(validator); - setValue(value); - } - public String encode() { return FibonacciIntegerEncoder.encode(this.value); } 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 55b10474..cb65ff66 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 @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; -import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerRangeEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.error.DecodingException; @@ -19,11 +18,6 @@ public EncodableFibonacciIntegerRange(List value) { setValue(value); } - public EncodableFibonacciIntegerRange(List value, Predicate> validator) { - super(validator); - setValue(value); - } - public String encode() { return FibonacciIntegerRangeEncoder.encode(this.value); } 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 c0ad3296..0351dc90 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,6 +1,5 @@ package com.iab.gpp.encoder.datatype; -import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; public class EncodableFixedInteger extends AbstractEncodableBitStringDataType { @@ -18,17 +17,6 @@ public EncodableFixedInteger(int bitStringLength, Integer value) { setValue(value); } - protected EncodableFixedInteger(int bitStringLength, Predicate validator) { - super(validator); - this.bitStringLength = bitStringLength; - } - - public EncodableFixedInteger(int bitStringLength, Integer value, Predicate validator) { - super(validator); - this.bitStringLength = bitStringLength; - setValue(value); - } - public String encode() { return FixedIntegerEncoder.encode(this.value, this.bitStringLength); } 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 b8762014..04ee34bc 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,7 +2,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerListEncoder; public class EncodableFixedIntegerList extends AbstractEncodableBitStringDataType> { @@ -23,19 +22,6 @@ public EncodableFixedIntegerList(int elementBitStringLength, List value setValue(value); } - protected EncodableFixedIntegerList(int elementBitStringLength, int numElements, Predicate> validator) { - super(validator); - this.elementBitStringLength = elementBitStringLength; - this.numElements = numElements; - } - - public EncodableFixedIntegerList(int elementBitStringLength, List value, Predicate> validator) { - super(validator); - this.elementBitStringLength = elementBitStringLength; - this.numElements = value.size(); - setValue(value); - } - public String encode() { return FixedIntegerListEncoder.encode(this.value, this.elementBitStringLength, this.numElements); } 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 dfe188ec..fbfe8898 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 @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; -import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; @@ -18,11 +17,6 @@ public EncodableFixedIntegerRange(List value) { setValue(value); } - public EncodableFixedIntegerRange(List value, Predicate> validator) { - super(validator); - setValue(value); - } - public String encode() { return FixedIntegerRangeEncoder.encode(this.value); } 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 d5ee908e..89e58ec2 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,6 +1,5 @@ package com.iab.gpp.encoder.datatype; -import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FixedStringEncoder; public class EncodableFixedString extends AbstractEncodableBitStringDataType { @@ -18,17 +17,6 @@ public EncodableFixedString(int stringLength, String value) { setValue(value); } - protected EncodableFixedString(int stringLength, Predicate validator) { - super(validator); - this.stringLength = stringLength; - } - - public EncodableFixedString(int stringLength, String value, Predicate validator) { - super(validator); - this.stringLength = stringLength; - setValue(value); - } - public String encode() { return FixedStringEncoder.encode(this.value, this.stringLength); } 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 4d58f860..891ff673 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 @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; -import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FibonacciIntegerRangeEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; @@ -20,11 +19,6 @@ public EncodableOptimizedFibonacciRange(List value) { setValue(value); } - public EncodableOptimizedFibonacciRange(List value, Predicate> validator) { - super(validator); - setValue(value); - } - public String encode() { // 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 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 d2325706..9dbbf5ae 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 @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; import java.util.TreeSet; -import java.util.function.Predicate; import com.iab.gpp.encoder.datatype.encoder.FixedBitfieldEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; @@ -19,11 +18,6 @@ public EncodableOptimizedFixedRange(List value) { setValue(value); } - public EncodableOptimizedFixedRange(List value, Predicate> validator) { - super(validator); - setValue(value); - } - public String encode() { // 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 diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java index 23289f42..9c322764 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java @@ -2,6 +2,7 @@ import java.util.Arrays; import java.util.List; +import java.util.function.Predicate; import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.bitstring.BitStringEncoder; @@ -30,37 +31,45 @@ public UsCaV1CoreSegment(String encodedString) { public List getFieldNames() { return UsCaV1Field.USCAV1_CORE_SEGMENT_FIELD_NAMES; } - + @Override protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsCaV1Field.VERSION, new EncodableFixedInteger(6, UsCaV1.VERSION)); - fields.put(UsCaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCaV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCaV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCaV1Field.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.SHARING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.SHARING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsCaV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0), v -> { - for(Integer i : v) { - if(i < 0 || i > 2) { - return false; - } - } - return true; - })); - fields.put(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0), v -> { - for(Integer i : v) { - if(i < 0 || i > 2) { - return false; - } - } - return true; - })); - fields.put(UsCaV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1, (v -> v >= 1 && v <= 2))); - fields.put(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsCaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsCaV1Field.PERSONAL_DATA_CONSENTS, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); return fields; } @@ -79,85 +88,90 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } - + @Override public void validate() { Integer sharingOptOutNotice = ((EncodableFixedInteger) fields.get(UsCaV1Field.SHARING_OPT_OUT_NOTICE)).getValue(); Integer sharingOptOut = ((EncodableFixedInteger) fields.get(UsCaV1Field.SHARING_OPT_OUT)).getValue(); Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCaV1Field.SALE_OPT_OUT_NOTICE)).getValue(); Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCaV1Field.SALE_OPT_OUT)).getValue(); - Integer mspaServiceProviderMode = ((EncodableFixedInteger) fields.get(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); - Integer mspaOptOutOptionMode = ((EncodableFixedInteger) fields.get(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); - Integer sensitiveDataLimtUserNotice = ((EncodableFixedInteger) fields.get(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE)).getValue(); - + Integer mspaServiceProviderMode = + ((EncodableFixedInteger) fields.get(UsCaV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = + ((EncodableFixedInteger) fields.get(UsCaV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + Integer sensitiveDataLimtUserNotice = + ((EncodableFixedInteger) fields.get(UsCaV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE)).getValue(); + if (sharingOptOutNotice == 0) { if (sharingOptOut != 0) { - throw new ValidationException("Invalid usca sharing notice / opt out combination: {" - + sharingOptOutNotice + " / " + sharingOptOut + "}"); + throw new ValidationException( + "Invalid usca sharing notice / opt out combination: {" + sharingOptOutNotice + " / " + sharingOptOut + "}"); } } else if (sharingOptOutNotice == 1) { if (sharingOptOut != 1 && sharingOptOut != 2) { - throw new ValidationException("Invalid usca sharing notice / opt out combination: {" - + sharingOptOutNotice + " / " + sharingOptOut + "}"); + throw new ValidationException( + "Invalid usca sharing notice / opt out combination: {" + sharingOptOutNotice + " / " + sharingOptOut + "}"); } } else if (sharingOptOutNotice == 2) { if (sharingOptOut != 1) { - throw new ValidationException("Invalid usca sharing notice / opt out combination: {" - + sharingOptOutNotice + " / " + sharingOptOut + "}"); + throw new ValidationException( + "Invalid usca sharing notice / opt out combination: {" + sharingOptOutNotice + " / " + sharingOptOut + "}"); } } - + if (saleOptOutNotice == 0) { if (saleOptOut != 0) { - throw new ValidationException("Invalid usca sale notice / opt out combination: {" - + saleOptOutNotice + " / " + saleOptOut + "}"); + throw new ValidationException( + "Invalid usca sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); } } else if (saleOptOutNotice == 1) { if (saleOptOut != 1 && saleOptOut != 2) { - throw new ValidationException("Invalid usca sale notice / opt out combination: {" - + saleOptOutNotice + " / " + saleOptOut + "}"); + throw new ValidationException( + "Invalid usca sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); } } else if (saleOptOutNotice == 2) { if (saleOptOut != 1) { - throw new ValidationException("Invalid usca sale notice / opt out combination: {" - + saleOptOutNotice + " / " + saleOptOut + "}"); + throw new ValidationException( + "Invalid usca sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); } } - + if (mspaServiceProviderMode == 0) { - if(saleOptOutNotice != 0) { + if (saleOptOutNotice != 0) { throw new ValidationException("Invalid usca mspa service provider mode / sale opt out notice combination: {" + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); } - - if(sharingOptOutNotice != 0) { + + if (sharingOptOutNotice != 0) { throw new ValidationException("Invalid usca mspa service provider mode / sharing opt out notice combination: {" + mspaServiceProviderMode + " / " + sharingOptOutNotice + "}"); } - - if(sensitiveDataLimtUserNotice != 0) { - throw new ValidationException("Invalid usca mspa service provider mode / sensitive data limit use notice combination: {" - + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); + + if (sensitiveDataLimtUserNotice != 0) { + throw new ValidationException( + "Invalid usca mspa service provider mode / sensitive data limit use notice combination: {" + + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); } } else if (mspaServiceProviderMode == 1) { if (mspaOptOutOptionMode != 2) { throw new ValidationException("Invalid usca mspa service provider / opt out option modes combination: {" + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); } - - if(saleOptOutNotice != 0) { + + if (saleOptOutNotice != 0) { throw new ValidationException("Invalid usca mspa service provider mode / sale opt out notice combination: {" + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); } - - if(sharingOptOutNotice != 0) { + + if (sharingOptOutNotice != 0) { throw new ValidationException("Invalid usca mspa service provider mode / sharing opt out notice combination: {" + mspaServiceProviderMode + " / " + sharingOptOutNotice + "}"); } - - if(sensitiveDataLimtUserNotice != 0) { - throw new ValidationException("Invalid usca mspa service provider mode / sensitive data limit use notice combination: {" - + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); + + if (sensitiveDataLimtUserNotice != 0) { + throw new ValidationException( + "Invalid usca mspa service provider mode / sensitive data limit use notice combination: {" + + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); } } else if (mspaServiceProviderMode == 2) { if (mspaOptOutOptionMode != 1) { @@ -167,5 +181,5 @@ public void validate() { } } - + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java index 62dd3f3e..0a8f5cd8 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java @@ -2,6 +2,7 @@ import java.util.Arrays; import java.util.List; +import java.util.function.Predicate; import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.bitstring.BitStringEncoder; @@ -33,28 +34,40 @@ public List getFieldNames() { @Override protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsCoV1Field.VERSION, new EncodableFixedInteger(6, UsCoV1.VERSION)); - fields.put(UsCoV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCoV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCoV1Field.SHARING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCoV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsCoV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0), v -> { - for(Integer i : v) { - if(i < 0 || i > 2) { - return false; - } - } - return true; - })); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); fields.put(UsCoV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCoV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1, (v -> v >= 1 && v <= 2))); - fields.put(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); return fields; } @@ -73,33 +86,37 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } - + @Override public void validate() { Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT_NOTICE)).getValue(); Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCoV1Field.SALE_OPT_OUT)).getValue(); - Integer targetedAdvertisingOptOutNotice = ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); - Integer targetedAdvertisingOptOut = ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); - Integer mspaServiceProviderMode = ((EncodableFixedInteger) fields.get(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); - Integer mspaOptOutOptionMode = ((EncodableFixedInteger) fields.get(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); - + Integer targetedAdvertisingOptOutNotice = + ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = + ((EncodableFixedInteger) fields.get(UsCoV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = + ((EncodableFixedInteger) fields.get(UsCoV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = + ((EncodableFixedInteger) fields.get(UsCoV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + if (saleOptOutNotice == 0) { if (saleOptOut != 0) { - throw new ValidationException("Invalid usco sale notice / opt out combination: {" - + saleOptOutNotice + " / " + saleOptOut + "}"); + throw new ValidationException( + "Invalid usco sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); } } else if (saleOptOutNotice == 1) { if (saleOptOut != 1 && saleOptOut != 2) { - throw new ValidationException("Invalid usco sale notice / opt out combination: {" - + saleOptOutNotice + " / " + saleOptOut + "}"); + throw new ValidationException( + "Invalid usco sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); } } else if (saleOptOutNotice == 2) { if (saleOptOut != 1) { - throw new ValidationException("Invalid usco sale notice / opt out combination: {" - + saleOptOutNotice + " / " + saleOptOut + "}"); + throw new ValidationException( + "Invalid usco sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); } } - + if (targetedAdvertisingOptOutNotice == 0) { if (targetedAdvertisingOptOut != 0) { throw new ValidationException("Invalid usco targeted advertising notice / opt out combination: {" @@ -116,9 +133,9 @@ public void validate() { + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); } } - + if (mspaServiceProviderMode == 0) { - if(saleOptOutNotice != 0) { + if (saleOptOutNotice != 0) { throw new ValidationException("Invalid usco mspa service provider mode / sale opt out notice combination: {" + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); } @@ -127,8 +144,8 @@ public void validate() { throw new ValidationException("Invalid usco mspa service provider / opt out option modes combination: {" + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); } - - if(saleOptOutNotice != 0) { + + if (saleOptOutNotice != 0) { throw new ValidationException("Invalid usco mspa service provider mode / sale opt out notice combination: {" + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); } @@ -139,6 +156,6 @@ public void validate() { } } } - - + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java index 57b33b09..25870edf 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java @@ -2,6 +2,7 @@ import java.util.Arrays; import java.util.List; +import java.util.function.Predicate; import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.bitstring.BitStringEncoder; @@ -33,35 +34,40 @@ public List getFieldNames() { @Override protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsCtV1Field.VERSION, new EncodableFixedInteger(6, UsCtV1.VERSION)); - fields.put(UsCtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsCtV1Field.SHARING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCtV1Field.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCtV1Field.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsCtV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0), v -> { - for(Integer i : v) { - if(i < 0 || i > 2) { - return false; - } - } - return true; - })); - fields.put(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0), v -> { - for(Integer i : v) { - if(i < 0 || i > 2) { - return false; - } - } - return true; - })); - fields.put(UsCtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1, (v -> v >= 1 && v <= 2))); - fields.put(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsCtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsCtV1Field.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); return fields; } @@ -80,33 +86,37 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } - + @Override public void validate() { Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsCtV1Field.SALE_OPT_OUT_NOTICE)).getValue(); Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsCtV1Field.SALE_OPT_OUT)).getValue(); - Integer targetedAdvertisingOptOutNotice = ((EncodableFixedInteger) fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); - Integer targetedAdvertisingOptOut = ((EncodableFixedInteger) fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); - Integer mspaServiceProviderMode = ((EncodableFixedInteger) fields.get(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); - Integer mspaOptOutOptionMode = ((EncodableFixedInteger) fields.get(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); - + Integer targetedAdvertisingOptOutNotice = + ((EncodableFixedInteger) fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = + ((EncodableFixedInteger) fields.get(UsCtV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = + ((EncodableFixedInteger) fields.get(UsCtV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = + ((EncodableFixedInteger) fields.get(UsCtV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + if (saleOptOutNotice == 0) { if (saleOptOut != 0) { - throw new ValidationException("Invalid usct sale notice / opt out combination: {" - + saleOptOutNotice + " / " + saleOptOut + "}"); + throw new ValidationException( + "Invalid usct sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); } } else if (saleOptOutNotice == 1) { if (saleOptOut != 1 && saleOptOut != 2) { - throw new ValidationException("Invalid usct sale notice / opt out combination: {" - + saleOptOutNotice + " / " + saleOptOut + "}"); + throw new ValidationException( + "Invalid usct sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); } } else if (saleOptOutNotice == 2) { if (saleOptOut != 1) { - throw new ValidationException("Invalid usct sale notice / opt out combination: {" - + saleOptOutNotice + " / " + saleOptOut + "}"); + throw new ValidationException( + "Invalid usct sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); } } - + if (targetedAdvertisingOptOutNotice == 0) { if (targetedAdvertisingOptOut != 0) { throw new ValidationException("Invalid usct targeted advertising notice / opt out combination: {" @@ -123,9 +133,9 @@ public void validate() { + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); } } - + if (mspaServiceProviderMode == 0) { - if(saleOptOutNotice != 0) { + if (saleOptOutNotice != 0) { throw new ValidationException("Invalid usct mspa service provider mode / sale opt out notice combination: {" + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); } @@ -134,8 +144,8 @@ public void validate() { throw new ValidationException("Invalid usct mspa service provider / opt out option modes combination: {" + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); } - - if(saleOptOutNotice != 0) { + + if (saleOptOutNotice != 0) { throw new ValidationException("Invalid usct mspa service provider mode / sale opt out notice combination: {" + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); } @@ -146,6 +156,6 @@ public void validate() { } } } - - + + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java index 2488bad9..6bd5ee54 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java @@ -2,6 +2,7 @@ import java.util.Arrays; import java.util.List; +import java.util.function.Predicate; import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.bitstring.BitStringEncoder; @@ -33,41 +34,50 @@ public List getFieldNames() { @Override protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsNatV1Field.VERSION, new EncodableFixedInteger(6, UsNatV1.VERSION)); - fields.put(UsNatV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsNatV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsNatV1Field.SHARING_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsNatV1Field.SHARING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.SHARING_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, - new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsNatV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsNatV1Field.SHARING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.SHARING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsNatV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), v -> { - for (Integer i : v) { - if (i < 0 || i > 2) { - return false; - } - } - return true; - })); - fields.put(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0), v -> { - for (Integer i : v) { - if (i < 0 || i > 2) { - return false; - } - } - return true; - })); - fields.put(UsNatV1Field.PERSONAL_DATA_CONSENTS, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsNatV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1, (v -> v >= 1 && v <= 2))); - fields.put(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsNatV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, new EncodableFixedIntegerList(2, Arrays.asList(0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); + fields.put(UsNatV1Field.PERSONAL_DATA_CONSENTS, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); return fields; } @@ -86,7 +96,7 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } - + @Override public void validate() { Integer sharingNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.SHARING_NOTICE)).getValue(); @@ -94,63 +104,68 @@ public void validate() { Integer sharingOptOut = ((EncodableFixedInteger) fields.get(UsNatV1Field.SHARING_OPT_OUT)).getValue(); Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.SALE_OPT_OUT_NOTICE)).getValue(); Integer saleOptOut = ((EncodableFixedInteger) fields.get(UsNatV1Field.SALE_OPT_OUT)).getValue(); - Integer targetedAdvertisingOptOutNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); - Integer targetedAdvertisingOptOut = ((EncodableFixedInteger) fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); - Integer mspaServiceProviderMode = ((EncodableFixedInteger) fields.get(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); - Integer mspaOptOutOptionMode = ((EncodableFixedInteger) fields.get(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); - Integer sensitiveDataLimtUserNotice = ((EncodableFixedInteger) fields.get(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE)).getValue(); - + Integer targetedAdvertisingOptOutNotice = + ((EncodableFixedInteger) fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE)).getValue(); + Integer targetedAdvertisingOptOut = + ((EncodableFixedInteger) fields.get(UsNatV1Field.TARGETED_ADVERTISING_OPT_OUT)).getValue(); + Integer mspaServiceProviderMode = + ((EncodableFixedInteger) fields.get(UsNatV1Field.MSPA_SERVICE_PROVIDER_MODE)).getValue(); + Integer mspaOptOutOptionMode = + ((EncodableFixedInteger) fields.get(UsNatV1Field.MSPA_OPT_OUT_OPTION_MODE)).getValue(); + Integer sensitiveDataLimtUserNotice = + ((EncodableFixedInteger) fields.get(UsNatV1Field.SENSITIVE_DATA_LIMIT_USE_NOTICE)).getValue(); + if (sharingNotice == 0) { if (sharingOptOut != 0) { - throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" - + sharingNotice + " / " + sharingOptOut + "}"); + throw new ValidationException( + "Invalid usnat sharing notice / opt out combination: {" + sharingNotice + " / " + sharingOptOut + "}"); } } else if (sharingNotice == 1) { if (sharingOptOut != 1 && sharingOptOut != 2) { - throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" - + sharingNotice + " / " + sharingOptOut + "}"); + throw new ValidationException( + "Invalid usnat sharing notice / opt out combination: {" + sharingNotice + " / " + sharingOptOut + "}"); } } else if (sharingNotice == 2) { if (sharingOptOut != 1) { - throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" - + sharingNotice + " / " + sharingOptOut + "}"); + throw new ValidationException( + "Invalid usnat sharing notice / opt out combination: {" + sharingNotice + " / " + sharingOptOut + "}"); } } - + if (sharingOptOutNotice == 0) { if (sharingOptOut != 0) { - throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" - + sharingOptOutNotice + " / " + sharingOptOut + "}"); + throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" + sharingOptOutNotice + + " / " + sharingOptOut + "}"); } } else if (sharingOptOutNotice == 1) { if (sharingOptOut != 1 && sharingOptOut != 2) { - throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" - + sharingOptOutNotice + " / " + sharingOptOut + "}"); + throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" + sharingOptOutNotice + + " / " + sharingOptOut + "}"); } } else if (sharingOptOutNotice == 2) { if (sharingOptOut != 1) { - throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" - + sharingOptOutNotice + " / " + sharingOptOut + "}"); + throw new ValidationException("Invalid usnat sharing notice / opt out combination: {" + sharingOptOutNotice + + " / " + sharingOptOut + "}"); } } - + if (saleOptOutNotice == 0) { if (saleOptOut != 0) { - throw new ValidationException("Invalid usnat sale notice / opt out combination: {" - + saleOptOutNotice + " / " + saleOptOut + "}"); + throw new ValidationException( + "Invalid usnat sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); } } else if (saleOptOutNotice == 1) { if (saleOptOut != 1 && saleOptOut != 2) { - throw new ValidationException("Invalid usnat sale notice / opt out combination: {" - + saleOptOutNotice + " / " + saleOptOut + "}"); + throw new ValidationException( + "Invalid usnat sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); } } else if (saleOptOutNotice == 2) { if (saleOptOut != 1) { - throw new ValidationException("Invalid usnat sale notice / opt out combination: {" - + saleOptOutNotice + " / " + saleOptOut + "}"); + throw new ValidationException( + "Invalid usnat sale notice / opt out combination: {" + saleOptOutNotice + " / " + saleOptOut + "}"); } } - + if (targetedAdvertisingOptOutNotice == 0) { if (targetedAdvertisingOptOut != 0) { throw new ValidationException("Invalid usnat targeted advertising notice / opt out combination: {" @@ -167,41 +182,43 @@ public void validate() { + targetedAdvertisingOptOutNotice + " / " + targetedAdvertisingOptOut + "}"); } } - + if (mspaServiceProviderMode == 0) { - if(saleOptOutNotice != 0) { + if (saleOptOutNotice != 0) { throw new ValidationException("Invalid usnat mspa service provider mode / sale opt out notice combination: {" + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); } - - if(sharingOptOutNotice != 0) { + + if (sharingOptOutNotice != 0) { throw new ValidationException("Invalid usnat mspa service provider mode / sharing opt out notice combination: {" + mspaServiceProviderMode + " / " + sharingOptOutNotice + "}"); } - - if(sensitiveDataLimtUserNotice != 0) { - throw new ValidationException("Invalid usnat mspa service provider mode / sensitive data limit use notice combination: {" - + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); + + if (sensitiveDataLimtUserNotice != 0) { + throw new ValidationException( + "Invalid usnat mspa service provider mode / sensitive data limit use notice combination: {" + + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); } } else if (mspaServiceProviderMode == 1) { if (mspaOptOutOptionMode != 2) { throw new ValidationException("Invalid usnat mspa service provider / opt out option modes combination: {" + mspaServiceProviderMode + " / " + mspaServiceProviderMode + "}"); } - - if(saleOptOutNotice != 0) { + + if (saleOptOutNotice != 0) { throw new ValidationException("Invalid usnat mspa service provider mode / sale opt out notice combination: {" + mspaServiceProviderMode + " / " + saleOptOutNotice + "}"); } - - if(sharingOptOutNotice != 0) { + + if (sharingOptOutNotice != 0) { throw new ValidationException("Invalid usnat mspa service provider mode / sharing opt out notice combination: {" + mspaServiceProviderMode + " / " + sharingOptOutNotice + "}"); } - - if(sensitiveDataLimtUserNotice != 0) { - throw new ValidationException("Invalid usnat mspa service provider mode / sensitive data limit use notice combination: {" - + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); + + if (sensitiveDataLimtUserNotice != 0) { + throw new ValidationException( + "Invalid usnat mspa service provider mode / sensitive data limit use notice combination: {" + + mspaServiceProviderMode + " / " + sensitiveDataLimtUserNotice + "}"); } } else if (mspaServiceProviderMode == 2) { if (mspaOptOutOptionMode != 1) { @@ -211,5 +228,5 @@ public void validate() { } } - + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java index 0a88910c..e1b6ae75 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java @@ -2,6 +2,7 @@ import java.util.Arrays; import java.util.List; +import java.util.function.Predicate; import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.bitstring.BitStringEncoder; @@ -33,30 +34,42 @@ public List getFieldNames() { @Override protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsUtV1Field.VERSION, new EncodableFixedInteger(6, UsUtV1.VERSION)); - fields.put(UsUtV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsUtV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsUtV1Field.SHARING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING_OPT_OUT_NOTICE, - new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsUtV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsUtV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0), v -> { - for (Integer i : v) { - if (i < 0 || i > 2) { - return false; - } - } - return true; - })); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); fields.put(UsUtV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsUtV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1, (v -> v >= 1 && v <= 2))); - fields.put(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsUtV1Field.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); return fields; } @@ -75,7 +88,7 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } - + @Override public void validate() { Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsUtV1Field.SALE_OPT_OUT_NOTICE)).getValue(); @@ -146,5 +159,5 @@ public void validate() { } } - + } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java index 8e04b968..997521d1 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java @@ -2,6 +2,7 @@ import java.util.Arrays; import java.util.List; +import java.util.function.Predicate; import com.iab.gpp.encoder.base64.AbstractBase64UrlEncoder; import com.iab.gpp.encoder.base64.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.bitstring.BitStringEncoder; @@ -33,28 +34,40 @@ public List getFieldNames() { @Override protected EncodableBitStringFields initializeFields() { + Predicate nullableBooleanAsTwoBitIntegerValidator = (n -> n >= 0 && n <= 2); + Predicate nonNullableBooleanAsTwoBitIntegerValidator = (n -> n >= 1 && n <= 2); + Predicate> nullableBooleanAsTwoBitIntegerListValidator = (l -> { + for (int n : l) { + if (n < 0 || n > 2) { + return false; + } + } + return true; + }); + EncodableBitStringFields fields = new EncodableBitStringFields(); fields.put(UsVaV1Field.VERSION, new EncodableFixedInteger(6, UsVaV1.VERSION)); - fields.put(UsVaV1Field.SHARING_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsVaV1Field.SALE_OPT_OUT_NOTICE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + fields.put(UsVaV1Field.SHARING_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.SALE_OPT_OUT_NOTICE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT_NOTICE, - new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsVaV1Field.SALE_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.SALE_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.TARGETED_ADVERTISING_OPT_OUT, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); fields.put(UsVaV1Field.SENSITIVE_DATA_PROCESSING, - new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0), v -> { - for (Integer i : v) { - if (i < 0 || i > 2) { - return false; - } - } - return true; - })); + new EncodableFixedIntegerList(2, Arrays.asList(0, 0, 0, 0, 0, 0, 0, 0)) + .withValidator(nullableBooleanAsTwoBitIntegerListValidator)); fields.put(UsVaV1Field.KNOWN_CHILD_SENSITIVE_DATA_CONSENTS, - new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsVaV1Field.MSPA_COVERED_TRANSACTION, new EncodableFixedInteger(2, 1, (v -> v >= 1 && v <= 2))); - fields.put(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); - fields.put(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, new EncodableFixedInteger(2, 0, (v -> v >= 0 && v <= 2))); + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.MSPA_COVERED_TRANSACTION, + new EncodableFixedInteger(2, 1).withValidator(nonNullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.MSPA_OPT_OUT_OPTION_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); + fields.put(UsVaV1Field.MSPA_SERVICE_PROVIDER_MODE, + new EncodableFixedInteger(2, 0).withValidator(nullableBooleanAsTwoBitIntegerValidator)); return fields; } @@ -73,7 +86,7 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel String bitString = base64UrlEncoder.decode(encodedString); bitStringEncoder.decode(bitString, getFieldNames(), fields); } - + @Override public void validate() { Integer saleOptOutNotice = ((EncodableFixedInteger) fields.get(UsVaV1Field.SALE_OPT_OUT_NOTICE)).getValue(); @@ -144,5 +157,5 @@ public void validate() { } } - + } From 811d172b619c504ccef49b964d074b3c62e27e30 Mon Sep 17 00:00:00 2001 From: chad Date: Sun, 8 Oct 2023 14:38:00 -0600 Subject: [PATCH 22/36] Better decoding exception messaging --- .../iab/gpp/encoder/segment/HeaderV1CoreSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/TcfCaV1CoreSegment.java | 9 +++++++-- .../segment/TcfCaV1DisclosedVendorsSegment.java | 9 +++++++-- .../segment/TcfCaV1PublisherPurposesSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/TcfEuV2CoreSegment.java | 9 +++++++-- .../segment/TcfEuV2PublisherPurposesSegment.java | 9 +++++++-- .../segment/TcfEuV2VendorsAllowedSegment.java | 9 +++++++-- .../segment/TcfEuV2VendorsDisclosedSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/UsCaV1CoreSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/UsCaV1GpcSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/UsCoV1CoreSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/UsCoV1GpcSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/UsCtV1CoreSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/UsCtV1GpcSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/UsNatV1CoreSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/UsNatV1GpcSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/UsUtV1CoreSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/UsVaV1CoreSegment.java | 9 +++++++-- .../iab/gpp/encoder/segment/UspV1CoreSegment.java | 12 ++++++++---- 19 files changed, 134 insertions(+), 40 deletions(-) diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java index 1154d1f6..5f944d90 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/HeaderV1CoreSegment.java @@ -7,6 +7,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFibonacciIntegerRange; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.HeaderV1Field; import com.iab.gpp.encoder.section.HeaderV1; @@ -51,8 +52,12 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if(encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode HeaderV1CoreSegment '" + encodedString + "'", e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1CoreSegment.java index 9cb97ee5..93dc1e77 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1CoreSegment.java @@ -14,6 +14,7 @@ import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedString; import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.TcfCaV1Field; import com.iab.gpp.encoder.section.TcfCaV1; @@ -78,7 +79,11 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if(encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfCaV1CoreSegment '" + encodedString + "'", e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1DisclosedVendorsSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1DisclosedVendorsSegment.java index 8dd89010..cbd7e90f 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1DisclosedVendorsSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1DisclosedVendorsSegment.java @@ -7,6 +7,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.TcfCaV1Field; @@ -49,7 +50,11 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfCaV1DisclosedVendorsSegment '" + encodedString + "'", e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1PublisherPurposesSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1PublisherPurposesSegment.java index 89d63390..1ab89c0b 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1PublisherPurposesSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfCaV1PublisherPurposesSegment.java @@ -10,6 +10,7 @@ import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.TcfCaV1Field; @@ -75,7 +76,11 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if(encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfCaV1PublisherPurposesSegment '" + encodedString + "'", e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2CoreSegment.java index 5e894459..dbbd87a0 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2CoreSegment.java @@ -14,6 +14,7 @@ import com.iab.gpp.encoder.datatype.EncodableFixedIntegerRange; import com.iab.gpp.encoder.datatype.EncodableFixedString; import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.TcfEuV2Field; import com.iab.gpp.encoder.section.TcfEuV2; @@ -82,7 +83,11 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if(encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfEuV2CoreSegment '" + encodedString + "'", e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2PublisherPurposesSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2PublisherPurposesSegment.java index 4d351f67..0b751017 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2PublisherPurposesSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2PublisherPurposesSegment.java @@ -10,6 +10,7 @@ import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.TcfEuV2Field; @@ -75,7 +76,11 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if(encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfEuV2PublisherPurposesSegment '" + encodedString + "'", e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsAllowedSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsAllowedSegment.java index ffe382be..e09b48bb 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsAllowedSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsAllowedSegment.java @@ -7,6 +7,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.TcfEuV2Field; @@ -49,7 +50,11 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if(encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfEuV2VendorsAllowedSegment '" + encodedString + "'", e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsDisclosedSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsDisclosedSegment.java index 1487eb5b..c66b012d 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsDisclosedSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/TcfEuV2VendorsDisclosedSegment.java @@ -7,6 +7,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.TcfEuV2Field; @@ -49,7 +50,11 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if(encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode TcfEuV2VendorsDisclosedSegment '" + encodedString + "'", e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java index 9c322764..73738284 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1CoreSegment.java @@ -8,6 +8,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsCaV1Field; @@ -85,8 +86,12 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsCaV1CoreSegment '" + encodedString + "'", e); + } } @Override diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1GpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1GpcSegment.java index d3b15593..b55e9a28 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1GpcSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCaV1GpcSegment.java @@ -6,6 +6,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableBoolean; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsCaV1Field; @@ -49,7 +50,11 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if(encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsCaV1GpcSegment '" + encodedString + "'", e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java index 0a8f5cd8..5fc86ff3 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1CoreSegment.java @@ -8,6 +8,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsCoV1Field; @@ -83,8 +84,12 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsCoV1CoreSegment '" + encodedString + "'", e); + } } @Override diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1GpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1GpcSegment.java index 6281419c..0d0594de 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1GpcSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCoV1GpcSegment.java @@ -6,6 +6,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableBoolean; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsCoV1Field; @@ -49,7 +50,11 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if(encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsCoV1GpcSegment '" + encodedString + "'", e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java index 25870edf..a07bed72 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1CoreSegment.java @@ -8,6 +8,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsCtV1Field; @@ -83,8 +84,12 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsCtV1CoreSegment '" + encodedString + "'", e); + } } @Override diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1GpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1GpcSegment.java index 6ff912c0..b10649a3 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1GpcSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsCtV1GpcSegment.java @@ -6,6 +6,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableBoolean; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsCtV1Field; @@ -49,7 +50,11 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if(encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsCtV1GpcSegment '" + encodedString + "'", e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java index 6bd5ee54..de3bc0dd 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1CoreSegment.java @@ -8,6 +8,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsNatV1Field; @@ -93,8 +94,12 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsNatV1CoreSegment '" + encodedString + "'", e); + } } @Override diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1GpcSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1GpcSegment.java index ea8d9746..848e360f 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1GpcSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsNatV1GpcSegment.java @@ -6,6 +6,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableBoolean; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsNatV1Field; @@ -49,7 +50,11 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if(encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsNatV1GpcSegment '" + encodedString + "'", e); + } } } diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java index e1b6ae75..1602e079 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsUtV1CoreSegment.java @@ -8,6 +8,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsUtV1Field; @@ -85,8 +86,12 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsUtV1CoreSegment '" + encodedString + "'", e); + } } @Override diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java index 997521d1..08a8a8dd 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UsVaV1CoreSegment.java @@ -8,6 +8,7 @@ import com.iab.gpp.encoder.bitstring.BitStringEncoder; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; import com.iab.gpp.encoder.datatype.EncodableFixedIntegerList; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.ValidationException; import com.iab.gpp.encoder.field.EncodableBitStringFields; import com.iab.gpp.encoder.field.UsVaV1Field; @@ -83,8 +84,12 @@ protected void decodeSegment(String encodedString, EncodableBitStringFields fiel if (encodedString == null || encodedString.isEmpty()) { this.fields.reset(fields); } - String bitString = base64UrlEncoder.decode(encodedString); - bitStringEncoder.decode(bitString, getFieldNames(), fields); + try { + String bitString = base64UrlEncoder.decode(encodedString); + bitStringEncoder.decode(bitString, getFieldNames(), fields); + } catch (Exception e) { + throw new DecodingException("Unable to decode UsVaV1CoreSegment '" + encodedString + "'", e); + } } @Override diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java index 6c07675d..59b3c557 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/segment/UspV1CoreSegment.java @@ -50,10 +50,14 @@ protected void decodeSegment(String encodedString, GenericFields fields) { throw new DecodingException("Invalid uspv1 string: '" + encodedString + "'"); } - fields.get(UspV1Field.VERSION).setValue(Integer.parseInt(encodedString.substring(0, 1))); - fields.get(UspV1Field.NOTICE).setValue(encodedString.charAt(1)); - fields.get(UspV1Field.OPT_OUT_SALE).setValue(encodedString.charAt(2)); - fields.get(UspV1Field.LSPA_COVERED).setValue(encodedString.charAt(3)); + try { + fields.get(UspV1Field.VERSION).setValue(Integer.parseInt(encodedString.substring(0, 1))); + fields.get(UspV1Field.NOTICE).setValue(encodedString.charAt(1)); + fields.get(UspV1Field.OPT_OUT_SALE).setValue(encodedString.charAt(2)); + fields.get(UspV1Field.LSPA_COVERED).setValue(encodedString.charAt(3)); + } catch (Exception e) { + throw new DecodingException("Unable to decode UspV1CoreSegment '" + encodedString + "'", e); + } } } From 157cacbc42b0e7f661756b7b2852e297f5e59239 Mon Sep 17 00:00:00 2001 From: chad Date: Sun, 8 Oct 2023 14:38:37 -0600 Subject: [PATCH 23/36] remove unused classes --- .../AbstractEncodableBitStringSection.java | 92 --------------- ...actEncodableSegmentedBitStringSection.java | 110 ------------------ 2 files changed, 202 deletions(-) delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableSegmentedBitStringSection.java diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java deleted file mode 100644 index f6637dad..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/AbstractEncodableBitStringSection.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.iab.gpp.encoder.section; - -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 AbstractEncodableBitStringSection implements EncodableSection { - protected Map> fields; - protected String[] fieldOrder; - - @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[] getFieldOrder() { - return this.fieldOrder; - } - - public String encodeToBitString() throws EncodingException { - String bitString = ""; - for (int i = 0; i < this.fieldOrder.length; i++) { - String fieldName = this.fieldOrder[i]; - if (this.fields.containsKey(fieldName)) { - AbstractEncodableBitStringDataType field = this.fields.get(fieldName); - bitString += field.encode(); - } else { - throw new EncodingException("Field not found: '" + fieldName + "'"); - } - } - - return bitString; - } - - public void decodeFromBitString(String bitString) throws DecodingException { - int index = 0; - for (int i = 0; i < this.fieldOrder.length; i++) { - String fieldName = this.fieldOrder[i]; - if (this.fields.containsKey(fieldName)) { - AbstractEncodableBitStringDataType field = this.fields.get(fieldName); - try { - String 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); - } 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/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(); -} From ecbd815b3b8787dc0c03385808b915fc127f4874 Mon Sep 17 00:00:00 2001 From: chad Date: Sun, 8 Oct 2023 14:42:38 -0600 Subject: [PATCH 24/36] Update README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 5c6f166d..b82e09e6 100644 --- a/README.md +++ b/README.md @@ -161,12 +161,15 @@ CmpList cmpList = loader.cmpList(cmpListContent); |tcfcav1|5|PurposesImpliedConsent|Boolean list of size 24| |tcfcav1|5|VendorExpressConsent|Integer list of variable size| |tcfcav1|5|VendorImpliedConsent|Integer list of variable size| +|tcfcav1|5|PubRestrictions|RangeEntry list of variable size| |tcfcav1|5|PubPurposesSegmentType|3 bit int. Value is 3| |tcfcav1|5|PubPurposesExpressConsent|Boolean list of size 24| |tcfcav1|5|PubPurposesImpliedConsent|Boolean list of size 24| |tcfcav1|5|NumCustomPurposes|6 bit int| |tcfcav1|5|CustomPurposesExpressConsent|Boolean list where size is set by the NumCustomPurposes field| |tcfcav1|5|CustomPurposesImpliedConsent|Boolean list where size is set by the NumCustomPurposes field| +|tcfcav1|5|DisclosedVendorsSegmentType|3 bit int. Value is 1| +|tcfcav1|5|DisclosedVendors|Integer list of variable size| |uspv1|6|Version|6 bit int. Value is 1| |uspv1|6|Notice|2 bit int| |uspv1|6|OptOutSale|2 bit int| From 75d9427563180d656c615dfaa6e8857e44f239d3 Mon Sep 17 00:00:00 2001 From: chad Date: Sun, 8 Oct 2023 19:44:07 -0600 Subject: [PATCH 25/36] add support for the old headerless tcfeuv2 strings --- .../java/com/iab/gpp/encoder/GppModel.java | 97 +++++++++++-------- 1 file changed, 58 insertions(+), 39 deletions(-) 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 494f9bdd..5b81785c 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 @@ -1,12 +1,15 @@ package com.iab.gpp.encoder; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; +import com.iab.gpp.encoder.field.HeaderV1Field; import com.iab.gpp.encoder.section.EncodableSection; import com.iab.gpp.encoder.section.HeaderV1; import com.iab.gpp.encoder.section.Sections; @@ -276,48 +279,64 @@ protected String encodeModel(Map sections) { } protected Map decodeModel(String str) { - Map sections = new HashMap<>(); - - if(str != null && !str.isEmpty()) { - String[] encodedSections = str.split("~"); - HeaderV1 header = new HeaderV1(encodedSections[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(UsCaV1.ID)) { - UsCaV1 section = new UsCaV1(encodedSections[i + 1]); - sections.put(UsCaV1.NAME, section); - } else if (sectionIds.get(i).equals(UsNatV1.ID)) { - UsNatV1 section = new UsNatV1(encodedSections[i + 1]); - sections.put(UsNatV1.NAME, section); - } else if (sectionIds.get(i).equals(UsVaV1.ID)) { - UsVaV1 section = new UsVaV1(encodedSections[i + 1]); - sections.put(UsVaV1.NAME, section); - } else if (sectionIds.get(i).equals(UsCoV1.ID)) { - UsCoV1 section = new UsCoV1(encodedSections[i + 1]); - sections.put(UsCoV1.NAME, section); - } else if (sectionIds.get(i).equals(UsUtV1.ID)) { - UsUtV1 section = new UsUtV1(encodedSections[i + 1]); - sections.put(UsUtV1.NAME, section); - } else if (sectionIds.get(i).equals(UsCtV1.ID)) { - UsCtV1 section = new UsCtV1(encodedSections[i + 1]); - sections.put(UsCtV1.NAME, section); + if(str == null || str.isEmpty() || str.startsWith("D")) { + Map sections = new HashMap<>(); + + if(str != null && !str.isEmpty()) { + String[] encodedSections = str.split("~"); + HeaderV1 header = new HeaderV1(encodedSections[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(UsCaV1.ID)) { + UsCaV1 section = new UsCaV1(encodedSections[i + 1]); + sections.put(UsCaV1.NAME, section); + } else if (sectionIds.get(i).equals(UsNatV1.ID)) { + UsNatV1 section = new UsNatV1(encodedSections[i + 1]); + sections.put(UsNatV1.NAME, section); + } else if (sectionIds.get(i).equals(UsVaV1.ID)) { + UsVaV1 section = new UsVaV1(encodedSections[i + 1]); + sections.put(UsVaV1.NAME, section); + } else if (sectionIds.get(i).equals(UsCoV1.ID)) { + UsCoV1 section = new UsCoV1(encodedSections[i + 1]); + sections.put(UsCoV1.NAME, section); + } else if (sectionIds.get(i).equals(UsUtV1.ID)) { + UsUtV1 section = new UsUtV1(encodedSections[i + 1]); + sections.put(UsUtV1.NAME, section); + } else if (sectionIds.get(i).equals(UsCtV1.ID)) { + UsCtV1 section = new UsCtV1(encodedSections[i + 1]); + sections.put(UsCtV1.NAME, section); + } } } + + return sections; + } else if(str.startsWith("C")) { + // old tcfeu only string + Map sections = new HashMap<>(); + + TcfEuV2 section = new TcfEuV2(str); + sections.put(TcfEuV2.NAME, section); + + HeaderV1 header = new HeaderV1(); + header.setFieldValue(HeaderV1Field.SECTION_IDS, Arrays.asList(2)); + sections.put(HeaderV1.NAME, section); + + return sections; + } else { + throw new DecodingException("Unable to decode '" + str + "'"); } - - return sections; } public String encodeSection(int sectionId) { From af2c0b7071d530ef1d5450bfb9b0bf6d2fafcc1d Mon Sep 17 00:00:00 2001 From: chad Date: Sun, 8 Oct 2023 23:45:14 -0600 Subject: [PATCH 26/36] encodeSection fix --- .../src/main/java/com/iab/gpp/encoder/GppModel.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 5b81785c..f4a8bf94 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 @@ -344,6 +344,12 @@ public String encodeSection(int sectionId) { } public String encodeSection(String sectionName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; + } + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName).encode(); } else { From 4f182f8493ce8a6e403a18b6f537f55eac29c1bf Mon Sep 17 00:00:00 2001 From: chad Date: Mon, 9 Oct 2023 06:52:15 -0600 Subject: [PATCH 27/36] encodeSection lazy fix --- .../src/main/java/com/iab/gpp/encoder/GppModel.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 494f9bdd..90c46d10 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 @@ -325,6 +325,12 @@ public String encodeSection(int sectionId) { } public String encodeSection(String sectionName) { + if (!this.decoded) { + this.sections = this.decodeModel(this.encodedString); + this.dirty = false; + this.decoded = true; + } + if (this.sections.containsKey(sectionName)) { return this.sections.get(sectionName).encode(); } else { From cedac142cdb5c57c97a307d92806bdc27de89afd Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Wed, 13 Dec 2023 08:36:40 -0700 Subject: [PATCH 28/36] tcfeu pub restrictions fix --- .../section/AbstractEncodableSegmentedBitStringSection.java | 1 + .../src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) 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 index eb5d5459..278c5944 100644 --- 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 @@ -78,6 +78,7 @@ private void decodeSegmentFromBitString(String[] segment, String segmentBitStrin if (this.fields.containsKey(fieldName)) { try { String substring = field.substring(segmentBitString, index); + System.out.println(fieldName + ": " + substring + " (" + index + "/" + segmentBitString.length() + ")"); field.decode(substring); index += substring.length(); } catch (SubstringException e) { diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java index 625121bd..ad6439dd 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java @@ -8,6 +8,7 @@ import java.util.List; import java.util.function.IntSupplier; import java.util.stream.Collectors; +import com.iab.gpp.encoder.datatype.EncodableArrayOfRanges; import com.iab.gpp.encoder.datatype.EncodableBoolean; import com.iab.gpp.encoder.datatype.EncodableDatetime; import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; @@ -72,7 +73,7 @@ private void initFields() { fields.put(TcfEuV2Field.VENDOR_CONSENTS, new EncodableOptimizedFixedRange(new ArrayList<>())); fields.put(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, new EncodableOptimizedFixedRange(new ArrayList<>())); - fields.put(TcfEuV2Field.PUBLISHER_RESTRICTIONS, new EncodableFixedIntegerRange(new ArrayList<>())); + fields.put(TcfEuV2Field.PUBLISHER_RESTRICTIONS, new EncodableArrayOfRanges(6, 2, new ArrayList<>(), false)); // publisher purposes segment fields.put(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); From 9b477a4e363c91eebb73be3bf90ba4d92a89c8e8 Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Wed, 13 Dec 2023 08:46:55 -0700 Subject: [PATCH 29/36] pub restrictions getters --- .../src/main/java/com/iab/gpp/encoder/section/TcfCaV1.java | 7 +++++++ .../src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java | 6 +++--- 2 files changed, 10 insertions(+), 3 deletions(-) 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 52e9a7c1..f6ebf10a 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 @@ -16,12 +16,14 @@ import com.iab.gpp.encoder.datatype.EncodableFixedString; import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.datatype.RangeEntry; import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; import com.iab.gpp.encoder.datatype.encoder.CompressedBase64UrlEncoder; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.TcfCaV1Field; +import com.iab.gpp.encoder.field.TcfEuV2Field; public class TcfCaV1 extends AbstractEncodableSegmentedBitStringSection { public static int ID = 5; @@ -281,6 +283,11 @@ public List getVendorExpressConsent() { public List getVendorImpliedConsent() { return (List) this.fields.get(TcfCaV1Field.VENDOR_IMPLIED_CONSENT).getValue(); } + + @SuppressWarnings("unchecked") + public List getPubRestrictions() { + return (List) this.fields.get(TcfCaV1Field.PUB_RESTRICTIONS).getValue(); + } public Integer getPubPurposesSegmentType() { return (Integer) this.fields.get(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE).getValue(); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java index ad6439dd..1e45d617 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java @@ -13,10 +13,10 @@ import com.iab.gpp.encoder.datatype.EncodableDatetime; import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; import com.iab.gpp.encoder.datatype.EncodableFixedInteger; -import com.iab.gpp.encoder.datatype.EncodableFixedIntegerRange; import com.iab.gpp.encoder.datatype.EncodableFixedString; import com.iab.gpp.encoder.datatype.EncodableFlexibleBitfield; import com.iab.gpp.encoder.datatype.EncodableOptimizedFixedRange; +import com.iab.gpp.encoder.datatype.RangeEntry; import com.iab.gpp.encoder.datatype.encoder.AbstractBase64UrlEncoder; import com.iab.gpp.encoder.datatype.encoder.TraditionalBase64UrlEncoder; import com.iab.gpp.encoder.error.DecodingException; @@ -322,8 +322,8 @@ public List getVendorLegitimateInterests() { } @SuppressWarnings("unchecked") - public List getPublisherRestrictions() { - return (List) this.fields.get(TcfEuV2Field.PUBLISHER_RESTRICTIONS).getValue(); + public List getPublisherRestrictions() { + return (List) this.fields.get(TcfEuV2Field.PUBLISHER_RESTRICTIONS).getValue(); } public Integer getPublisherPurposesSegmentType() { From c7dbab5dff993f49da766a12c174a0d75ac95b50 Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Wed, 13 Dec 2023 10:19:41 -0700 Subject: [PATCH 30/36] tcfeu pub restirctions fix --- .../datatype/EncodableArrayOfFixedRanges.java | 113 +++++++++++++ ...a => EncodableArrayOfOptimizedRanges.java} | 8 +- .../EncodableOptimizedArrayOfRanges.java | 114 +++++++++++++ .../com/iab/gpp/encoder/section/TcfCaV1.java | 5 +- .../com/iab/gpp/encoder/section/TcfEuV2.java | 4 +- .../EncodableArrayOfFixedRangesTest.java | 158 ++++++++++++++++++ ... EncodableArrayOfOptimizedRangesTest.java} | 30 ++-- .../iab/gpp/encoder/section/TcfEuV2Test.java | 44 +++++ 8 files changed, 452 insertions(+), 24 deletions(-) create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRanges.java rename iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/{EncodableArrayOfRanges.java => EncodableArrayOfOptimizedRanges.java} (88%) create mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedArrayOfRanges.java create mode 100644 iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRangesTest.java rename iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/{EncodableArrayOfRangesTest.java => EncodableArrayOfOptimizedRangesTest.java} (86%) diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRanges.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRanges.java new file mode 100644 index 00000000..5cfc4edc --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRanges.java @@ -0,0 +1,113 @@ +package com.iab.gpp.encoder.datatype; + +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; +import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; + +public class EncodableArrayOfFixedRanges extends AbstractEncodableBitStringDataType> { + + private int keyBitStringLength; + private int typeBitStringLength; + + protected EncodableArrayOfFixedRanges(int keyBitStringLength, int typeBitStringLength) { + super(true); + this.keyBitStringLength = keyBitStringLength; + this.typeBitStringLength = typeBitStringLength; + } + + public EncodableArrayOfFixedRanges(int keyBitStringLength, int typeBitStringLength, List value) { + super(true); + this.keyBitStringLength = keyBitStringLength; + this.typeBitStringLength = typeBitStringLength; + setValue(value); + } + + public EncodableArrayOfFixedRanges(int keyBitStringLength, int typeBitStringLength, List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + this.keyBitStringLength = keyBitStringLength; + this.typeBitStringLength = typeBitStringLength; + setValue(value); + } + + @Override + public String encode() throws EncodingException { + try { + List entries = this.value; + + StringBuilder sb = new StringBuilder(); + sb.append(FixedIntegerEncoder.encode(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())); + } + + return sb.toString(); + } catch (Exception e) { + throw new EncodingException(e); + } + } + + @Override + public void decode(String bitString) throws DecodingException { + try { + List entries = new ArrayList<>(); + + int size = FixedIntegerEncoder.decode(bitString.substring(0, 12)); + int index = 12; + for (int i = 0; i < size; i++) { + int key = FixedIntegerEncoder.decode(bitString.substring(index, index + keyBitStringLength)); + index += keyBitStringLength; + + int type = FixedIntegerEncoder.decode(bitString.substring(index, index + typeBitStringLength)); + index += typeBitStringLength; + + String substring = new EncodableFixedIntegerRange().substring(bitString, index); + List ids = FixedIntegerRangeEncoder.decode(substring); + index += substring.length(); + + entries.add(new RangeEntry(key, type, ids)); + } + + this.value = entries; + } catch (Exception e) { + throw new DecodingException(e); + } + } + + @Override + public String substring(String 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(); + for (int i = 0; i < size; i++) { + sb.append(bitString.substring(index, index + 8)); + index += 8; + + String substring = null; + int max = FixedIntegerEncoder.decode(bitString.substring(index, index + 16)); + if (bitString.charAt(index + 16) == '1') { + substring = bitString.substring(index, index + 17) + + new EncodableFixedIntegerRange().substring(bitString, index + 17); + } else { + substring = bitString.substring(index, index + 17 + max); + } + index += substring.length(); + + sb.append(substring); + } + + return sb.toString(); + } catch (Exception e) { + throw new SubstringException(e); + } + } + +} diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRanges.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRanges.java similarity index 88% rename from iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRanges.java rename to iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRanges.java index 3c5237a0..b76a4629 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRanges.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRanges.java @@ -7,25 +7,25 @@ import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; -public class EncodableArrayOfRanges extends AbstractEncodableBitStringDataType> { +public class EncodableArrayOfOptimizedRanges extends AbstractEncodableBitStringDataType> { private int keyBitStringLength; private int typeBitStringLength; - protected EncodableArrayOfRanges(int keyBitStringLength, int typeBitStringLength) { + protected EncodableArrayOfOptimizedRanges(int keyBitStringLength, int typeBitStringLength) { super(true); this.keyBitStringLength = keyBitStringLength; this.typeBitStringLength = typeBitStringLength; } - public EncodableArrayOfRanges(int keyBitStringLength, int typeBitStringLength, List value) { + public EncodableArrayOfOptimizedRanges(int keyBitStringLength, int typeBitStringLength, List value) { super(true); this.keyBitStringLength = keyBitStringLength; this.typeBitStringLength = typeBitStringLength; setValue(value); } - public EncodableArrayOfRanges(int keyBitStringLength, int typeBitStringLength, List value, boolean hardFailIfMissing) { + public EncodableArrayOfOptimizedRanges(int keyBitStringLength, int typeBitStringLength, List value, boolean hardFailIfMissing) { super(hardFailIfMissing); this.keyBitStringLength = keyBitStringLength; this.typeBitStringLength = typeBitStringLength; diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedArrayOfRanges.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedArrayOfRanges.java new file mode 100644 index 00000000..40fad646 --- /dev/null +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedArrayOfRanges.java @@ -0,0 +1,114 @@ +package com.iab.gpp.encoder.datatype; + +import java.util.ArrayList; +import java.util.List; +import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; +import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; +import com.iab.gpp.encoder.datatype.encoder.OptimizedFixedRangeEncoder; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; + +public class EncodableOptimizedArrayOfRanges extends AbstractEncodableBitStringDataType> { + + private int keyBitStringLength; + private int typeBitStringLength; + + protected EncodableOptimizedArrayOfRanges(int keyBitStringLength, int typeBitStringLength) { + super(true); + this.keyBitStringLength = keyBitStringLength; + this.typeBitStringLength = typeBitStringLength; + } + + public EncodableOptimizedArrayOfRanges(int keyBitStringLength, int typeBitStringLength, List value) { + super(true); + this.keyBitStringLength = keyBitStringLength; + this.typeBitStringLength = typeBitStringLength; + setValue(value); + } + + public EncodableOptimizedArrayOfRanges(int keyBitStringLength, int typeBitStringLength, List value, boolean hardFailIfMissing) { + super(hardFailIfMissing); + this.keyBitStringLength = keyBitStringLength; + this.typeBitStringLength = typeBitStringLength; + setValue(value); + } + + @Override + public String encode() throws EncodingException { + try { + List entries = this.value; + + StringBuilder sb = new StringBuilder(); + sb.append(FixedIntegerEncoder.encode(entries.size(), 12)); + for (RangeEntry entry : entries) { + sb.append(FixedIntegerEncoder.encode(entry.getKey(), keyBitStringLength)) + .append(FixedIntegerEncoder.encode(entry.getType(), typeBitStringLength)) + .append(OptimizedFixedRangeEncoder.encode(entry.getIds())); + } + + return sb.toString(); + } catch (Exception e) { + throw new EncodingException(e); + } + } + + @Override + public void decode(String bitString) throws DecodingException { + try { + List entries = new ArrayList<>(); + + int size = FixedIntegerEncoder.decode(bitString.substring(0, 12)); + int index = 12; + for (int i = 0; i < size; i++) { + int key = FixedIntegerEncoder.decode(bitString.substring(index, index + keyBitStringLength)); + index += keyBitStringLength; + + int type = FixedIntegerEncoder.decode(bitString.substring(index, index + typeBitStringLength)); + index += typeBitStringLength; + + String substring = new EncodableOptimizedFixedRange().substring(bitString, index); + List ids = FixedIntegerRangeEncoder.decode(substring); + index += substring.length(); + + entries.add(new RangeEntry(key, type, ids)); + } + + this.value = entries; + } catch (Exception e) { + throw new DecodingException(e); + } + } + + @Override + public String substring(String 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(); + for (int i = 0; i < size; i++) { + sb.append(bitString.substring(index, index + 8)); + index += 8; + + String substring = null; + int max = FixedIntegerEncoder.decode(bitString.substring(index, index + 16)); + if (bitString.charAt(index + 16) == '1') { + substring = bitString.substring(index, index + 17) + + new EncodableFixedIntegerRange().substring(bitString, index + 17); + } else { + substring = bitString.substring(index, index + 17 + max); + } + index += substring.length(); + + sb.append(substring); + } + + return sb.toString(); + } catch (Exception e) { + throw new SubstringException(e); + } + } + +} 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 f6ebf10a..10376b78 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 @@ -8,7 +8,7 @@ import java.util.List; import java.util.function.IntSupplier; import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableArrayOfRanges; +import com.iab.gpp.encoder.datatype.EncodableArrayOfOptimizedRanges; import com.iab.gpp.encoder.datatype.EncodableBoolean; import com.iab.gpp.encoder.datatype.EncodableDatetime; import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; @@ -23,7 +23,6 @@ import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; import com.iab.gpp.encoder.field.TcfCaV1Field; -import com.iab.gpp.encoder.field.TcfEuV2Field; public class TcfCaV1 extends AbstractEncodableSegmentedBitStringSection { public static int ID = 5; @@ -70,7 +69,7 @@ private void initFields() { false, false, false, false, false, false, false, false, false, false, false, false, false, false))); fields.put(TcfCaV1Field.VENDOR_EXPRESS_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); fields.put(TcfCaV1Field.VENDOR_IMPLIED_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); - fields.put(TcfCaV1Field.PUB_RESTRICTIONS, new EncodableArrayOfRanges(6, 2, new ArrayList<>(), false)); + fields.put(TcfCaV1Field.PUB_RESTRICTIONS, new EncodableArrayOfOptimizedRanges(6, 2, new ArrayList<>(), false)); // publisher purposes segment fields.put(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java index 1e45d617..9b63d0ca 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java @@ -8,7 +8,7 @@ import java.util.List; import java.util.function.IntSupplier; import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableArrayOfRanges; +import com.iab.gpp.encoder.datatype.EncodableArrayOfFixedRanges; import com.iab.gpp.encoder.datatype.EncodableBoolean; import com.iab.gpp.encoder.datatype.EncodableDatetime; import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; @@ -73,7 +73,7 @@ private void initFields() { fields.put(TcfEuV2Field.VENDOR_CONSENTS, new EncodableOptimizedFixedRange(new ArrayList<>())); fields.put(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, new EncodableOptimizedFixedRange(new ArrayList<>())); - fields.put(TcfEuV2Field.PUBLISHER_RESTRICTIONS, new EncodableArrayOfRanges(6, 2, new ArrayList<>(), false)); + fields.put(TcfEuV2Field.PUBLISHER_RESTRICTIONS, new EncodableArrayOfFixedRanges(6, 2, new ArrayList<>(), false)); // publisher purposes segment fields.put(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRangesTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRangesTest.java new file mode 100644 index 00000000..20d040c3 --- /dev/null +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRangesTest.java @@ -0,0 +1,158 @@ +package com.iab.gpp.encoder.datatype; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import com.iab.gpp.encoder.error.DecodingException; +import com.iab.gpp.encoder.error.EncodingException; + +public class EncodableArrayOfFixedRangesTest { + + @Test + public void testEncode1() throws EncodingException { + List value = new ArrayList<>(); + EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2, value); + Assertions.assertEquals("000000000000", + encodableArrayOfRanges.encode()); + } + + @Test + public void testEncode2() throws EncodingException { + List value = new ArrayList<>(); + value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); + EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2, value); + Assertions.assertEquals("00000000000100010110000000000011000000000000011000000000000001100000000000000110000", + encodableArrayOfRanges.encode()); + } + + @Test + public void testEncode3() throws EncodingException { + List value = new ArrayList<>(); + value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); + value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); + EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2, value); + Assertions.assertEquals("00000000001000010110000000000011000000000000011000000000000001100000000000000110000000101100000000000100000000000001001000000000000011110", + encodableArrayOfRanges.encode()); + } + + @Test + public void testEncode4() throws EncodingException { + List value = new ArrayList<>(); + value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); + value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); + value.add(new RangeEntry(5, 2, Arrays.asList(28))); + EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2, value); + Assertions.assertEquals("000000000011000101100000000000110000000000000110000000000000011000000000000001100000001011000000000001000000000000010010000000000000111100001011000000000000100000000000011100", + encodableArrayOfRanges.encode()); + } + + @Test + public void testEncode5() throws EncodingException { + List value = new ArrayList<>(); + value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); + value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); + value.add(new RangeEntry(5, 2, Arrays.asList(28))); + value.add(new RangeEntry(5, 2, Arrays.asList(29))); + EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2, value); + Assertions.assertEquals("0000000001000001011000000000001100000000000001100000000000000110000000000000011000000010110000000000010000000000000100100000000000001111000010110000000000001000000000000111000001011000000000000100000000000011101", + encodableArrayOfRanges.encode()); + } + + @Test + public void testDecode1() throws DecodingException { + EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2); + encodableArrayOfRanges.decode("000000000000"); + Assertions.assertTrue(encodableArrayOfRanges.getValue().isEmpty()); + } + + @Test + public void testDecode2() throws DecodingException { + EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2); + encodableArrayOfRanges.decode("00000000000100010110000000000011000000000000011000000000000001100000000000000110000"); + Assertions.assertEquals(1, encodableArrayOfRanges.getValue().size()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); + Assertions.assertEquals(Arrays.asList(12, 24, 48), encodableArrayOfRanges.getValue().get(0).getIds()); + } + + @Test + public void testDecode3() throws DecodingException { + EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2); + encodableArrayOfRanges.decode("00000000001000010110000000000011000000000000011000000000000001100000000000000110000000101100000000000100000000000001001000000000000011110"); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().size()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); + Assertions.assertEquals(encodableArrayOfRanges.getValue().get(0).getIds(), Arrays.asList(12, 24, 48)); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(1).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(1).getType()); + Assertions.assertEquals(encodableArrayOfRanges.getValue().get(1).getIds(), Arrays.asList(18, 30)); + } + + @Test + public void testDecode4() throws DecodingException { + EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2); + encodableArrayOfRanges.decode("000000000011000101100000000000110000000000000110000000000000011000000000000001100000001011000000000001000000000000010010000000000000111100001011000000000000100000000000011100"); + Assertions.assertEquals(3, encodableArrayOfRanges.getValue().size()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); + Assertions.assertEquals(encodableArrayOfRanges.getValue().get(0).getIds(), Arrays.asList(12, 24, 48)); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(1).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(1).getType()); + Assertions.assertEquals(encodableArrayOfRanges.getValue().get(1).getIds(), Arrays.asList(18, 30)); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(2).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(2).getType()); + Assertions.assertEquals(encodableArrayOfRanges.getValue().get(2).getIds(), Arrays.asList(28)); + } + + @Test + public void testDecode5() throws DecodingException { + EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2); + encodableArrayOfRanges.decode("0000000001000001011000000000001100000000000001100000000000000110000000000000011000000010110000000000010000000000000100100000000000001111000010110000000000001000000000000111000001011000000000000100000000000011101"); + Assertions.assertEquals(4, encodableArrayOfRanges.getValue().size()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); + Assertions.assertEquals(Arrays.asList(12, 24, 48), encodableArrayOfRanges.getValue().get(0).getIds()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(1).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(1).getType()); + Assertions.assertEquals(Arrays.asList(18, 30), encodableArrayOfRanges.getValue().get(1).getIds()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(2).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(2).getType()); + Assertions.assertEquals(Arrays.asList(28), encodableArrayOfRanges.getValue().get(2).getIds()); + Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(3).getKey()); + Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(3).getType()); + Assertions.assertEquals(Arrays.asList(29), encodableArrayOfRanges.getValue().get(3).getIds()); + } + + @Test + public void testSubstring1() throws DecodingException, SubstringException { + Assertions.assertEquals("000000000000", new EncodableArrayOfFixedRanges(6, 2).substring( + "01010100000000000011111111000000000001110000000000000000000000000000001000000000000000000000000000000", 6)); + } + + @Test + public void testSubstring2() throws DecodingException, SubstringException { + Assertions.assertEquals("00000000000111111111000000000001110000000000000000000000000000001", + new EncodableArrayOfFixedRanges(6, 2).substring( + "01010100000000000111111111000000000001110000000000000000000000000000001000000000000000000000000000000", + 6)); + } + + @Test + public void testSubstring3() throws DecodingException, SubstringException { + Assertions.assertEquals("000000000001111111110000000000011101100000000000100000000000011101", + new EncodableArrayOfFixedRanges(6, 2).substring( + "01010100000000000111111111000000000001110110000000000010000000000001110100000000000000000000000000000", + 6)); + } + + @Test + public void testSubstring4() throws DecodingException, SubstringException { + Assertions.assertEquals( + "0000000001000001011100000000001100000000000000001000000000001000000000000000000000001000101110000000000011110000000000000000000100000000000100010111000000000001110000000000000000000000000000001000101110000000000011101100000000000100000000000011101", + new EncodableArrayOfFixedRanges(6, 2).substring( + "0101010000000001000001011100000000001100000000000000001000000000001000000000000000000000001000101110000000000011110000000000000000000100000000000100010111000000000001110000000000000000000000000000001000101110000000000011101100000000000100000000000011101010101", + 6)); + } +} diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRangesTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRangesTest.java similarity index 86% rename from iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRangesTest.java rename to iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRangesTest.java index 4893901f..b53ecf80 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfRangesTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRangesTest.java @@ -8,12 +8,12 @@ import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; -public class EncodableArrayOfRangesTest { +public class EncodableArrayOfOptimizedRangesTest { @Test public void testEncode1() throws EncodingException { List value = new ArrayList<>(); - EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2, value); + EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2, value); Assertions.assertEquals("000000000000", encodableArrayOfRanges.encode()); } @@ -22,7 +22,7 @@ public void testEncode1() throws EncodingException { public void testEncode2() throws EncodingException { List value = new ArrayList<>(); value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); - EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2, value); + EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2, value); Assertions.assertEquals("0000000000010001011000000000001100000000000000001000000000001000000000000000000000001", encodableArrayOfRanges.encode()); } @@ -32,7 +32,7 @@ public void testEncode3() throws EncodingException { List value = new ArrayList<>(); value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); - EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2, value); + EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2, value); Assertions.assertEquals("00000000001000010110000000000011000000000000000010000000000010000000000000000000000010001011000000000000111100000000000000000001000000000001", encodableArrayOfRanges.encode()); } @@ -43,7 +43,7 @@ public void testEncode4() throws EncodingException { value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); value.add(new RangeEntry(5, 2, Arrays.asList(28))); - EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2, value); + EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2, value); Assertions.assertEquals("0000000000110001011000000000001100000000000000001000000000001000000000000000000000001000101100000000000011110000000000000000000100000000000100010110000000000001110000000000000000000000000000001", encodableArrayOfRanges.encode()); } @@ -55,21 +55,21 @@ public void testEncode5() throws EncodingException { value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); value.add(new RangeEntry(5, 2, Arrays.asList(28))); value.add(new RangeEntry(5, 2, Arrays.asList(29))); - EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2, value); + EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2, value); Assertions.assertEquals("0000000001000001011000000000001100000000000000001000000000001000000000000000000000001000101100000000000011110000000000000000000100000000000100010110000000000001110000000000000000000000000000001000101100000000000011101100000000000100000000000011101", encodableArrayOfRanges.encode()); } @Test public void testDecode1() throws DecodingException { - EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2); + EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2); encodableArrayOfRanges.decode("000000000000"); Assertions.assertTrue(encodableArrayOfRanges.getValue().isEmpty()); } @Test public void testDecode2() throws DecodingException { - EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2); + EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2); encodableArrayOfRanges.decode("0000000000010001011000000000001100000000000000001000000000001000000000000000000000001"); Assertions.assertEquals(1, encodableArrayOfRanges.getValue().size()); Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); @@ -79,7 +79,7 @@ public void testDecode2() throws DecodingException { @Test public void testDecode3() throws DecodingException { - EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2); + EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2); encodableArrayOfRanges.decode("00000000001000010110000000000011000000000000000010000000000010000000000000000000000010001011000000000000111100000000000000000001000000000001"); Assertions.assertEquals(2, encodableArrayOfRanges.getValue().size()); Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); @@ -92,7 +92,7 @@ public void testDecode3() throws DecodingException { @Test public void testDecode4() throws DecodingException { - EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2); + EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2); encodableArrayOfRanges.decode("0000000000110001011000000000001100000000000000001000000000001000000000000000000000001000101100000000000011110000000000000000000100000000000100010110000000000001110000000000000000000000000000001"); Assertions.assertEquals(3, encodableArrayOfRanges.getValue().size()); Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); @@ -108,7 +108,7 @@ public void testDecode4() throws DecodingException { @Test public void testDecode5() throws DecodingException { - EncodableArrayOfRanges encodableArrayOfRanges = new EncodableArrayOfRanges(6, 2); + EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2); encodableArrayOfRanges.decode("0000000001000001011000000000001100000000000000001000000000001000000000000000000000001000101100000000000011110000000000000000000100000000000100010110000000000001110000000000000000000000000000001000101100000000000011101100000000000100000000000011101"); Assertions.assertEquals(4, encodableArrayOfRanges.getValue().size()); Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); @@ -127,14 +127,14 @@ public void testDecode5() throws DecodingException { @Test public void testSubstring1() throws DecodingException, SubstringException { - Assertions.assertEquals("000000000000", new EncodableArrayOfRanges(6, 2).substring( + Assertions.assertEquals("000000000000", new EncodableArrayOfOptimizedRanges(6, 2).substring( "01010100000000000011111111000000000001110000000000000000000000000000001000000000000000000000000000000", 6)); } @Test public void testSubstring2() throws DecodingException, SubstringException { Assertions.assertEquals("00000000000111111111000000000001110000000000000000000000000000001", - new EncodableArrayOfRanges(6, 2).substring( + new EncodableArrayOfOptimizedRanges(6, 2).substring( "01010100000000000111111111000000000001110000000000000000000000000000001000000000000000000000000000000", 6)); } @@ -142,7 +142,7 @@ public void testSubstring2() throws DecodingException, SubstringException { @Test public void testSubstring3() throws DecodingException, SubstringException { Assertions.assertEquals("000000000001111111110000000000011101100000000000100000000000011101", - new EncodableArrayOfRanges(6, 2).substring( + new EncodableArrayOfOptimizedRanges(6, 2).substring( "01010100000000000111111111000000000001110110000000000010000000000001110100000000000000000000000000000", 6)); } @@ -151,7 +151,7 @@ public void testSubstring3() throws DecodingException, SubstringException { public void testSubstring4() throws DecodingException, SubstringException { Assertions.assertEquals( "0000000001000001011100000000001100000000000000001000000000001000000000000000000000001000101110000000000011110000000000000000000100000000000100010111000000000001110000000000000000000000000000001000101110000000000011101100000000000100000000000011101", - new EncodableArrayOfRanges(6, 2).substring( + new EncodableArrayOfOptimizedRanges(6, 2).substring( "0101010000000001000001011100000000001100000000000000001000000000001000000000000000000000001000101110000000000011110000000000000000000100000000000100010111000000000001110000000000000000000000000000001000101110000000000011101100000000000100000000000011101010101", 6)); } diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java index ee7145a9..a4d335dc 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfEuV2Test.java @@ -6,6 +6,7 @@ import java.util.List; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import com.iab.gpp.encoder.datatype.RangeEntry; import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; import com.iab.gpp.encoder.error.InvalidFieldException; @@ -349,6 +350,49 @@ public void testDecode6() throws DecodingException { tcfEuV2.getFieldValue("VendorLegitimateInterests")); } + @Test + public void testDecode7() throws DecodingException { + TcfEuV2 tcfEuV2 = new TcfEuV2("COoC-kUOoC-kUAHABAENAwCoAIAAAELAAAwIF5wAoAAgAGAvMACX_ABBAAQAFA"); + + Assertions.assertEquals(2, tcfEuV2.getFieldValue("Version")); + Assertions.assertEquals("2019-10-07T05:17:54Z[UTC]", tcfEuV2.getFieldValue("Created").toString()); + Assertions.assertEquals("2019-10-07T05:17:54Z[UTC]", tcfEuV2.getFieldValue("LastUpdated").toString()); + Assertions.assertEquals(7, tcfEuV2.getFieldValue("CmpId")); + Assertions.assertEquals(1, tcfEuV2.getFieldValue("CmpVersion")); + Assertions.assertEquals(0, tcfEuV2.getFieldValue("ConsentScreen")); + Assertions.assertEquals("EN", tcfEuV2.getFieldValue("ConsentLanguage")); + Assertions.assertEquals(48, tcfEuV2.getFieldValue("VendorListVersion")); + Assertions.assertEquals(2, tcfEuV2.getFieldValue("PolicyVersion")); + Assertions.assertEquals(true, tcfEuV2.getFieldValue("IsServiceSpecific")); + Assertions.assertEquals(false, tcfEuV2.getFieldValue("UseNonStandardStacks")); + + Assertions.assertEquals( + Arrays.asList(true, false, false, false, false, false, false, false, false, false, false, false), + tcfEuV2.getFieldValue("SpecialFeatureOptins")); + Assertions.assertEquals( + Arrays.asList(true, false, false, false, false, false, false, false, false, false, false, false, false, false, + false, false, false, false, false, false, false, false, false, false), + tcfEuV2.getFieldValue("PurposeConsents")); + Assertions.assertEquals( + Arrays.asList(false, true, false, false, false, false, true, false, true, true, false, false, false, false, + false, false, false, false, false, false, false, false, false, false), + tcfEuV2.getFieldValue("PurposeLegitimateInterests")); + + Assertions.assertEquals(false, tcfEuV2.getFieldValue("PurposeOneTreatment")); + Assertions.assertEquals("GB", tcfEuV2.getFieldValue("PublisherCountryCode")); + + Assertions.assertEquals(Arrays.asList(1, 2, 3, 755), tcfEuV2.getFieldValue("VendorConsents")); + + Assertions.assertEquals(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9), + tcfEuV2.getFieldValue("VendorLegitimateInterests")); + + Assertions.assertEquals(1, ((List)tcfEuV2.getFieldValue("PublisherRestrictions")).size()); + RangeEntry rangeEntry = ((List)tcfEuV2.getFieldValue("PublisherRestrictions")).get(0); + Assertions.assertEquals(1, rangeEntry.getKey()); + Assertions.assertEquals(0, rangeEntry.getType()); + Assertions.assertEquals(Arrays.asList(10), rangeEntry.getIds()); + } + @Test() public void testDecodeGarbage() { Assertions.assertThrows(DecodingException.class, () -> { From 41df5bc169ffb18e630d8cbc9012d2d95b5be5dc Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Wed, 13 Dec 2023 11:09:39 -0700 Subject: [PATCH 31/36] cleanup --- .../EncodableOptimizedArrayOfRanges.java | 114 ------------------ ...actEncodableSegmentedBitStringSection.java | 1 - 2 files changed, 115 deletions(-) delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedArrayOfRanges.java diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedArrayOfRanges.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedArrayOfRanges.java deleted file mode 100644 index 40fad646..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableOptimizedArrayOfRanges.java +++ /dev/null @@ -1,114 +0,0 @@ -package com.iab.gpp.encoder.datatype; - -import java.util.ArrayList; -import java.util.List; -import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; -import com.iab.gpp.encoder.datatype.encoder.FixedIntegerRangeEncoder; -import com.iab.gpp.encoder.datatype.encoder.OptimizedFixedRangeEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; - -public class EncodableOptimizedArrayOfRanges extends AbstractEncodableBitStringDataType> { - - private int keyBitStringLength; - private int typeBitStringLength; - - protected EncodableOptimizedArrayOfRanges(int keyBitStringLength, int typeBitStringLength) { - super(true); - this.keyBitStringLength = keyBitStringLength; - this.typeBitStringLength = typeBitStringLength; - } - - public EncodableOptimizedArrayOfRanges(int keyBitStringLength, int typeBitStringLength, List value) { - super(true); - this.keyBitStringLength = keyBitStringLength; - this.typeBitStringLength = typeBitStringLength; - setValue(value); - } - - public EncodableOptimizedArrayOfRanges(int keyBitStringLength, int typeBitStringLength, List value, boolean hardFailIfMissing) { - super(hardFailIfMissing); - this.keyBitStringLength = keyBitStringLength; - this.typeBitStringLength = typeBitStringLength; - setValue(value); - } - - @Override - public String encode() throws EncodingException { - try { - List entries = this.value; - - StringBuilder sb = new StringBuilder(); - sb.append(FixedIntegerEncoder.encode(entries.size(), 12)); - for (RangeEntry entry : entries) { - sb.append(FixedIntegerEncoder.encode(entry.getKey(), keyBitStringLength)) - .append(FixedIntegerEncoder.encode(entry.getType(), typeBitStringLength)) - .append(OptimizedFixedRangeEncoder.encode(entry.getIds())); - } - - return sb.toString(); - } catch (Exception e) { - throw new EncodingException(e); - } - } - - @Override - public void decode(String bitString) throws DecodingException { - try { - List entries = new ArrayList<>(); - - int size = FixedIntegerEncoder.decode(bitString.substring(0, 12)); - int index = 12; - for (int i = 0; i < size; i++) { - int key = FixedIntegerEncoder.decode(bitString.substring(index, index + keyBitStringLength)); - index += keyBitStringLength; - - int type = FixedIntegerEncoder.decode(bitString.substring(index, index + typeBitStringLength)); - index += typeBitStringLength; - - String substring = new EncodableOptimizedFixedRange().substring(bitString, index); - List ids = FixedIntegerRangeEncoder.decode(substring); - index += substring.length(); - - entries.add(new RangeEntry(key, type, ids)); - } - - this.value = entries; - } catch (Exception e) { - throw new DecodingException(e); - } - } - - @Override - public String substring(String 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(); - for (int i = 0; i < size; i++) { - sb.append(bitString.substring(index, index + 8)); - index += 8; - - String substring = null; - int max = FixedIntegerEncoder.decode(bitString.substring(index, index + 16)); - if (bitString.charAt(index + 16) == '1') { - substring = bitString.substring(index, index + 17) - + new EncodableFixedIntegerRange().substring(bitString, index + 17); - } else { - substring = bitString.substring(index, index + 17 + max); - } - index += substring.length(); - - sb.append(substring); - } - - return sb.toString(); - } catch (Exception e) { - throw new SubstringException(e); - } - } - -} 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 index 278c5944..eb5d5459 100644 --- 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 @@ -78,7 +78,6 @@ private void decodeSegmentFromBitString(String[] segment, String segmentBitStrin if (this.fields.containsKey(fieldName)) { try { String substring = field.substring(segmentBitString, index); - System.out.println(fieldName + ": " + substring + " (" + index + "/" + segmentBitString.length() + ")"); field.decode(substring); index += substring.length(); } catch (SubstringException e) { From 58556f5826a6a7fa9623f85ca3c45b424b01ac5b Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Wed, 13 Dec 2023 12:34:57 -0700 Subject: [PATCH 32/36] pub restrictions fix --- ...> EncodableArrayOfFixedIntegerRanges.java} | 29 ++-- .../EncodableArrayOfOptimizedRanges.java | 113 ------------- .../com/iab/gpp/encoder/section/TcfCaV1.java | 4 +- .../com/iab/gpp/encoder/section/TcfEuV2.java | 4 +- .../EncodableArrayOfFixedRangesTest.java | 158 ------------------ .../EncodableArrayOfOptimizedRangesTest.java | 158 ------------------ .../iab/gpp/encoder/section/TcfCaV1Test.java | 2 +- 7 files changed, 18 insertions(+), 450 deletions(-) rename iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/{EncodableArrayOfFixedRanges.java => EncodableArrayOfFixedIntegerRanges.java} (74%) delete mode 100644 iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRanges.java delete mode 100644 iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRangesTest.java delete mode 100644 iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRangesTest.java diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRanges.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedIntegerRanges.java similarity index 74% rename from iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRanges.java rename to iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedIntegerRanges.java index 5cfc4edc..d892e9f6 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRanges.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedIntegerRanges.java @@ -7,25 +7,25 @@ import com.iab.gpp.encoder.error.DecodingException; import com.iab.gpp.encoder.error.EncodingException; -public class EncodableArrayOfFixedRanges extends AbstractEncodableBitStringDataType> { +public class EncodableArrayOfFixedIntegerRanges extends AbstractEncodableBitStringDataType> { private int keyBitStringLength; private int typeBitStringLength; - protected EncodableArrayOfFixedRanges(int keyBitStringLength, int typeBitStringLength) { + protected EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength) { super(true); this.keyBitStringLength = keyBitStringLength; this.typeBitStringLength = typeBitStringLength; } - public EncodableArrayOfFixedRanges(int keyBitStringLength, int typeBitStringLength, List value) { + public EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength, List value) { super(true); this.keyBitStringLength = keyBitStringLength; this.typeBitStringLength = typeBitStringLength; setValue(value); } - public EncodableArrayOfFixedRanges(int keyBitStringLength, int typeBitStringLength, List value, boolean hardFailIfMissing) { + public EncodableArrayOfFixedIntegerRanges(int keyBitStringLength, int typeBitStringLength, List value, boolean hardFailIfMissing) { super(hardFailIfMissing); this.keyBitStringLength = keyBitStringLength; this.typeBitStringLength = typeBitStringLength; @@ -88,20 +88,17 @@ public String substring(String bitString, int fromIndex) throws SubstringExcepti int index = fromIndex + sb.length(); for (int i = 0; i < size; i++) { - sb.append(bitString.substring(index, index + 8)); - index += 8; + String keySubstring = bitString.substring(index, index + keyBitStringLength); + index += keySubstring.length(); + sb.append(keySubstring); - String substring = null; - int max = FixedIntegerEncoder.decode(bitString.substring(index, index + 16)); - if (bitString.charAt(index + 16) == '1') { - substring = bitString.substring(index, index + 17) - + new EncodableFixedIntegerRange().substring(bitString, index + 17); - } else { - substring = bitString.substring(index, index + 17 + max); - } - index += substring.length(); + String typeSubstring = bitString.substring(index, index + typeBitStringLength); + index += typeSubstring.length(); + sb.append(typeSubstring); - sb.append(substring); + String rangeSubstring = new EncodableFixedIntegerRange().substring(bitString, index); + index += rangeSubstring.length(); + sb.append(rangeSubstring); } return sb.toString(); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRanges.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRanges.java deleted file mode 100644 index b76a4629..00000000 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRanges.java +++ /dev/null @@ -1,113 +0,0 @@ -package com.iab.gpp.encoder.datatype; - -import java.util.ArrayList; -import java.util.List; -import com.iab.gpp.encoder.datatype.encoder.FixedIntegerEncoder; -import com.iab.gpp.encoder.datatype.encoder.OptimizedFixedRangeEncoder; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; - -public class EncodableArrayOfOptimizedRanges extends AbstractEncodableBitStringDataType> { - - private int keyBitStringLength; - private int typeBitStringLength; - - protected EncodableArrayOfOptimizedRanges(int keyBitStringLength, int typeBitStringLength) { - super(true); - this.keyBitStringLength = keyBitStringLength; - this.typeBitStringLength = typeBitStringLength; - } - - public EncodableArrayOfOptimizedRanges(int keyBitStringLength, int typeBitStringLength, List value) { - super(true); - this.keyBitStringLength = keyBitStringLength; - this.typeBitStringLength = typeBitStringLength; - setValue(value); - } - - public EncodableArrayOfOptimizedRanges(int keyBitStringLength, int typeBitStringLength, List value, boolean hardFailIfMissing) { - super(hardFailIfMissing); - this.keyBitStringLength = keyBitStringLength; - this.typeBitStringLength = typeBitStringLength; - setValue(value); - } - - @Override - public String encode() throws EncodingException { - try { - List entries = this.value; - - StringBuilder sb = new StringBuilder(); - sb.append(FixedIntegerEncoder.encode(entries.size(), 12)); - for (RangeEntry entry : entries) { - sb.append(FixedIntegerEncoder.encode(entry.getKey(), keyBitStringLength)) - .append(FixedIntegerEncoder.encode(entry.getType(), typeBitStringLength)) - .append(OptimizedFixedRangeEncoder.encode(entry.getIds())); - } - - return sb.toString(); - } catch (Exception e) { - throw new EncodingException(e); - } - } - - @Override - public void decode(String bitString) throws DecodingException { - try { - List entries = new ArrayList<>(); - - int size = FixedIntegerEncoder.decode(bitString.substring(0, 12)); - int index = 12; - for (int i = 0; i < size; i++) { - int key = FixedIntegerEncoder.decode(bitString.substring(index, index + keyBitStringLength)); - index += keyBitStringLength; - - int type = FixedIntegerEncoder.decode(bitString.substring(index, index + typeBitStringLength)); - index += typeBitStringLength; - - String substring = new EncodableOptimizedFixedRange().substring(bitString, index); - List ids = OptimizedFixedRangeEncoder.decode(substring); - index += substring.length(); - - entries.add(new RangeEntry(key, type, ids)); - } - - this.value = entries; - } catch (Exception e) { - throw new DecodingException(e); - } - } - - @Override - public String substring(String 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(); - for (int i = 0; i < size; i++) { - sb.append(bitString.substring(index, index + 8)); - index += 8; - - String substring = null; - int max = FixedIntegerEncoder.decode(bitString.substring(index, index + 16)); - if (bitString.charAt(index + 16) == '1') { - substring = bitString.substring(index, index + 17) - + new EncodableFixedIntegerRange().substring(bitString, index + 17); - } else { - substring = bitString.substring(index, index + 17 + max); - } - index += substring.length(); - - sb.append(substring); - } - - return sb.toString(); - } catch (Exception e) { - throw new SubstringException(e); - } - } - -} 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 10376b78..d69fb6b9 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 @@ -8,7 +8,7 @@ import java.util.List; import java.util.function.IntSupplier; import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableArrayOfOptimizedRanges; +import com.iab.gpp.encoder.datatype.EncodableArrayOfFixedIntegerRanges; import com.iab.gpp.encoder.datatype.EncodableBoolean; import com.iab.gpp.encoder.datatype.EncodableDatetime; import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; @@ -69,7 +69,7 @@ private void initFields() { false, false, false, false, false, false, false, false, false, false, false, false, false, false))); fields.put(TcfCaV1Field.VENDOR_EXPRESS_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); fields.put(TcfCaV1Field.VENDOR_IMPLIED_CONSENT, new EncodableOptimizedFixedRange(new ArrayList<>())); - fields.put(TcfCaV1Field.PUB_RESTRICTIONS, new EncodableArrayOfOptimizedRanges(6, 2, new ArrayList<>(), false)); + fields.put(TcfCaV1Field.PUB_RESTRICTIONS, new EncodableArrayOfFixedIntegerRanges(6, 2, new ArrayList<>(), false)); // publisher purposes segment fields.put(TcfCaV1Field.PUB_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); diff --git a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java index 9b63d0ca..989c760f 100644 --- a/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java +++ b/iabgpp-encoder/src/main/java/com/iab/gpp/encoder/section/TcfEuV2.java @@ -8,7 +8,7 @@ import java.util.List; import java.util.function.IntSupplier; import java.util.stream.Collectors; -import com.iab.gpp.encoder.datatype.EncodableArrayOfFixedRanges; +import com.iab.gpp.encoder.datatype.EncodableArrayOfFixedIntegerRanges; import com.iab.gpp.encoder.datatype.EncodableBoolean; import com.iab.gpp.encoder.datatype.EncodableDatetime; import com.iab.gpp.encoder.datatype.EncodableFixedBitfield; @@ -73,7 +73,7 @@ private void initFields() { fields.put(TcfEuV2Field.VENDOR_CONSENTS, new EncodableOptimizedFixedRange(new ArrayList<>())); fields.put(TcfEuV2Field.VENDOR_LEGITIMATE_INTERESTS, new EncodableOptimizedFixedRange(new ArrayList<>())); - fields.put(TcfEuV2Field.PUBLISHER_RESTRICTIONS, new EncodableArrayOfFixedRanges(6, 2, new ArrayList<>(), false)); + fields.put(TcfEuV2Field.PUBLISHER_RESTRICTIONS, new EncodableArrayOfFixedIntegerRanges(6, 2, new ArrayList<>(), false)); // publisher purposes segment fields.put(TcfEuV2Field.PUBLISHER_PURPOSES_SEGMENT_TYPE, new EncodableFixedInteger(3, 3)); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRangesTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRangesTest.java deleted file mode 100644 index 20d040c3..00000000 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfFixedRangesTest.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.iab.gpp.encoder.datatype; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; - -public class EncodableArrayOfFixedRangesTest { - - @Test - public void testEncode1() throws EncodingException { - List value = new ArrayList<>(); - EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2, value); - Assertions.assertEquals("000000000000", - encodableArrayOfRanges.encode()); - } - - @Test - public void testEncode2() throws EncodingException { - List value = new ArrayList<>(); - value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); - EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2, value); - Assertions.assertEquals("00000000000100010110000000000011000000000000011000000000000001100000000000000110000", - encodableArrayOfRanges.encode()); - } - - @Test - public void testEncode3() throws EncodingException { - List value = new ArrayList<>(); - value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); - value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); - EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2, value); - Assertions.assertEquals("00000000001000010110000000000011000000000000011000000000000001100000000000000110000000101100000000000100000000000001001000000000000011110", - encodableArrayOfRanges.encode()); - } - - @Test - public void testEncode4() throws EncodingException { - List value = new ArrayList<>(); - value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); - value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); - value.add(new RangeEntry(5, 2, Arrays.asList(28))); - EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2, value); - Assertions.assertEquals("000000000011000101100000000000110000000000000110000000000000011000000000000001100000001011000000000001000000000000010010000000000000111100001011000000000000100000000000011100", - encodableArrayOfRanges.encode()); - } - - @Test - public void testEncode5() throws EncodingException { - List value = new ArrayList<>(); - value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); - value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); - value.add(new RangeEntry(5, 2, Arrays.asList(28))); - value.add(new RangeEntry(5, 2, Arrays.asList(29))); - EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2, value); - Assertions.assertEquals("0000000001000001011000000000001100000000000001100000000000000110000000000000011000000010110000000000010000000000000100100000000000001111000010110000000000001000000000000111000001011000000000000100000000000011101", - encodableArrayOfRanges.encode()); - } - - @Test - public void testDecode1() throws DecodingException { - EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2); - encodableArrayOfRanges.decode("000000000000"); - Assertions.assertTrue(encodableArrayOfRanges.getValue().isEmpty()); - } - - @Test - public void testDecode2() throws DecodingException { - EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2); - encodableArrayOfRanges.decode("00000000000100010110000000000011000000000000011000000000000001100000000000000110000"); - Assertions.assertEquals(1, encodableArrayOfRanges.getValue().size()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); - Assertions.assertEquals(Arrays.asList(12, 24, 48), encodableArrayOfRanges.getValue().get(0).getIds()); - } - - @Test - public void testDecode3() throws DecodingException { - EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2); - encodableArrayOfRanges.decode("00000000001000010110000000000011000000000000011000000000000001100000000000000110000000101100000000000100000000000001001000000000000011110"); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().size()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); - Assertions.assertEquals(encodableArrayOfRanges.getValue().get(0).getIds(), Arrays.asList(12, 24, 48)); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(1).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(1).getType()); - Assertions.assertEquals(encodableArrayOfRanges.getValue().get(1).getIds(), Arrays.asList(18, 30)); - } - - @Test - public void testDecode4() throws DecodingException { - EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2); - encodableArrayOfRanges.decode("000000000011000101100000000000110000000000000110000000000000011000000000000001100000001011000000000001000000000000010010000000000000111100001011000000000000100000000000011100"); - Assertions.assertEquals(3, encodableArrayOfRanges.getValue().size()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); - Assertions.assertEquals(encodableArrayOfRanges.getValue().get(0).getIds(), Arrays.asList(12, 24, 48)); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(1).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(1).getType()); - Assertions.assertEquals(encodableArrayOfRanges.getValue().get(1).getIds(), Arrays.asList(18, 30)); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(2).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(2).getType()); - Assertions.assertEquals(encodableArrayOfRanges.getValue().get(2).getIds(), Arrays.asList(28)); - } - - @Test - public void testDecode5() throws DecodingException { - EncodableArrayOfFixedRanges encodableArrayOfRanges = new EncodableArrayOfFixedRanges(6, 2); - encodableArrayOfRanges.decode("0000000001000001011000000000001100000000000001100000000000000110000000000000011000000010110000000000010000000000000100100000000000001111000010110000000000001000000000000111000001011000000000000100000000000011101"); - Assertions.assertEquals(4, encodableArrayOfRanges.getValue().size()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); - Assertions.assertEquals(Arrays.asList(12, 24, 48), encodableArrayOfRanges.getValue().get(0).getIds()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(1).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(1).getType()); - Assertions.assertEquals(Arrays.asList(18, 30), encodableArrayOfRanges.getValue().get(1).getIds()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(2).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(2).getType()); - Assertions.assertEquals(Arrays.asList(28), encodableArrayOfRanges.getValue().get(2).getIds()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(3).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(3).getType()); - Assertions.assertEquals(Arrays.asList(29), encodableArrayOfRanges.getValue().get(3).getIds()); - } - - @Test - public void testSubstring1() throws DecodingException, SubstringException { - Assertions.assertEquals("000000000000", new EncodableArrayOfFixedRanges(6, 2).substring( - "01010100000000000011111111000000000001110000000000000000000000000000001000000000000000000000000000000", 6)); - } - - @Test - public void testSubstring2() throws DecodingException, SubstringException { - Assertions.assertEquals("00000000000111111111000000000001110000000000000000000000000000001", - new EncodableArrayOfFixedRanges(6, 2).substring( - "01010100000000000111111111000000000001110000000000000000000000000000001000000000000000000000000000000", - 6)); - } - - @Test - public void testSubstring3() throws DecodingException, SubstringException { - Assertions.assertEquals("000000000001111111110000000000011101100000000000100000000000011101", - new EncodableArrayOfFixedRanges(6, 2).substring( - "01010100000000000111111111000000000001110110000000000010000000000001110100000000000000000000000000000", - 6)); - } - - @Test - public void testSubstring4() throws DecodingException, SubstringException { - Assertions.assertEquals( - "0000000001000001011100000000001100000000000000001000000000001000000000000000000000001000101110000000000011110000000000000000000100000000000100010111000000000001110000000000000000000000000000001000101110000000000011101100000000000100000000000011101", - new EncodableArrayOfFixedRanges(6, 2).substring( - "0101010000000001000001011100000000001100000000000000001000000000001000000000000000000000001000101110000000000011110000000000000000000100000000000100010111000000000001110000000000000000000000000000001000101110000000000011101100000000000100000000000011101010101", - 6)); - } -} diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRangesTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRangesTest.java deleted file mode 100644 index b53ecf80..00000000 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/datatype/EncodableArrayOfOptimizedRangesTest.java +++ /dev/null @@ -1,158 +0,0 @@ -package com.iab.gpp.encoder.datatype; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import com.iab.gpp.encoder.error.DecodingException; -import com.iab.gpp.encoder.error.EncodingException; - -public class EncodableArrayOfOptimizedRangesTest { - - @Test - public void testEncode1() throws EncodingException { - List value = new ArrayList<>(); - EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2, value); - Assertions.assertEquals("000000000000", - encodableArrayOfRanges.encode()); - } - - @Test - public void testEncode2() throws EncodingException { - List value = new ArrayList<>(); - value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); - EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2, value); - Assertions.assertEquals("0000000000010001011000000000001100000000000000001000000000001000000000000000000000001", - encodableArrayOfRanges.encode()); - } - - @Test - public void testEncode3() throws EncodingException { - List value = new ArrayList<>(); - value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); - value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); - EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2, value); - Assertions.assertEquals("00000000001000010110000000000011000000000000000010000000000010000000000000000000000010001011000000000000111100000000000000000001000000000001", - encodableArrayOfRanges.encode()); - } - - @Test - public void testEncode4() throws EncodingException { - List value = new ArrayList<>(); - value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); - value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); - value.add(new RangeEntry(5, 2, Arrays.asList(28))); - EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2, value); - Assertions.assertEquals("0000000000110001011000000000001100000000000000001000000000001000000000000000000000001000101100000000000011110000000000000000000100000000000100010110000000000001110000000000000000000000000000001", - encodableArrayOfRanges.encode()); - } - - @Test - public void testEncode5() throws EncodingException { - List value = new ArrayList<>(); - value.add(new RangeEntry(5, 2, Arrays.asList(12, 24, 48))); - value.add(new RangeEntry(5, 2, Arrays.asList(18, 30))); - value.add(new RangeEntry(5, 2, Arrays.asList(28))); - value.add(new RangeEntry(5, 2, Arrays.asList(29))); - EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2, value); - Assertions.assertEquals("0000000001000001011000000000001100000000000000001000000000001000000000000000000000001000101100000000000011110000000000000000000100000000000100010110000000000001110000000000000000000000000000001000101100000000000011101100000000000100000000000011101", - encodableArrayOfRanges.encode()); - } - - @Test - public void testDecode1() throws DecodingException { - EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2); - encodableArrayOfRanges.decode("000000000000"); - Assertions.assertTrue(encodableArrayOfRanges.getValue().isEmpty()); - } - - @Test - public void testDecode2() throws DecodingException { - EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2); - encodableArrayOfRanges.decode("0000000000010001011000000000001100000000000000001000000000001000000000000000000000001"); - Assertions.assertEquals(1, encodableArrayOfRanges.getValue().size()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); - Assertions.assertEquals(Arrays.asList(12, 24, 48), encodableArrayOfRanges.getValue().get(0).getIds()); - } - - @Test - public void testDecode3() throws DecodingException { - EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2); - encodableArrayOfRanges.decode("00000000001000010110000000000011000000000000000010000000000010000000000000000000000010001011000000000000111100000000000000000001000000000001"); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().size()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); - Assertions.assertEquals(encodableArrayOfRanges.getValue().get(0).getIds(), Arrays.asList(12, 24, 48)); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(1).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(1).getType()); - Assertions.assertEquals(encodableArrayOfRanges.getValue().get(1).getIds(), Arrays.asList(18, 30)); - } - - @Test - public void testDecode4() throws DecodingException { - EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2); - encodableArrayOfRanges.decode("0000000000110001011000000000001100000000000000001000000000001000000000000000000000001000101100000000000011110000000000000000000100000000000100010110000000000001110000000000000000000000000000001"); - Assertions.assertEquals(3, encodableArrayOfRanges.getValue().size()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); - Assertions.assertEquals(encodableArrayOfRanges.getValue().get(0).getIds(), Arrays.asList(12, 24, 48)); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(1).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(1).getType()); - Assertions.assertEquals(encodableArrayOfRanges.getValue().get(1).getIds(), Arrays.asList(18, 30)); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(2).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(2).getType()); - Assertions.assertEquals(encodableArrayOfRanges.getValue().get(2).getIds(), Arrays.asList(28)); - } - - @Test - public void testDecode5() throws DecodingException { - EncodableArrayOfOptimizedRanges encodableArrayOfRanges = new EncodableArrayOfOptimizedRanges(6, 2); - encodableArrayOfRanges.decode("0000000001000001011000000000001100000000000000001000000000001000000000000000000000001000101100000000000011110000000000000000000100000000000100010110000000000001110000000000000000000000000000001000101100000000000011101100000000000100000000000011101"); - Assertions.assertEquals(4, encodableArrayOfRanges.getValue().size()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(0).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(0).getType()); - Assertions.assertEquals(Arrays.asList(12, 24, 48), encodableArrayOfRanges.getValue().get(0).getIds()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(1).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(1).getType()); - Assertions.assertEquals(Arrays.asList(18, 30), encodableArrayOfRanges.getValue().get(1).getIds()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(2).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(2).getType()); - Assertions.assertEquals(Arrays.asList(28), encodableArrayOfRanges.getValue().get(2).getIds()); - Assertions.assertEquals(5, encodableArrayOfRanges.getValue().get(3).getKey()); - Assertions.assertEquals(2, encodableArrayOfRanges.getValue().get(3).getType()); - Assertions.assertEquals(Arrays.asList(29), encodableArrayOfRanges.getValue().get(3).getIds()); - } - - @Test - public void testSubstring1() throws DecodingException, SubstringException { - Assertions.assertEquals("000000000000", new EncodableArrayOfOptimizedRanges(6, 2).substring( - "01010100000000000011111111000000000001110000000000000000000000000000001000000000000000000000000000000", 6)); - } - - @Test - public void testSubstring2() throws DecodingException, SubstringException { - Assertions.assertEquals("00000000000111111111000000000001110000000000000000000000000000001", - new EncodableArrayOfOptimizedRanges(6, 2).substring( - "01010100000000000111111111000000000001110000000000000000000000000000001000000000000000000000000000000", - 6)); - } - - @Test - public void testSubstring3() throws DecodingException, SubstringException { - Assertions.assertEquals("000000000001111111110000000000011101100000000000100000000000011101", - new EncodableArrayOfOptimizedRanges(6, 2).substring( - "01010100000000000111111111000000000001110110000000000010000000000001110100000000000000000000000000000", - 6)); - } - - @Test - public void testSubstring4() throws DecodingException, SubstringException { - Assertions.assertEquals( - "0000000001000001011100000000001100000000000000001000000000001000000000000000000000001000101110000000000011110000000000000000000100000000000100010111000000000001110000000000000000000000000000001000101110000000000011101100000000000100000000000011101", - new EncodableArrayOfOptimizedRanges(6, 2).substring( - "0101010000000001000001011100000000001100000000000000001000000000001000000000000000000000001000101110000000000011110000000000000000000100000000000100010111000000000001110000000000000000000000000000001000101110000000000011101100000000000100000000000011101010101", - 6)); - } -} diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java index deed8e64..de11c560 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/section/TcfCaV1Test.java @@ -83,7 +83,7 @@ public void testEncode4() throws EncodingException, InvalidFieldException { tcfCaV1.setFieldValue(TcfCaV1Field.CREATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); tcfCaV1.setFieldValue(TcfCaV1Field.LAST_UPDATED, ZonedDateTime.of(2022, 1, 1, 0, 0, 0, 0, ZoneId.of("UTC"))); - Assertions.assertEquals("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAACCgAS7o.YAAAAAAAAAA", tcfCaV1.encode()); + Assertions.assertEquals("BPSG_8APSG_8AAAAAAENAACAAAAAAAAAAAAAAAAACCgBwABAAOAAoADgAJA.YAAAAAAAAAA", tcfCaV1.encode()); } @Test From 7ca0288970d27651e79461020fd500100d1c0df7 Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Sat, 16 Dec 2023 13:54:46 -0700 Subject: [PATCH 33/36] optimize bitstring padding --- .../base64/CompressedBase64UrlEncoder.java | 23 ++++++++++++++----- .../base64/TraditionalBase64UrlEncoder.java | 11 ++++++--- 2 files changed, 25 insertions(+), 9 deletions(-) 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 5cd0970a..4ebd7be7 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,5 +1,7 @@ package com.iab.gpp.encoder.base64; +import java.util.Arrays; + public class CompressedBase64UrlEncoder extends AbstractBase64UrlEncoder { private static CompressedBase64UrlEncoder instance = new CompressedBase64UrlEncoder(); @@ -14,14 +16,23 @@ public static CompressedBase64UrlEncoder getInstance() { @Override protected String pad(String bitString) { - while (bitString.length() % 8 > 0) { - bitString += "0"; + char[] chars1 = null; + if(bitString.length() % 8 > 0) { + chars1 = new char[8 - (bitString.length() % 8)]; + } else { + chars1 = new char[0]; } - while (bitString.length() % 6 > 0) { - bitString += "0"; + 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]; } - - return bitString; + 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 f0d2f9ea..78ffe719 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,5 +1,7 @@ package com.iab.gpp.encoder.base64; +import java.util.Arrays; + public class TraditionalBase64UrlEncoder extends AbstractBase64UrlEncoder { private static TraditionalBase64UrlEncoder instance = new TraditionalBase64UrlEncoder(); @@ -14,10 +16,13 @@ public static TraditionalBase64UrlEncoder getInstance() { @Override protected String pad(String bitString) { - while (bitString.length() % 24 > 0) { - bitString += "0"; + 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; } - return bitString; } } From 254b84437ae939a2d9e37af7313969a0b3c71fbe Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Mon, 22 Jul 2024 00:17:41 -0600 Subject: [PATCH 34/36] Validating first 2 characters of string to avoid OOM --- .../src/main/java/com/iab/gpp/encoder/GppModel.java | 2 +- .../test/java/com/iab/gpp/encoder/GppModelTest.java | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) 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 f4a8bf94..cde071b9 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 @@ -279,7 +279,7 @@ protected String encodeModel(Map sections) { } protected Map decodeModel(String str) { - if(str == null || str.isEmpty() || str.startsWith("D")) { + if(str == null || str.isEmpty() || str.startsWith("DB")) { Map sections = new HashMap<>(); if(str != null && !str.isEmpty()) { diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index 4e1546c5..2049e1ad 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -714,4 +714,16 @@ public void testDecodingEmptyString() { gppModel.setFieldValue("uspv1", UspV1Field.NOTICE, 'Y'); Assertions.assertEquals("DBABTA~1Y--", gppModel.encode()); } + + //java.lang.OutOfMemoryError: Java heap space + @Test + public void testDecodingExceptionValidStringButNotGPP() { + try { + GppModel gppModel = new GppModel("DP48G0AP48G0AEsACCPLAkEgAAAAAEPgAB5YAAAQaQD2F2K2kKFkPCmQWYAQBCijYEAhQAAAAkCBIAAgAUgQAgFIIAgAIFAAAAAAAAAQEgCQAAQABAAAIACgAAAAAAIAAAAAAAQQAAAAAIAAAAAAAAEAAAAAAAQAAAAIAABEhCAAQQAEAAAAAAAQAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAgAA"); + gppModel.getHeader().getName(); + Assertions.fail("Expected LazyDecodingException"); + } catch (DecodingException e) { + + } + } } From 3cfd3df8e89906fa7dea5ea818fae4924fd37e4a Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Mon, 22 Jul 2024 00:49:18 -0600 Subject: [PATCH 35/36] Fail on empty or mismatched sections --- .../java/com/iab/gpp/encoder/GppModel.java | 9 +++++ .../com/iab/gpp/encoder/GppModelTest.java | 36 +++++++++++++------ 2 files changed, 34 insertions(+), 11 deletions(-) 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 cde071b9..5af51ddc 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 @@ -289,7 +289,16 @@ protected Map decodeModel(String str) { @SuppressWarnings("unchecked") List sectionIds = (List) header.getFieldValue("SectionIds"); + + if(sectionIds.size() != encodedSections.length-1) { + throw new DecodingException("Unable to decode '" + str + "'. The number of sections does not match the number of sections defined in the header."); + } + for (int i = 0; i < sectionIds.size(); i++) { + String encodedSection = encodedSections[i + 1]; + if(encodedSection.trim().isEmpty()) { + throw new DecodingException("Unable to decode '" + str + "'. Section " + (i+1) + " is blank."); + } if (sectionIds.get(i).equals(TcfEuV2.ID)) { TcfEuV2 section = new TcfEuV2(encodedSections[i + 1]); sections.put(TcfEuV2.NAME, section); diff --git a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java index 2049e1ad..9f9bb3c9 100644 --- a/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java +++ b/iabgpp-encoder/src/test/java/com/iab/gpp/encoder/GppModelTest.java @@ -715,15 +715,29 @@ public void testDecodingEmptyString() { Assertions.assertEquals("DBABTA~1Y--", gppModel.encode()); } - //java.lang.OutOfMemoryError: Java heap space - @Test - public void testDecodingExceptionValidStringButNotGPP() { - try { - GppModel gppModel = new GppModel("DP48G0AP48G0AEsACCPLAkEgAAAAAEPgAB5YAAAQaQD2F2K2kKFkPCmQWYAQBCijYEAhQAAAAkCBIAAgAUgQAgFIIAgAIFAAAAAAAAAQEgCQAAQABAAAIACgAAAAAAIAAAAAAAQQAAAAAIAAAAAAAAEAAAAAAAQAAAAIAABEhCAAQQAEAAAAAAAQAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAgAA"); - gppModel.getHeader().getName(); - Assertions.fail("Expected LazyDecodingException"); - } catch (DecodingException e) { - - } - } + @Test + public void testMismatchedSections() { + try { + GppModel gppModel = new GppModel("DBACOeA~CPSG_8APSG_8ANwAAAENAwCAAAAAAAAAAAAAAAAAAAAA.QAAA.IAAA~BPSG_8APSG_8AAyACAENGdCgf_gfgAfgfgBgABABAAABAB4AACACAAA.fHHHA4444ao"); + gppModel.getHeader().getSectionsIds(); + Assertions.fail("Expected DecodingException"); + } catch (DecodingException e) { + + } catch (Exception e) { + Assertions.fail("Expected DecodingException"); + } + } + + @Test + public void testEmptySections() { + try { + GppModel gppModel = new GppModel("DBACOeA~~1YNN"); + gppModel.getHeader().getSectionsIds(); + Assertions.fail("Expected DecodingException"); + } catch (DecodingException e) { + + } catch (Exception e) { + Assertions.fail("Expected DecodingException"); + } + } } From 94cce758ed59d5235265db994a7f3496ac3c86cf Mon Sep 17 00:00:00 2001 From: Chad Huff Date: Mon, 22 Jul 2024 01:10:01 -0600 Subject: [PATCH 36/36] minor cleanup --- .../java/com/iab/gpp/encoder/GppModel.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) 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 5af51ddc..b447d3a7 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 @@ -300,31 +300,31 @@ protected Map decodeModel(String str) { throw new DecodingException("Unable to decode '" + str + "'. Section " + (i+1) + " is blank."); } if (sectionIds.get(i).equals(TcfEuV2.ID)) { - TcfEuV2 section = new TcfEuV2(encodedSections[i + 1]); + TcfEuV2 section = new TcfEuV2(encodedSection); sections.put(TcfEuV2.NAME, section); } else if (sectionIds.get(i).equals(TcfCaV1.ID)) { - TcfCaV1 section = new TcfCaV1(encodedSections[i + 1]); + TcfCaV1 section = new TcfCaV1(encodedSection); sections.put(TcfCaV1.NAME, section); } else if (sectionIds.get(i).equals(UspV1.ID)) { - UspV1 section = new UspV1(encodedSections[i + 1]); + UspV1 section = new UspV1(encodedSection); sections.put(UspV1.NAME, section); } else if (sectionIds.get(i).equals(UsCaV1.ID)) { - UsCaV1 section = new UsCaV1(encodedSections[i + 1]); + UsCaV1 section = new UsCaV1(encodedSection); sections.put(UsCaV1.NAME, section); } else if (sectionIds.get(i).equals(UsNatV1.ID)) { - UsNatV1 section = new UsNatV1(encodedSections[i + 1]); + UsNatV1 section = new UsNatV1(encodedSection); sections.put(UsNatV1.NAME, section); } else if (sectionIds.get(i).equals(UsVaV1.ID)) { - UsVaV1 section = new UsVaV1(encodedSections[i + 1]); + UsVaV1 section = new UsVaV1(encodedSection); sections.put(UsVaV1.NAME, section); } else if (sectionIds.get(i).equals(UsCoV1.ID)) { - UsCoV1 section = new UsCoV1(encodedSections[i + 1]); + UsCoV1 section = new UsCoV1(encodedSection); sections.put(UsCoV1.NAME, section); } else if (sectionIds.get(i).equals(UsUtV1.ID)) { - UsUtV1 section = new UsUtV1(encodedSections[i + 1]); + UsUtV1 section = new UsUtV1(encodedSection); sections.put(UsUtV1.NAME, section); } else if (sectionIds.get(i).equals(UsCtV1.ID)) { - UsCtV1 section = new UsCtV1(encodedSections[i + 1]); + UsCtV1 section = new UsCtV1(encodedSection); sections.put(UsCtV1.NAME, section); } }