Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions openpdf-core/src/main/java/org/openpdf/text/pdf/PdfBatchUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -223,18 +223,38 @@
/** Quick permissions helper. */
public static int perms(boolean print, boolean modify, boolean copy, boolean annotate) {
int p = 0;
if (print) p |= PdfWriter.ALLOW_PRINTING;
if (modify) p |= PdfWriter.ALLOW_MODIFY_CONTENTS;
if (copy) p |= PdfWriter.ALLOW_COPY;
if (annotate) p |= PdfWriter.ALLOW_MODIFY_ANNOTATIONS;
if (print) {
p |= PdfWriter.ALLOW_PRINTING;
}
if (modify) {
p |= PdfWriter.ALLOW_MODIFY_CONTENTS;
}
if (copy) {
p |= PdfWriter.ALLOW_COPY;
}
if (annotate) {
p |= PdfWriter.ALLOW_MODIFY_ANNOTATIONS;
}
return p;
}

/** AES 128 vs 256 convenience. */
public static int aes128() { return PdfWriter.ENCRYPTION_AES_128; }
public static int aes256() { return PdfWriter.ENCRYPTION_AES_256_V3; }
public static int aes128() {
return PdfWriter.ENCRYPTION_AES_128;
}

public static int aes256() {
return PdfWriter.ENCRYPTION_AES_256_V3;
}

