-
Notifications
You must be signed in to change notification settings - Fork 18
Add isEquivalentTo method to COSBase and COSObject #712
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: integration
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -299,6 +299,70 @@ public Collection<COSObject> getValues() { | |
| return this.entries.values(); | ||
| } | ||
|
|
||
| private Set<ASAtom> getNonNullKeySet() { | ||
| Set<ASAtom> nonNullKeys = new HashSet<>(); | ||
| for (ASAtom key : getKeySet()) { | ||
| COSBase value = getKey(key).get(); // assume getKey returns a COSBase wrapper | ||
| if (value != null) { | ||
| nonNullKeys.add(key); | ||
| } | ||
| } | ||
| return nonNullKeys; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isEquivalentTo(Object o) { | ||
| if (this == o) return true; | ||
| if (o == null) return false; | ||
| if (o instanceof COSObject) { | ||
| return this.isEquivalentTo(((COSObject) o).get()); | ||
| } | ||
| if (!(o instanceof COSDictionary)) return false; | ||
|
|
||
| List<COSBasePair> checkedObjects = new LinkedList<>(); | ||
| return isEquivalentTo(o, checkedObjects); | ||
| } | ||
|
|
||
| /** | ||
| * Internal recursive comparison with cycle detection. | ||
| */ | ||
| boolean isEquivalentTo(Object o, List<COSBasePair> checkedObjects) { | ||
| if (this == o) return true; | ||
| if (o == null) return false; | ||
| if (o instanceof COSObject) { | ||
| return this.isEquivalentTo(((COSObject) o).get(), checkedObjects); | ||
| } | ||
| if (!(o instanceof COSDictionary)) return false; | ||
|
Comment on lines
+313
to
+335
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Confirm COSStream's superclass
rg -n 'class COSStream' -A2 --type=javaRepository: veraPDF/veraPDF-parser Length of output: 160 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf 'Java files named COS*.java:\n'
fd '^COS.*\.java$' . || true
printf '\nSearch symbols:\n'
rg -n 'class COSStream|COSClassCOSStream|class COSDictionary|isEquivalentTo|function equivalent|byteContent|COSStream' -S --type=java . || trueRepository: veraPDF/veraPDF-parser Length of output: 25872 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf 'COSDictionary isEquivalentTo and equals:\n'
sed -n '310,420p' src/main/java/org/verapdf/cos/COSDictionary.java | cat -n
printf '\nCOSStream isEquivalentTo and equals:\n'
sed -n '290,415p' src/main/java/org/verapdf/cos/COSStream.java | cat -n
printf '\nCOSDirect and COSBase relevant data members:\n'
sed -n '1,120p' src/main/java/org/verapdf/cos/COSDirect.java | cat -n
sed -n '260,315p' src/main/java/org/verapdf/cos/COSDirect.java | cat -nRepository: veraPDF/veraPDF-parser Length of output: 15896 Reject
🤖 Prompt for AI Agents |
||
|
|
||
| COSDictionary that = (COSDictionary) o; | ||
|
|
||
| if (COSBasePair.listContainsPair(checkedObjects, this, that)) { | ||
| return true; | ||
| } | ||
| COSBasePair.addPairToList(checkedObjects, this, that); | ||
|
|
||
| Set<ASAtom> thisKeys = this.getNonNullKeySet(); | ||
| Set<ASAtom> thatKeys = that.getNonNullKeySet(); | ||
|
|
||
| if (!thisKeys.equals(thatKeys)) { | ||
| return false; | ||
| } | ||
|
|
||
| for (ASAtom key : thisKeys) { | ||
| COSBase thisVal = this.getKey(key).get(); | ||
| COSBase thatVal = that.getKey(key).get(); | ||
|
|
||
| if (thisVal == null && thatVal == null) continue; | ||
| if (thisVal == null || thatVal == null) return false; | ||
|
|
||
| if (!thisVal.isEquivalentTo(thatVal, checkedObjects)) { | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object obj) { | ||
| if (this == obj) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,6 +25,7 @@ | |
| import org.verapdf.cos.visitor.IVisitor; | ||
|
|
||
| import java.nio.charset.StandardCharsets; | ||
| import java.util.Arrays; | ||
| import java.util.Objects; | ||
|
|
||
| /** | ||
|
|
@@ -91,6 +92,19 @@ public boolean setName(final ASAtom value) { | |
| return true; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isEquivalentTo(Object o) { | ||
| if (this == o) return true; | ||
| if (!(o instanceof COSName)) return false; | ||
|
|
||
| COSName that = (COSName) o; | ||
|
|
||
| byte[] thisBytes = this.getName().getValue().getBytes(StandardCharsets.ISO_8859_1); | ||
| byte[] thatBytes = that.getName().getValue().getBytes(StandardCharsets.ISO_8859_1); | ||
|
|
||
| return Arrays.equals(thisBytes, thatBytes); | ||
| } | ||
|
|
||
|
Comment on lines
+95
to
+107
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win Handle null
🧰 Tools🪛 ast-grep (0.45.0)[warning] 101-101: Use a randomly-generated IV (random-iv) [warning] 102-102: Use a randomly-generated IV (random-iv) 🤖 Prompt for AI Agents |
||
| public ASAtom get() { | ||
| return value; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -494,6 +494,19 @@ public void setIsHeaderFormatComplyPDFA(Boolean isHeaderFormatComplyPDFA) { | |
| this.isHeaderFormatComplyPDFA = isHeaderFormatComplyPDFA; | ||
| } | ||
|
|
||
| public boolean isEquivalentTo(Object o) { | ||
| if (o == this) return true; | ||
| if (o instanceof COSObject) { | ||
| COSObject cosObject = (COSObject) o; | ||
| return base.isEquivalentTo(cosObject.base); | ||
| } | ||
|
|
||
| if (o instanceof COSIndirect) { | ||
| return base.isEquivalentTo(((COSIndirect) o).getDirect().base); | ||
|
Comment on lines
+497
to
+505
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win Define behavior for empty and unresolved wrappers before dereferencing. Both implementations assume a non-null underlying object, but the surrounding APIs permit empty COSObjects and nullable indirect children.
📍 Affects 2 files
🤖 Prompt for AI Agents |
||
| } | ||
| return false; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ | |
| import org.verapdf.cos.visitor.ICOSVisitor; | ||
| import org.verapdf.cos.visitor.IVisitor; | ||
|
|
||
| import java.math.BigDecimal; | ||
| import java.text.DecimalFormat; | ||
| import java.text.DecimalFormatSymbols; | ||
|
|
||
|
|
@@ -45,6 +46,11 @@ public class COSReal extends COSNumber { | |
| protected COSReal() { | ||
| } | ||
|
|
||
| @Override | ||
| public BigDecimal getDecimalValue() { | ||
| return BigDecimal.valueOf(value); | ||
| } | ||
|
Comment on lines
+49
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
printf 'Files:\n'
fd -a 'COSReal.java|COSInteger.java' .
printf '\nCOSReal outline:\n'
ast-grep outline src/main/java/org/verapdf/cos/COSReal.java || true
printf '\nCOSInteger outline:\n'
ast-grep outline src/main/java/org/verapdf/cos/COSInteger.java || true
printf '\nRelevant code snippets:\n'
sed -n '1,140p' src/main/java/org/verapdf/cos/COSReal.java
printf '\n---\n'
sed -n '1,125p' src/main/java/org/verapdf/cos/COSInteger.java
printf '\nSearch for COSReal/COSInteger creation and getDecimalValue usage:\n'
rg -n "new COSReal|COSReal\.|getDecimalValue|compareTo.*getDecimalValue" src/main/java/org/verapdf/cos src/main/java -g '*.java' | head -200
printf '\nJava BigDecimal.valueOf behavior probe:\n'
python3 - <<'PY'
import math
values = [float('nan'), float('inf'), float('-inf'), 42.0]
for v in values:
try:
print(f"{v}: finite={math.isfinite(v)}")
print(f" Double.toString={float_repr(v)}")
except NameError as e:
print(f"{v}: finite={math.isfinite(v)}")
PY
printf '\nBehavior note: BigDecimal.valueOf(float/double) rejects NaN/infinity via Double.toString.\n'Repository: veraPDF/veraPDF-parser Length of output: 14662 🏁 Script executed: #!/bin/bash
set -euo pipefail
provider=$(mvn help:evaluate -Dexpression=project.properties.pdfbox-provider -q -DforceStdout 2>/dev/null || true)
if [ -n "$provider" ]; then
echo "current pdfbox-provider=${provider}"
else
echo "pdfbox-provider not available"
fi
# Read the parser/token code around real-number construction without running repo code.
printf '\nPDFStreamParser token.real context:\n'
sed -n '120,190p' src/main/java/org/verapdf/parser/PDFStreamParser.java
printf '\nPostscript operators around division/log/sqrt context:\n'
sed -n '360,505p' src/main/java/org/verapdf/parser/postscript/PSOperator.java
printf '\nPDFStreamParser number token pattern references:\n'
rg -n "real|NUMBER|Double\\.|parseFloat" src/main/java/org/verapdf/parser src/main/java/org/verapdf/pd/function src/main/java/org/verapdf/pd/colors -g '*.java' | head -120Repository: veraPDF/veraPDF-parser Length of output: 11491 🌐 Web query:
💡 Result: In Java, the Citations:
Prevent finite-only real values from being exposed through BigDecimal conversion.
📍 Affects 2 files
🤖 Prompt for AI Agents |
||
|
|
||
| protected COSReal(final double value) { | ||
| this.value = value; | ||
| } | ||
|
|
@@ -88,6 +94,23 @@ public boolean setReal(final double value) { | |
| return true; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isEquivalentTo(Object o) { | ||
| if (this == o) return true; | ||
|
|
||
| if (o instanceof COSReal) { | ||
| COSReal thatReal = (COSReal) o; | ||
| return this.getDecimalValue().compareTo(thatReal.getDecimalValue()) == 0; | ||
| } | ||
|
|
||
| if (o instanceof COSInteger) { | ||
| COSInteger thatInt = (COSInteger) o; | ||
| return this.getDecimalValue().compareTo(thatInt.getDecimalValue()) == 0; | ||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| public double get() { | ||
| return this.value; | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🩺 Stability & Availability | 🔴 Critical | 🏗️ Heavy lift
Preserve cycle-detection state across indirect dispatch.
The list-aware recursive callers pass
checkedObjects, but the default and indirect implementations fall back to one-argument methods and restart traversal.src/main/java/org/verapdf/cos/COSBase.java#L145-L147: do not discard the supplied list for recursive types.src/main/java/org/verapdf/cos/COSIndirect.java#L483-L486: propagate the list when comparing indirect targets.src/main/java/org/verapdf/cos/COSIndirect.java#L492-L497: propagate the list when comparing an indirect target with a COSObject.📍 Affects 2 files
src/main/java/org/verapdf/cos/COSBase.java#L145-L147(this comment)src/main/java/org/verapdf/cos/COSIndirect.java#L483-L486src/main/java/org/verapdf/cos/COSIndirect.java#L492-L497🤖 Prompt for AI Agents