Skip to content
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

Number fxes #898

Merged
merged 15 commits into from
Mar 10, 2024
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ plugins {
import com.github.jk1.license.render.*

group = 'stirling.software'
version = '0.22.1'

version = '0.22.2'
sourceCompatibility = '17'

repositories {
Expand Down Expand Up @@ -158,6 +159,8 @@ dependencies {
// https://mvnrepository.com/artifact/com.github.vladimir-bukhtoyarov/bucket4j-core
implementation 'com.github.vladimir-bukhtoyarov:bucket4j-core:7.6.0'

implementation 'com.fathzer:javaluator:3.0.3'

developmentOnly("org.springframework.boot:spring-boot-devtools:3.2.2")
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.28'
Expand Down
4 changes: 2 additions & 2 deletions scripts/download-security-jar.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ if [ "$DOCKER_ENABLE_SECURITY" = "true" ] && [ "$VERSION_TAG" != "alpha" ]; then
if [ $? -eq 0 ]; then # checks if curl was successful
rm -f app.jar
ln -s app-security.jar app.jar
chown stirlingpdfuser:stirlingpdfgroup app.jar
chmod 755 app.jar
chown stirlingpdfuser:stirlingpdfgroup app.jar || true
chmod 755 app.jar || true
fi
fi
fi
10 changes: 5 additions & 5 deletions scripts/init-without-ocr.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

# Update the user and group IDs as per environment variables
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
usermod -o -u "$PUID" stirlingpdfuser
usermod -o -u "$PUID" stirlingpdfuser || true
fi

if [ ! -z "$PGID" ] && [ "$PGID" != "$(getent group stirlingpdfgroup | cut -d: -f3)" ]; then
groupmod -o -g "$PGID" stirlingpdfgroup
groupmod -o -g "$PGID" stirlingpdfgroup || true
fi
umask "$UMASK"
umask "$UMASK" || true

echo "Setting permissions and ownership for necessary directories..."
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
if [[ "$INSTALL_BOOK_AND_ADVANCED_HTML_OPS" == "true" ]]; then
apk add --no-cache calibre@testing
fi
Expand Down
10 changes: 5 additions & 5 deletions scripts/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,18 @@ fi

# Update the user and group IDs as per environment variables
if [ ! -z "$PUID" ] && [ "$PUID" != "$(id -u stirlingpdfuser)" ]; then
usermod -o -u "$PUID" stirlingpdfuser
usermod -o -u "$PUID" stirlingpdfuser || true
fi


if [ ! -z "$PGID" ] && [ "$PGID" != "$(getent group stirlingpdfgroup | cut -d: -f3)" ]; then
groupmod -o -g "$PGID" stirlingpdfgroup
groupmod -o -g "$PGID" stirlingpdfgroup || true
fi
umask "$UMASK"
umask "$UMASK" || true

echo "Setting permissions and ownership for necessary directories..."
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar
chown -R stirlingpdfuser:stirlingpdfgroup $HOME /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true
chmod -R 755 /logs /scripts /usr/share/fonts/opentype/noto /usr/share/tessdata /configs /customFiles /pipeline /app.jar || true



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public ResponseEntity<byte[]> deletePages(@ModelAttribute PDFWithPageNums reques
String[] pageOrderArr = pagesToDelete.split(",");

List<Integer> pagesToRemove =
GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages(), true);
GeneralUtils.parsePageList(pageOrderArr, document.getNumberOfPages(), false);

Collections.sort(pagesToRemove);

Expand Down Expand Up @@ -195,7 +195,7 @@ public ResponseEntity<byte[]> rearrangePages(@ModelAttribute RearrangePagesReque
if (sortType != null && sortType.length() > 0) {
newPageOrder = processSortTypes(sortType, totalPages);
} else {
newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages, true);
newPageOrder = GeneralUtils.parsePageList(pageOrderArr, totalPages, false);
}
logger.info("newPageOrder = " + newPageOrder);
logger.info("totalPages = " + totalPages);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@ public ResponseEntity<byte[]> splitPdf(@ModelAttribute PDFWithPageNums request)
// open the pdf document

PDDocument document = Loader.loadPDF(file.getBytes());

List<Integer> pageNumbers = request.getPageNumbersList(document, true);
if (!pageNumbers.contains(document.getNumberOfPages() - 1)) {
int totalPages = document.getNumberOfPages();
List<Integer> pageNumbers = request.getPageNumbersList(document, false);
System.out.println(
pageNumbers.stream().map(String::valueOf).collect(Collectors.joining(",")));
if (!pageNumbers.contains(totalPages - 1)) {
// Create a mutable ArrayList so we can add to it
pageNumbers = new ArrayList<>(pageNumbers);
pageNumbers.add(document.getNumberOfPages() - 1);
pageNumbers.add(totalPages - 1);
}

logger.info(
Expand All @@ -69,7 +71,7 @@ public ResponseEntity<byte[]> splitPdf(@ModelAttribute PDFWithPageNums request)
for (int i = previousPageNumber; i <= splitPoint; i++) {
PDPage page = document.getPage(i);
splitDocument.addPage(page);
logger.debug("Adding page {} to split document", i);
logger.info("Adding page {} to split document", i);
}
previousPageNumber = splitPoint + 1;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public ResponseEntity<byte[]> addStamp(@ModelAttribute AddStampRequest request)
// Load the input PDF
PDDocument document = Loader.loadPDF(pdfFile.getBytes());

List<Integer> pageNumbers = request.getPageNumbersList(document, false);
List<Integer> pageNumbers = request.getPageNumbersList(document, true);

for (int pageIndex : pageNumbers) {
int zeroBasedIndex = pageIndex - 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ public List<Integer> getPageNumbersList(boolean zeroCount) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return GeneralUtils.parsePageString(pageNumbers, pageCount, zeroCount);
return GeneralUtils.parsePageList(pageNumbers, pageCount, zeroCount);
}

@Hidden
public List<Integer> getPageNumbersList(PDDocument doc, boolean zeroCount) {
int pageCount = 0;
pageCount = doc.getNumberOfPages();
return GeneralUtils.parsePageString(pageNumbers, pageCount, zeroCount);
return GeneralUtils.parsePageList(pageNumbers, pageCount, zeroCount);
}
}
164 changes: 94 additions & 70 deletions src/main/java/stirling/software/SPDF/utils/GeneralUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.web.multipart.MultipartFile;

import com.fathzer.soft.javaluator.DoubleEvaluator;

import io.github.pixee.security.HostValidator;
import io.github.pixee.security.Urls;

Expand Down Expand Up @@ -115,91 +116,114 @@ public static Long convertSizeToBytes(String sizeStr) {
return null;
}

public static List<Integer> parsePageString(String pageOrder, int totalPages) {
return parsePageString(pageOrder, totalPages, false);
}

public static List<Integer> parsePageString(
String pageOrder, int totalPages, boolean isOneBased) {
if (pageOrder == null || pageOrder.isEmpty()) {
return Collections.singletonList(1);
public static List<Integer> parsePageList(String pages, int totalPages, boolean oneBased) {
if (pages == null) {
return List.of(1); // Default to first page if input is null
}
if (pageOrder.matches("\\d+")) {
// Convert the single number string to an integer and return it in a list
return Collections.singletonList(Integer.parseInt(pageOrder));
try {
return parsePageList(pages.split(","), totalPages, oneBased);
} catch (NumberFormatException e) {
return List.of(1); // Default to first page if input is invalid
}
return parsePageList(pageOrder.split(","), totalPages, isOneBased);
}

public static List<Integer> parsePageList(String[] pageOrderArr, int totalPages) {
return parsePageList(pageOrderArr, totalPages, false);
public static List<Integer> parsePageList(String[] pages, int totalPages) {
return parsePageList(pages, totalPages, false);
}

public static List<Integer> parsePageList(
String[] pageOrderArr, int totalPages, boolean isOneBased) {
List<Integer> newPageOrder = new ArrayList<>();

int adjustmentFactor = isOneBased ? 1 : 0;

// loop through the page order array
for (String element : pageOrderArr) {
if ("all".equalsIgnoreCase(element)) {
public static List<Integer> parsePageList(String[] pages, int totalPages, boolean oneBased) {
List<Integer> result = new ArrayList<>();
int offset = oneBased ? 1 : 0;
for (String page : pages) {
if ("all".equalsIgnoreCase(page)) {
for (int i = 0; i < totalPages; i++) {
newPageOrder.add(i + adjustmentFactor);
result.add(i + offset);
}
// As all pages are already added, no need to check further
break;
} else if (element.matches("\\d*n\\+?-?\\d*|\\d*\\+?n")) {
// Handle page order as a function
int coefficient = 0;
int constant = 0;
boolean coefficientExists = false;
boolean constantExists = false;

if (element.contains("n")) {
String[] parts = element.split("n");
if (!"".equals(parts[0]) && parts[0] != null) {
coefficient = Integer.parseInt(parts[0]);
coefficientExists = true;
}
if (parts.length > 1 && !"".equals(parts[1]) && parts[1] != null) {
constant = Integer.parseInt(parts[1]);
constantExists = true;
}
} else if (element.contains("+")) {
constant = Integer.parseInt(element.replace("+", ""));
constantExists = true;
} else if (page.contains(",")) {
// Split the string into parts, could be single pages or ranges
String[] parts = page.split(",");
for (String part : parts) {
result.addAll(handlePart(part, totalPages, offset));
}
} else {
result.addAll(handlePart(page, totalPages, offset));
}
}
return new ArrayList<>(
new java.util.LinkedHashSet<>(result)); // Remove duplicates and maintain order
}

public static List<Integer> evaluateNFunc(String expression, int maxValue) {
List<Integer> results = new ArrayList<>();
DoubleEvaluator evaluator = new DoubleEvaluator();

// Validate the expression
if (!expression.matches("[0-9n+\\-*/() ]+")) {
throw new IllegalArgumentException("Invalid expression");
}

for (int i = 1; i <= totalPages; i++) {
int pageNum = coefficientExists ? coefficient * i : i;
pageNum += constantExists ? constant : 0;
int n = 0;
while (true) {
// Replace 'n' with the current value of n, correctly handling numbers before 'n'
String sanitizedExpression = insertMultiplicationBeforeN(expression, n);
Double result = evaluator.evaluate(sanitizedExpression);

if (pageNum <= totalPages && pageNum > 0) {
newPageOrder.add(pageNum - adjustmentFactor);
// Check if the result is null or not within bounds
if (result == null || result <= 0 || result.intValue() > maxValue) {
if (n != 0) break;
} else {
results.add(result.intValue());
}
n++;
}

return results;
}

private static String insertMultiplicationBeforeN(String expression, int nValue) {
// Insert multiplication between a number and 'n' (e.g., "4n" becomes "4*n")
String withMultiplication = expression.replaceAll("(\\d)n", "$1*n");
// Now replace 'n' with its current value
return withMultiplication.replaceAll("n", String.valueOf(nValue));
}

private static List<Integer> handlePart(String part, int totalPages, int offset) {
List<Integer> partResult = new ArrayList<>();

// First check for n-syntax because it should not be processed as a range
if (part.contains("n")) {
partResult = evaluateNFunc(part, totalPages);
// Adjust the results according to the offset
for (int i = 0; i < partResult.size(); i++) {
int adjustedValue = partResult.get(i) - 1 + offset;
partResult.set(i, adjustedValue);
}
} else if (part.contains("-")) {
// Process ranges only if it's not n-syntax
String[] rangeParts = part.split("-");
try {
int start = Integer.parseInt(rangeParts[0]);
int end = Integer.parseInt(rangeParts[1]);
for (int i = start; i <= end; i++) {
if (i >= 1 && i <= totalPages) {
partResult.add(i - 1 + offset);
}
}
} else if (element.contains("-")) {
// split the range into start and end page
String[] range = element.split("-");
int start = Integer.parseInt(range[0]);
int end = Integer.parseInt(range[1]);
// check if the end page is greater than total pages
if (end > totalPages) {
end = totalPages;
}
// loop through the range of pages
for (int j = start; j <= end; j++) {
// print the current index
newPageOrder.add(j - adjustmentFactor);
} catch (NumberFormatException e) {
// Range is invalid, ignore this part
}
} else {
// This is a single page number
try {
int pageNum = Integer.parseInt(part.trim());
if (pageNum >= 1 && pageNum <= totalPages) {
partResult.add(pageNum - 1 + offset);
}
} else {
// if the element is a single page
newPageOrder.add(Integer.parseInt(element) - adjustmentFactor);
} catch (NumberFormatException ignored) {
// Ignore invalid numbers
}
}

return newPageOrder;
return partResult;
}

public static boolean createDir(String path) {
Expand Down
Loading
Loading