/** Small utility for closing Closeables, ignoring exceptions. */
private static void closeQuietly(Closeable c) { try { if (c != null) c.close(); } catch (Exception ignored) {} }
private static void closeQuietly(Closeable c) {

Check warning on line 251 in openpdf-core/src/main/java/org/openpdf/text/pdf/PdfBatchUtils.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this unused private "closeQuietly" method.

See more on https://sonarcloud.io/project/issues?id=LibrePDF_OpenPDF&issues=AZ0lrY-CdRIchpXbp8xG&open=AZ0lrY-CdRIchpXbp8xG&pullRequest=1522

Check notice on line 251 in openpdf-core/src/main/java/org/openpdf/text/pdf/PdfBatchUtils.java

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

openpdf-core/src/main/java/org/openpdf/text/pdf/PdfBatchUtils.java#L251

Avoid unused private methods such as 'closeQuietly(Closeable)'.
try {
if (c != null) {
c.close();
}
} catch (Exception ignored) {

Check warning on line 256 in openpdf-core/src/main/java/org/openpdf/text/pdf/PdfBatchUtils.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this block of code, fill it in, or add a comment explaining why it is empty.

See more on https://sonarcloud.io/project/issues?id=LibrePDF_OpenPDF&issues=AZ0lrY-CdRIchpXbp8xH&open=AZ0lrY-CdRIchpXbp8xH&pullRequest=1522
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ public int comparePdfVersions(String v1, String v2) {
int minor2 = (p2.length > 1) ? Integer.parseInt(p2[1]) : 0;
return Integer.compare(minor1, minor2);
}

/**
* @see org.openpdf.text.pdf.interfaces.PdfVersion#setPdfVersion(org.openpdf.text.pdf.PdfName)
*/
Expand Down
37 changes: 28 additions & 9 deletions openpdf-core/src/main/java/org/openpdf/text/utils/PdfBatch.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,64 @@
* Utility class for executing collections of tasks concurrently using Java 21 virtual threads.
*/
public final class PdfBatch {

private PdfBatch() {}

public static final class BatchResult<T> {
public final List<T> successes = new ArrayList<>();
public final List<Throwable> failures = new ArrayList<>();
public boolean isAllSuccessful() { return failures.isEmpty(); }
public int total() { return successes.size() + failures.size(); }
@Override public String toString() {

public boolean isAllSuccessful() {
return failures.isEmpty();
}

public int total() {
return successes.size() + failures.size();
}

@Override
public String toString() {
return "BatchResult{" +
"successes=" + successes.size() +
", failures=" + failures.size() +
", total=" + total() +
'}';
} }
}
}

public static <T> BatchResult<T> run(Collection<? extends Callable<T>> tasks,
Consumer<T> onSuccess,
Consumer<Throwable> onFailure) {
Objects.requireNonNull(tasks, "tasks");
var result = new BatchResult<T>();
if (tasks.isEmpty()) return result;
if (tasks.isEmpty()) {
return result;
}

try (ExecutorService exec = Executors.newVirtualThreadPerTaskExecutor()) {
List<Future<T>> futures = tasks.stream().map(exec::submit).toList();
for (Future<T> f : futures) {
try {
T v = f.get();
result.successes.add(v);
if (onSuccess != null) onSuccess.accept(v);
if (onSuccess != null) {
onSuccess.accept(v);
}
} catch (ExecutionException ee) {
Throwable cause = ee.getCause() != null ? ee.getCause() : ee;
result.failures.add(cause);
if (onFailure != null) onFailure.accept(cause);
if (onFailure != null) {
onFailure.accept(cause);
}
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
result.failures.add(ie);
if (onFailure != null) onFailure.accept(ie);
if (onFailure != null) {
onFailure.accept(ie);
}
}
}
}
return result;

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ class OpenPdfVersionTest {

private static Set<String> buildSupportedVersions() {
Set<String> s = new LinkedHashSet<>();
for (int i = 0; i <= 7; i++) s.add("1." + i);
for (int i = 0; i <= 7; i++) {
s.add("1." + i);
}
s.add("2.0");
return s;
}
Expand Down Expand Up @@ -75,7 +77,7 @@ void createDefaultPdfIs20(@TempDir Path tmp) throws Exception {
}

@ParameterizedTest(name = "Create + round-trip version {0} (memory and file)")
@ValueSource(strings = {"1.2","1.3","1.4","1.5","1.6","1.7","2.0"})
@ValueSource(strings = {"1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "2.0"})
void createAndRoundTripSpecificVersions(String version, @TempDir Path tmp) throws Exception {
// In-memory
byte[] bytes = createPdfToBytes(version);
Expand Down Expand Up @@ -257,7 +259,9 @@ private static String getVersionFromReaderNormalized(PdfReader reader) {
// Common in OpenPDF: getPdfVersion() returns char or String
Method m = reader.getClass().getMethod("getPdfVersion");
Object v = m.invoke(reader);
if (v == null) return null;
if (v == null) {
return null;
}
if (v instanceof Character) {
char c = (Character) v;
if (Character.isDigit(c)) {
Expand All @@ -274,7 +278,9 @@ private static String getVersionFromReaderNormalized(PdfReader reader) {
try {
Method m2 = reader.getClass().getMethod("getHeaderVersion");
Object v2 = m2.invoke(reader);
if (v2 instanceof String) return (String) v2;
if (v2 instanceof String) {
return (String) v2;
}
} catch (Exception ignored2) {
// no suitable method
}
Expand Down Expand Up @@ -312,12 +318,16 @@ private static String extractHeaderVersion(byte[] pdfBytes) {
int len = Math.min(pdfBytes.length, 4096);
String header = new String(pdfBytes, 0, len, StandardCharsets.ISO_8859_1);
int idx = header.indexOf("%PDF-");
if (idx < 0) throw new IllegalStateException("PDF header not found");
if (idx < 0) {
throw new IllegalStateException("PDF header not found");
}
int start = idx + 5;
int end = start;
while (end < header.length()) {
char c = header.charAt(end);
if (!Character.isDigit(c) && c != '.') break;
if (!Character.isDigit(c) && c != '.') {
break;
}
end++;
}
return header.substring(start, end);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,15 @@ private static String extractHeaderVersion(byte[] pdfBytes) {
int len = Math.min(pdfBytes.length, 4096);
String header = new String(pdfBytes, 0, len, StandardCharsets.ISO_8859_1);
int idx = header.indexOf("%PDF-");
if (idx < 0) throw new IllegalStateException("PDF header not found");
if (idx < 0) {
throw new IllegalStateException("PDF header not found");
}
int start = idx + 5, end = start;
while (end < header.length()) {
char c = header.charAt(end);
if (!Character.isDigit(c) && c != '.') break;
if (!Character.isDigit(c) && c != '.') {
break;
}
end++;
}
return header.substring(start, end);
Expand All @@ -127,13 +131,19 @@ private static String getVersionFromReaderNormalized(PdfReader reader) {
try {
Method m = reader.getClass().getMethod("getPdfVersion");
Object v = m.invoke(reader);
if (v == null) return null;
if (v == null) {
return null;
}
if (v instanceof Character) {
char c = (Character) v;
if (Character.isDigit(c)) return "1." + c;
if (Character.isDigit(c)) {
return "1." + c;
}
return String.valueOf(c);
}
if (v instanceof String) return (String) v;
if (v instanceof String) {
return (String) v;
}
} catch (NoSuchMethodException ignored) {
// Older/newer forks may differ; ignore gracefully.
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ class Pdf20ExamplesConformanceTest {

// Override with -Dopenpdf.pdf20.dir=/absolute/path if needed
private static final Path DIR = Path.of(System.getProperty("openpdf.pdf20.dir", "src/test/resources/pdf-2-0"));
private static Path f(String name) { return DIR.resolve(name); }

private static Path f(String name) {
return DIR.resolve(name);
}

// ---------- Simple PDF 2.0 file ----------

Expand Down Expand Up @@ -67,7 +70,9 @@ void testUtf8Annotation() throws Exception {

for (int i = 0; i < annots.size(); i++) {
PdfDictionary a = (PdfDictionary) PdfReader.getPdfObject(annots.getAsIndirectObject(i));
if (a == null) continue;
if (a == null) {
continue;
}
PdfString contents = a.getAsString(PdfName.CONTENTS);
if (contents != null) {
String s = contents.toUnicodeString();
Expand Down Expand Up @@ -124,22 +129,31 @@ void testPageLevelOutputIntent() throws Exception {
// ================= helpers =================

private static class Header {
final int offset; final String version;
Header(int o, String v) { offset = o; version = v; }
final int offset;
final String version;

Header(int o, String v) {
offset = o;
version = v;
}
}

/** Find the first %PDF- header anywhere and parse its version. */
private static Header firstHeader(byte[] bytes) {
int idx = indexOfAscii(bytes, "%PDF-");
if (idx < 0) return null;
if (idx < 0) {
return null;
}
String ver = parseHeaderVersion(bytes, idx);
return new Header(idx, ver);
}

/** True if the file contains a %PDF-x.y header with the given version anywhere. */
private static boolean containsHeaderVersion(byte[] bytes, String wanted) {
for (Header h : allHeaders(bytes)) {
if (wanted.equals(h.version)) return true;
if (wanted.equals(h.version)) {
return true;
}
}
return false;
}
Expand All @@ -151,7 +165,9 @@ private static List<Header> allHeaders(byte[] bytes) {
byte[] pat = "%PDF-".getBytes(StandardCharsets.ISO_8859_1);
while (true) {
int idx = indexOf(bytes, pat, from);
if (idx < 0) break;
if (idx < 0) {
break;
}
String ver = parseHeaderVersion(bytes, idx);
list.add(new Header(idx, ver));
from = idx + pat.length;
Expand All @@ -165,7 +181,9 @@ private static String parseHeaderVersion(byte[] bytes, int headerIdx) {
int end = start;
while (end < bytes.length) {
char c = (char) (bytes[end] & 0xFF);
if (!Character.isDigit(c) && c != '.') break;
if (!Character.isDigit(c) && c != '.') {
break;
}
end++;
}
return new String(bytes, start, end - start, StandardCharsets.ISO_8859_1);
Expand All @@ -188,7 +206,9 @@ private static int indexOfAscii(byte[] bytes, String token) {
private static int indexOf(byte[] hay, byte[] needle, int from) {
outer: for (int i = from; i <= hay.length - needle.length; i++) {
for (int j = 0; j < needle.length; j++) {
if (hay[i + j] != needle[j]) continue outer;
if (hay[i + j] != needle[j]) {
continue outer;
}
}
return i;
}
Expand Down
Loading