java.security.AccessControlException when using com.aspose.pdf.Document

Hi,

we have a command line tool which generates a .doc file using aspose.Words, and if some parameter is set, it converts it to PDF to place signature fields.

The tool operates under a security policy which denies access to everything except some internal folders, and to try to prevent problems with the PDF Document class looking for fonts, right before instantiating it, the code is:

List<String> paths = new ArrayList<>(1);
paths.add(Util.getFontsFolder());
com.aspose.pdf.Document.setLocalFontPaths(paths);

ByteArrayOutputStream baos = new ByteArrayOutputStream();
doc.save(baos, SaveFormat.PDF);
com.aspose.pdf.Document pdf = new com.aspose.pdf.Document(new ByteArrayInputStream(baos.toByteArray()));

so, before creating the pdf instance, the list of available fonts paths is set to the only one which can be accessed based on the security policy, and which I am certain contains the fonts needed, however we still get exceptions like:

Exception in thread "main" java.lang.ExceptionInInitializerError
        at com.aspose.pdf.Document.m1(Unknown Source)
        at com.aspose.pdf.Document.addLocalFontPath(Unknown Source)
        at com.aspose.pdf.Document.setLocalFontPaths(Unknown Source)
        at com.agews.suite626.util.Util.placeSignatureFields(Util.java:293)
        at com.agews.suite626.printer.Print.output(Print.java:299)
        at com.agews.suite626.printer.Print.main(Print.java:176)
Caused by: java.security.AccessControlException: access denied ("java.io.FilePermission" "/usr/share/fonts" "read")
        at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472)
        at java.security.AccessController.checkPermission(AccessController.java:884)
        at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
        at java.lang.SecurityManager.checkRead(SecurityManager.java:888)
        at java.io.File.isDirectory(File.java:844)
        at com.aspose.pdf.internal.ms.System.IO.z4.m4(Unknown Source)
        at com.aspose.pdf.internal.p294.z8.m2(Unknown Source)
        at com.aspose.pdf.internal.p294.z8.m4(Unknown Source)
        at com.aspose.pdf.internal.p294.z8.<init>(Unknown Source)
        at com.aspose.pdf.internal.p294.z8.<clinit>(Unknown Source)
        ... 6 more

If I add that path to the policy, it goes again in error with another different path, as if it is still trying some default fonts paths.

How do I set it so that it only checks in that single given folder?

Upon further inspection of the code, the issue is caused by the fact that class com.aspose.pdf.Document has a private static ThreadLocal<List<String>> variable, which is initialized with an empty new ThreadLocal().

When the method getLocalFontPaths is called, it checks the list in the thread local variable, and upon finding it null, it tries to initialize it with the default font paths, which is exactly what I do NOT want it to do.

By looking at the code, there seem to be no option to fix this behaviour at “call place”, so I think it must be fixed directly in your code.

@mtassinari,

The getLocalFontPaths method returns a list of local font directories and the default directory is already added. You can add and remove directories from this list, and then reset by calling setLocalFontPaths method. If this does not help, then kindly send all details of the scenario, including source PDF, font files and let us know which version of Aspose.PDF for Java API you are using. We will investigate and share our findings with you.

It should not be null and maintain a single custom directory path.

I cannot provide any source PDF nor fonts file because those would be completely irrelevant for the issue I am describing.

Here follows the decompiled code of class com.aspose.pdf.Document version 17.10:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.aspose.pdf;

import com.aspose.pdf.devices.DocumentDevice;
import com.aspose.pdf.facades.DocumentPrivilege;
import com.aspose.pdf.internal.ms.System.z139;
import com.aspose.pdf.internal.ms.System.z65;
import com.aspose.pdf.internal.ms.System.z67;
import com.aspose.pdf.internal.ms.System.IO.Stream;
import com.aspose.pdf.internal.ms.System.IO.z28;
import com.aspose.pdf.internal.ms.System.IO.z34;
import com.aspose.pdf.internal.p1025.z7;
import com.aspose.pdf.internal.p17.z9;
import com.aspose.pdf.internal.p294.z8;
import com.aspose.pdf.internal.p63.z17;
import com.aspose.pdf.internal.p66.z5;
import com.aspose.pdf.internal.p75.z3;
import com.aspose.pdf.internal.p813.z569;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public final class Document extends ADocument implements IDocument {
    @z139
    private static ThreadLocal<List<String>> m3 = new ThreadLocal();
    private Document.IDocumentFontUtilities m4;

    private static synchronized List<String> m22() {
        return (List)m3.get();
    }

    private static synchronized void m1(List<String> var0) {
        m3.set(var0);
    }

    public static List<String> getLocalFontPaths() {
        if (m22() == null) {
            m2(false);
        }

        return m22();
    }

    public static void addLocalFontPath(String path) {
        if (m1(path)) {
            z17.m1().m5();
        }

    }

    static boolean m1(String var0) {
        if (!var0.isEmpty() && !"/".equals(var0)) {
            File var1 = new File(var0);
            if (var1.exists() && var1.isDirectory()) {
                if (!var0.endsWith("/") && !var0.endsWith("\\")) {
                    var0 = var0 + "/";
                }

                boolean var2 = false;
                Iterator var3 = getLocalFontPaths().iterator();

                while(var3.hasNext()) {
                    String var4 = (String)var3.next();
                    if (var4.equals(var0)) {
                        var2 = true;
                    }
                }

                if (!var2) {
                    getLocalFontPaths().add(var0);
                    String[] var5 = (String[])((String[])getLocalFontPaths().toArray(new String[getLocalFontPaths().size()]));

                    for(int var6 = 0; var6 < var5.length; ++var6) {
                        var5[var6] = var5[var6].substring(0, var5[var6].length() - 1);
                    }

                    z8.m5().m1(var5, true);
                    z7.m5().m1(var5, true);
                    com.aspose.pdf.internal.p552.z8.m5().m1(var5, true);
                    return true;
                }
            }
        }

        return false;
    }

    public static void setLocalFontPaths(List<String> newFontPathsList) {
        m1((List)(new ArrayList()));
        Iterator var1 = newFontPathsList.iterator();

        while(var1.hasNext()) {
            String var2 = (String)var1.next();
            addLocalFontPath(var2);
        }

        z17.m1().m5();
    }

    public static void restoreLocalFontPath() {
        m2(true);
    }

    private static synchronized String m23() {
        return z67.m3("WINDIR");
    }

    static void m2(boolean var0) {
        int var1 = z67.m9().m1();
        switch(var1) {
        case 0:
        case 1:
        case 2:
        case 3:
            m1((List)(new ArrayList()));
            m1(z34.m2(m23(), "Fonts/"));
            break;
        case 4:
        case 5:
        default:
            m1((List)(new ArrayList()));
            m1("/usr/openwin/lib/X11/fonts/TrueType/");
            m1("/usr/local/share/fonts/");
            m1("$home/.fonts/");
            m1("/usr/X11R6/lib/X11/fonts/ttfonts/");
            m1("~/.fonts/");
            m1("/usr/share/fonts/");
            m1("/usr/share/X11/fonts/TTF/");
            m1("/system/fonts/");
            m1("/QIBM/UserData/OS400/Fonts/");
            if (!System.getProperty("user.home").equals("$home")) {
                m1(System.getProperty("user.home") + "/.fonts/");
            }
            break;
        case 6:
            m1((List)(new ArrayList()));
            m1("/Library/Fonts/");
            m1("~/Library/Fonts/");
            m1("/Network/Library/Fonts/");
            m1("/System/Library/Fonts/");
        }

        String[] var2 = (String[])((String[])m22().toArray(new String[m22().size()]));

        for(int var3 = 0; var3 < var2.length; ++var3) {
            var2[var3] = var2[var3].substring(0, var2[var3].length() - 1);
        }

        z8.m5().m1(var2, true);
        if (var0) {
            z17.m1().m5();
        }

    }

    public PageInfo getPageInfo() {
        return super.getPageInfo();
    }

    public void setPageInfo(PageInfo value) {
        super.setPageInfo(value);
    }

    public DestinationCollection getDestinations() {
        return super.getDestinations();
    }

    public int getPdfaFormat() {
        return super.getPdfaFormat();
    }

    public Document.IDocumentFontUtilities getFontUtilities() {
        if (this.m4 == null) {
            this.m4 = new Document.z1(this);
        }

        return this.m4;
    }

    public void removePdfaCompliance() {
        super.removePdfaCompliance();
    }

    public Collection getCollection() {
        return super.getCollection();
    }

    public void setCollection(Collection value) {
        super.setCollection(value);
    }

    public z9 getEngineDoc() {
        return super.getEngineDoc();
    }

    public String getVersion() {
        return super.getVersion();
    }

    public IAppointment getOpenAction() {
        return super.getOpenAction();
    }

    public void setOpenAction(IAppointment value) {
        super.setOpenAction(value);
    }

    public boolean getHideToolBar() {
        return super.getHideToolBar();
    }

    public void setHideToolBar(boolean value) {
        super.setHideToolBar(value);
    }

    public boolean getHideMenubar() {
        return super.getHideMenubar();
    }

    public Document() {
    }

    public void setHideMenubar(boolean value) {
        super.setHideMenubar(value);
    }

    public boolean getHideWindowUI() {
        return super.getHideWindowUI();
    }

    public void setHideWindowUI(boolean value) {
        super.setHideWindowUI(value);
    }

    public boolean getFitWindow() {
        return super.getFitWindow();
    }

    public void setFitWindow(boolean value) {
        super.setFitWindow(value);
    }

    public boolean getCenterWindow() {
        return super.getCenterWindow();
    }

    public void setCenterWindow(boolean value) {
        super.setCenterWindow(value);
    }

    public boolean getDisplayDocTitle() {
        return super.getDisplayDocTitle();
    }

    public void setDisplayDocTitle(boolean value) {
        super.setDisplayDocTitle(value);
    }

    public PageCollection getPages() {
        return super.getPages();
    }

    public OutlineCollection getOutlines() {
        return super.getOutlines();
    }

    public DocumentActionCollection getActions() {
        return super.getActions();
    }

    public Form getForm() {
        return super.getForm();
    }

    public EmbeddedFileCollection getEmbeddedFiles() {
        return super.getEmbeddedFiles();
    }

    public int getDirection() {
        return super.getDirection();
    }

    public void setDirection(int value) {
        super.setDirection(value);
    }

    public int getPageMode() {
        return super.getPageMode();
    }

    public void setPageMode(int pageMode) {
        super.setPageMode(pageMode);
    }

    public int getNonFullScreenPageMode() {
        return super.getNonFullScreenPageMode();
    }

    public void setNonFullScreenPageMode(int value) {
        super.setNonFullScreenPageMode(value);
    }

    public int getPageLayout() {
        return super.getPageLayout();
    }

    public void setPageLayout(int value) {
        super.setPageLayout(value);
    }

    public String getFileName() {
        return super.getFileName();
    }

    public DocumentInfo getInfo() {
        return super.getInfo();
    }

    public Metadata getMetadata() {
        return super.getMetadata();
    }

    public RootElement getLogicalStructure() {
        return super.getLogicalStructure();
    }

    public Document(InputStream input) {
        super(input);
    }

    public Document(InputStream input, String password) {
        super(input, password);
    }

    public Document(Stream input) {
        super(input);
    }

    Document(Stream input, String password, boolean isManagedStream) {
        super(input, password, isManagedStream);
    }

    public Document(InputStream input, String password, boolean isManagedStream) {
        super(input, password, isManagedStream);
    }

    Document(Stream input, boolean isManagedStream) {
        super(input, isManagedStream);
    }

    public Document(InputStream input, boolean isManagedStream) {
        super(input, isManagedStream);
    }

    public Document(InputStream input, LoadOptions options) {
        super(z28.fromJava(input), options);
    }

    Document(Stream input, LoadOptions options) {
        super(input, options);
    }

    public Document(String filename, LoadOptions options) {
        super(filename, options);
    }

    public Document(Stream input, String password) {
        super(input, password);
    }

    public Document(String filename) {
        super(filename);
    }

    public Document(String filename, String password) {
        super(filename, password);
    }

    public void processParagraphs() {
        super.processParagraphs();
    }

    public void saveInternal(Stream output) {
        super.saveInternal(output);
    }

    public void save(OutputStream output) {
        super.save(output);
    }

    public void save(String outputFileName) {
        super.save(outputFileName);
    }

    public void exportAnnotationsToXfdf(String fileName) {
        super.exportAnnotationsToXfdf(fileName);
    }

    void m1(DocumentDevice var1, Stream var2) {
        super.m1(var1, var2);
    }

    public void sendTo(DocumentDevice device, OutputStream output) {
        super.sendTo(device, output);
    }

    void m1(DocumentDevice var1, int var2, int var3, Stream var4) {
        super.m1(var1, var2, var3, var4);
    }

    public void sendTo(DocumentDevice device, int fromPage, int toPage, OutputStream output) {
        super.sendTo(device, fromPage, toPage, output);
    }

    public void sendTo(DocumentDevice device, String outputFileName) {
        super.sendTo(device, outputFileName);
    }

    public void sendTo(DocumentDevice device, int fromPage, int toPage, String outputFileName) {
        super.sendTo(device, fromPage, toPage, outputFileName);
    }

    public void removeMetadata() {
        super.removeMetadata();
    }

    public void importAnnotationsFromXfdf(String fileName) {
        super.importAnnotationsFromXfdf(fileName);
    }

    public boolean validate(String outputLogFileName, int format) {
        return super.validate(outputLogFileName, format);
    }

    public boolean convert(String outputLogFileName, int format, int action) {
        return super.convert(outputLogFileName, format, action);
    }

    public boolean validate(OutputStream outputLogStream, int format) {
        return super.validate(outputLogStream, format);
    }

    boolean m1(Stream var1, int var2) {
        return super.m1(var1, var2);
    }

    public boolean convert(String outputLogFileName, int format, int action, int transparencyAction) {
        return super.convert(outputLogFileName, format, action, transparencyAction);
    }

    public boolean convert(Document.CallBackGetHocr callback) {
        return super.convert(callback);
    }

    public boolean convertInternal(Stream outputLogStream, int format, int action) {
        return super.convertInternal(outputLogStream, format, action);
    }

    public boolean convert(OutputStream outputLogStream, int format, int action) {
        return super.convert(outputLogStream, format, action);
    }

    public boolean convert(PdfFormatConversionOptions options) {
        return super.convert(options);
    }

    boolean m1(z569 var1, int var2, boolean var3, int var4) {
        return super.m1(var1, var2, var3, var4);
    }

    public void flatten() {
        super.flatten();
    }

    public int getCryptoAlgorithm() {
        return super.getCryptoAlgorithm();
    }

    public void encrypt(String userPassword, String ownerPassword, DocumentPrivilege privileges, int cryptoAlgorithm, boolean usePdf20) {
        super.encrypt(userPassword, ownerPassword, privileges, cryptoAlgorithm, usePdf20);
    }

    public void encrypt(String userPassword, String ownerPassword, int permissions, int cryptoAlgorithm) {
        super.encrypt(userPassword, ownerPassword, permissions, cryptoAlgorithm);
    }

    public void encrypt(String userPassword, String ownerPassword, int permissions, int cryptoAlgorithm, boolean usePdf20) {
        super.encrypt(userPassword, ownerPassword, permissions, cryptoAlgorithm, usePdf20);
    }

    public void changePasswords(String ownerPassword, String newUserPassword, String newOwnerPassword) {
        super.changePasswords(ownerPassword, newUserPassword, newOwnerPassword);
    }

    public Document(String filename, String password, boolean isManagedStream) {
        super(filename, password, isManagedStream);
    }

    public boolean isLinearized() {
        return super.isLinearized();
    }

    public void setLinearized(boolean value) {
        super.setLinearized(value);
    }

    public void decrypt() {
        super.decrypt();
    }

    public int getPermissions() {
        return super.getPermissions();
    }

    public boolean isEncrypted() {
        return super.isEncrypted();
    }

    public void optimize() {
        super.optimize();
    }

    public void save() {
        super.save();
    }

    public void save(String outputFileName, int format) {
        super.save(outputFileName, format);
    }

    void m2(Stream var1, int var2) {
        super.m2(var1, var2);
    }

    public void save(OutputStream outputStream, int format) {
        super.save(outputStream, format);
    }

    public void save(String outputFileName, SaveOptions options) {
        super.save(outputFileName, options);
    }

    void m1(Stream var1, SaveOptions var2) {
        super.m1(var1, var2);
    }

    public void save(OutputStream outputStream, SaveOptions options) {
        super.save(outputStream, options);
    }

    public Id getId() {
        return super.getId();
    }

    public z3 getMetadataStream() {
        return super.getMetadataStream();
    }

    public void suppressUpdate() {
        super.suppressUpdate();
    }

    public void resumeUpdate() {
        super.resumeUpdate();
    }

    public void dispose() {
        super.dispose();
    }

    public Color getBackground() {
        return super.getBackground();
    }

    public void setBackground(Color value) {
        super.setBackground(value);
    }

    public Copier getDefaultCopier() {
        return super.getDefaultCopier();
    }

    public void optimizeResources() {
        super.optimizeResources();
    }

    public void optimizeResources(Document.OptimizationOptions strategy) {
        super.optimizeResources(strategy);
    }

    public boolean getOptimizeSize() {
        return super.getOptimizeSize();
    }

    public void setOptimizeSize(boolean value) {
        super.setOptimizeSize(value);
    }

    public boolean getIgnoreCorruptedObjects() {
        return super.getIgnoreCorruptedObjects();
    }

    public void setIgnoreCorruptedObjects(boolean value) {
        super.setIgnoreCorruptedObjects(value);
    }

    public Object getCatalogValue(String key) {
        return super.getCatalogValue(key);
    }

    public PageLabelCollection getPageLabels() {
        return super.getPageLabels();
    }

    public void freeMemory() {
        super.freeMemory();
    }

    public boolean isAbsentFontTryToSubstitute() {
        return super.isAbsentFontTryToSubstitute();
    }

    public void setAbsentFontTryToSubstitute(boolean setAbsentFontTryToSubstitute) {
        super.setAbsentFontTryToSubstitute(setAbsentFontTryToSubstitute);
    }

    public boolean check(boolean doRepair) {
        return super.check(doRepair);
    }

    private static class z1 implements Document.IDocumentFontUtilities {
        private Document m1;

        public z1(Document var1) {
            this.m1 = var1;
        }

        public void subsetFonts(byte subsetStrategy) {
            z5.m3(this.m1).m1(subsetStrategy);
        }
    }

    public interface IDocumentFontUtilities {
        void subsetFonts(byte var1);
    }

    public static final class FontSubsetStrategy extends z65 {
        public static final byte SubsetEmbeddedFontsOnly = 0;
        public static final byte SubsetAllFonts = 1;

        private FontSubsetStrategy() {
        }

        static {
            z65.register(new com.aspose.pdf.internal.ms.System.z65.z5(Document.FontSubsetStrategy.class, Byte.class) {
                {
                    this.m1("SubsetEmbeddedFontsOnly", 0L);
                    this.m1("SubsetAllFonts", 1L);
                }
            });
        }
    }

    public static class OptimizationOptions {
        private boolean m1 = false;
        private boolean m2 = false;
        private boolean m3 = false;
        private boolean m4 = false;
        private boolean m5 = false;
        private boolean m6 = false;
        private boolean m7 = false;
        private boolean m8 = false;
        private int m9 = 100;
        private int m10 = 6000;
        private int m11 = 0;
        private int m12 = 0;

        public OptimizationOptions() {
        }

        public boolean getLinkDuplcateStreams() {
            return this.m1;
        }

        public void setLinkDuplcateStreams(boolean value) {
            this.m1 = value;
        }

        public boolean getAllowReusePageContent() {
            return this.m7;
        }

        public void setAllowReusePageContent(boolean value) {
            this.m7 = value;
        }

        public boolean getRemoveUnusedStreams() {
            return this.m2;
        }

        public void setRemoveUnusedStreams(boolean value) {
            this.m2 = value;
        }

        public boolean getRemoveUnusedObjects() {
            return this.m3;
        }

        public void setRemoveUnusedObjects(boolean value) {
            this.m3 = value;
        }

        public boolean isCompressImages() {
            return this.m4;
        }

        public void setCompressImages(boolean value) {
            this.m4 = value;
        }

        public boolean isResizeImages() {
            return this.m5;
        }

        public void setResizeImages(boolean value) {
            this.m5 = value;
        }

        public int getImageQuality() {
            return this.m9;
        }

        public void setImageQuality(int value) {
            if (value > 0 && value <= 100) {
                this.m9 = value;
            } else {
                throw new com.aspose.pdf.internal.ms.System.z9("Image quality value must be in range [0...100]");
            }
        }

        public int getMaxResoultion() {
            return this.m10;
        }

        public void setMaxResoultion(int value) {
            this.m10 = value;
        }

        public boolean isUnembedFonts() {
            return this.m6;
        }

        public void setUnembedFonts(boolean value) {
            this.m6 = value;
        }

        public boolean isRemovePrivateInfo() {
            return this.m8;
        }

        public void setRemovePrivateInfo(boolean value) {
            this.m8 = value;
        }

        public static Document.OptimizationOptions all() {
            Document.OptimizationOptions var0 = new Document.OptimizationOptions();
            var0.setLinkDuplcateStreams(true);
            var0.setRemoveUnusedObjects(true);
            var0.setRemoveUnusedStreams(true);
            return var0;
        }

        public int getResolution() {
            return this.m11;
        }

        public void setResolution(int dpi) {
            this.m11 = dpi;
        }

        public int getMaximumImageDimension() {
            return this.m12;
        }

        public void setMaximumImageDimension(int dimension) {
            this.m12 = dimension;
        }
    }

    public interface CallBackGetHocr {
        String invoke(BufferedImage var1);
    }
}

As you can see, the private static ThreadLocal<List<String>> is initialized with a new ThreadLocal(), which at initialization time does not contain a List<String>.

If we follow the code path of a call to setLocalFontPaths:

  1. it calls on addLocalFontPath(String path)
  2. which in turn calls m1(String var0) (I guess that method has another name on the original source)
  3. which then calls getLocalFontPaths()
  4. which calls m22(), a method which tries to get the List<String> from the ThreadLocal
  5. since the ThreadLocal does not contain the list, it calls m2(boolean var0) passing false to initialize it
  6. which tries to load the default font paths by going back to m1(String var0) for each one
  7. and this causes the AccessControlException, because each of those paths is tested by creating a File instance and checking that exists and isDirectory, but the security policy we are using does not allow those paths to be accessed

In my opinion, this is an issue that must be solved by your dev team, and could be solved simply by adding a try { ... } catch { ... } around the code which instantiate the File to verify it exists, if an exception occur just consider as if the test was false.

@mtassinari

Thanks for sharing the requested details.

We are looking into the scenario and will get back to you with our findings soon. Please be patient.

@mtassinari,

Please download and try the latest version 18.1 of Aspose.Pdf for Java API. It does not initialize the object of type ThreadLocal at start (private static object). The old version 17.10 may have a bug. This is the decompiled code of class com.aspose.pdf.Document version 18.1: DecompiledDocument.zip (6.1 KB)

I am sorry but what you attached is not the “decompiled” version of class com.aspose.pdf.Document, it is just the bytecode!

And I just tried version 18.1.0, it still has the same bug, here is the real decompiled code:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.aspose.pdf;

import com.aspose.pdf.devices.DocumentDevice;
import com.aspose.pdf.facades.DocumentPrivilege;
import com.aspose.pdf.internal.ms.System.z139;
import com.aspose.pdf.internal.ms.System.z65;
import com.aspose.pdf.internal.ms.System.z67;
import com.aspose.pdf.internal.ms.System.IO.Stream;
import com.aspose.pdf.internal.ms.System.IO.z28;
import com.aspose.pdf.internal.ms.System.IO.z34;
import com.aspose.pdf.internal.p281.z9;
import com.aspose.pdf.internal.p546.z8;
import com.aspose.pdf.internal.p69.z17;
import com.aspose.pdf.internal.p72.z5;
import com.aspose.pdf.internal.p81.z3;
import com.aspose.pdf.internal.p837.z569;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public final class Document extends ADocument implements IDocument {
    @z139
    private static ThreadLocal<List<String>> m4 = new ThreadLocal();
    private Document.IDocumentFontUtilities m5;

    private static synchronized List<String> m22() {
        return (List)m4.get();
    }

    private static synchronized void m1(List<String> var0) {
        m4.set(var0);
    }

    public static List<String> getLocalFontPaths() {
        if (m22() == null) {
            m2(false);
        }

        return m22();
    }

    public static void addLocalFontPath(String path) {
        if (m1(path)) {
            z17.m1().m5();
        }

    }

    static boolean m1(String var0) {
        if (!var0.isEmpty() && !"/".equals(var0)) {
            File var1 = new File(var0);
            if (var1.exists() && var1.isDirectory()) {
                if (!var0.endsWith("/") && !var0.endsWith("\\")) {
                    var0 = var0 + "/";
                }

                boolean var2 = false;
                Iterator var3 = getLocalFontPaths().iterator();

                while(var3.hasNext()) {
                    String var4 = (String)var3.next();
                    if (var4.equals(var0)) {
                        var2 = true;
                    }
                }

                if (!var2) {
                    getLocalFontPaths().add(var0);
                    String[] var5 = (String[])((String[])getLocalFontPaths().toArray(new String[getLocalFontPaths().size()]));

                    for(int var6 = 0; var6 < var5.length; ++var6) {
                        var5[var6] = var5[var6].substring(0, var5[var6].length() - 1);
                    }

                    z9.m5().m1(var5, true);
                    z8.m5().m1(var5, true);
                    return true;
                }
            }
        }

        return false;
    }

    public static void setLocalFontPaths(List<String> newFontPathsList) {
        m1((List)(new ArrayList()));
        Iterator var1 = newFontPathsList.iterator();

        while(var1.hasNext()) {
            String var2 = (String)var1.next();
            addLocalFontPath(var2);
        }

        z17.m1().m5();
    }

    public static void restoreLocalFontPath() {
        m2(true);
    }

    private static synchronized String m23() {
        return z67.m3("WINDIR");
    }

    static void m2(boolean var0) {
        int var1 = z67.m9().m1();
        switch(var1) {
        case 0:
        case 1:
        case 2:
        case 3:
            m1((List)(new ArrayList()));
            m1(z34.m2(m23(), "Fonts/"));
            break;
        case 4:
        case 5:
        default:
            m1((List)(new ArrayList()));
            m1("/usr/openwin/lib/X11/fonts/TrueType/");
            m1("/usr/local/share/fonts/");
            m1("$home/.fonts/");
            m1("/usr/X11R6/lib/X11/fonts/ttfonts/");
            m1("~/.fonts/");
            m1("/usr/share/fonts/");
            m1("/usr/share/X11/fonts/TTF/");
            m1("/system/fonts/");
            m1("/QIBM/UserData/OS400/Fonts/");
            if (!System.getProperty("user.home").equals("$home")) {
                m1(System.getProperty("user.home") + "/.fonts/");
            }
            break;
        case 6:
            m1((List)(new ArrayList()));
            m1("/Library/Fonts/");
            m1("~/Library/Fonts/");
            m1("/Network/Library/Fonts/");
            m1("/System/Library/Fonts/");
        }

        String[] var2 = (String[])((String[])m22().toArray(new String[m22().size()]));

        for(int var3 = 0; var3 < var2.length; ++var3) {
            var2[var3] = var2[var3].substring(0, var2[var3].length() - 1);
        }

        z9.m5().m1(var2, true);
        if (var0) {
            z17.m1().m5();
        }

    }

    public PageInfo getPageInfo() {
        return super.getPageInfo();
    }

    public void setPageInfo(PageInfo value) {
        super.setPageInfo(value);
    }

    public DestinationCollection getDestinations() {
        return super.getDestinations();
    }

    public int getPdfaFormat() {
        return super.getPdfaFormat();
    }

    public Document.IDocumentFontUtilities getFontUtilities() {
        if (this.m5 == null) {
            this.m5 = new Document.z1(this);
        }

        return this.m5;
    }

    public void removePdfaCompliance() {
        super.removePdfaCompliance();
    }

    public Collection getCollection() {
        return super.getCollection();
    }

    public void setCollection(Collection value) {
        super.setCollection(value);
    }

    public com.aspose.pdf.internal.p22.z9 getEngineDoc() {
        return super.getEngineDoc();
    }

    public String getVersion() {
        return super.getVersion();
    }

    public IAppointment getOpenAction() {
        return super.getOpenAction();
    }

    public void setOpenAction(IAppointment value) {
        super.setOpenAction(value);
    }

    public boolean getHideToolBar() {
        return super.getHideToolBar();
    }

    public void setHideToolBar(boolean value) {
        super.setHideToolBar(value);
    }

    public boolean getHideMenubar() {
        return super.getHideMenubar();
    }

    public Document() {
    }

    public void setHideMenubar(boolean value) {
        super.setHideMenubar(value);
    }

    public boolean getHideWindowUI() {
        return super.getHideWindowUI();
    }

    public void setHideWindowUI(boolean value) {
        super.setHideWindowUI(value);
    }

    public boolean getFitWindow() {
        return super.getFitWindow();
    }

    public void setFitWindow(boolean value) {
        super.setFitWindow(value);
    }

    public boolean getCenterWindow() {
        return super.getCenterWindow();
    }

    public void setCenterWindow(boolean value) {
        super.setCenterWindow(value);
    }

    public boolean getDisplayDocTitle() {
        return super.getDisplayDocTitle();
    }

    public void setDisplayDocTitle(boolean value) {
        super.setDisplayDocTitle(value);
    }

    public PageCollection getPages() {
        return super.getPages();
    }

    public OutlineCollection getOutlines() {
        return super.getOutlines();
    }

    public DocumentActionCollection getActions() {
        return super.getActions();
    }

    public Form getForm() {
        return super.getForm();
    }

    public EmbeddedFileCollection getEmbeddedFiles() {
        return super.getEmbeddedFiles();
    }

    public int getDirection() {
        return super.getDirection();
    }

    public void setDirection(int value) {
        super.setDirection(value);
    }

    public int getPageMode() {
        return super.getPageMode();
    }

    public void setPageMode(int pageMode) {
        super.setPageMode(pageMode);
    }

    public int getNonFullScreenPageMode() {
        return super.getNonFullScreenPageMode();
    }

    public void setNonFullScreenPageMode(int value) {
        super.setNonFullScreenPageMode(value);
    }

    public int getPageLayout() {
        return super.getPageLayout();
    }

    public void setPageLayout(int value) {
        super.setPageLayout(value);
    }

    public String getFileName() {
        return super.getFileName();
    }

    public DocumentInfo getInfo() {
        return super.getInfo();
    }

    public Metadata getMetadata() {
        return super.getMetadata();
    }

    public RootElement getLogicalStructure() {
        return super.getLogicalStructure();
    }

    public Document(InputStream input) {
        super(input);
    }

    public Document(InputStream input, String password) {
        super(input, password);
    }

    public Document(Stream input) {
        super(input);
    }

    Document(Stream input, String password, boolean isManagedStream) {
        super(input, password, isManagedStream);
    }

    public Document(InputStream input, String password, boolean isManagedStream) {
        super(input, password, isManagedStream);
    }

    Document(Stream input, boolean isManagedStream) {
        super(input, isManagedStream);
    }

    public Document(InputStream input, boolean isManagedStream) {
        super(input, isManagedStream);
    }

    public Document(InputStream input, LoadOptions options) {
        super(z28.fromJava(input), options);
    }

    Document(Stream input, LoadOptions options) {
        super(input, options);
    }

    public Document(String filename, LoadOptions options) {
        super(filename, options);
    }

    public Document(Stream input, String password) {
        super(input, password);
    }

    public Document(String filename) {
        super(filename);
    }

    public Document(String filename, String password) {
        super(filename, password);
    }

    public void processParagraphs() {
        super.processParagraphs();
    }

    public void saveInternal(Stream output) {
        super.saveInternal(output);
    }

    public void save(OutputStream output) {
        super.save(output);
    }

    public void save(String outputFileName) {
        super.save(outputFileName);
    }

    public void exportAnnotationsToXfdf(String fileName) {
        super.exportAnnotationsToXfdf(fileName);
    }

    void m1(DocumentDevice var1, Stream var2) {
        super.m1(var1, var2);
    }

    public void sendTo(DocumentDevice device, OutputStream output) {
        super.sendTo(device, output);
    }

    void m1(DocumentDevice var1, int var2, int var3, Stream var4) {
        super.m1(var1, var2, var3, var4);
    }

    public void sendTo(DocumentDevice device, int fromPage, int toPage, OutputStream output) {
        super.sendTo(device, fromPage, toPage, output);
    }

    public void sendTo(DocumentDevice device, String outputFileName) {
        super.sendTo(device, outputFileName);
    }

    public void sendTo(DocumentDevice device, int fromPage, int toPage, String outputFileName) {
        super.sendTo(device, fromPage, toPage, outputFileName);
    }

    public void removeMetadata() {
        super.removeMetadata();
    }

    public void importAnnotationsFromXfdf(String fileName) {
        super.importAnnotationsFromXfdf(fileName);
    }

    public boolean validate(String outputLogFileName, int format) {
        return super.validate(outputLogFileName, format);
    }

    public boolean convert(String outputLogFileName, int format, int action) {
        return super.convert(outputLogFileName, format, action);
    }

    public boolean validate(OutputStream outputLogStream, int format) {
        return super.validate(outputLogStream, format);
    }

    boolean m1(Stream var1, int var2) {
        return super.m1(var1, var2);
    }

    public boolean convert(String outputLogFileName, int format, int action, int transparencyAction) {
        return super.convert(outputLogFileName, format, action, transparencyAction);
    }

    public boolean convert(Document.CallBackGetHocr callback) {
        return super.convert(callback);
    }

    public boolean convertInternal(Stream outputLogStream, int format, int action) {
        return super.convertInternal(outputLogStream, format, action);
    }

    public boolean convert(OutputStream outputLogStream, int format, int action) {
        return super.convert(outputLogStream, format, action);
    }

    public boolean convert(PdfFormatConversionOptions options) {
        return super.convert(options);
    }

    boolean m1(z569 var1, int var2, boolean var3, int var4) {
        return super.m1(var1, var2, var3, var4);
    }

    public void flatten() {
        super.flatten();
    }

    public int getCryptoAlgorithm() {
        return super.getCryptoAlgorithm();
    }

    public void encrypt(String userPassword, String ownerPassword, DocumentPrivilege privileges, int cryptoAlgorithm, boolean usePdf20) {
        super.encrypt(userPassword, ownerPassword, privileges, cryptoAlgorithm, usePdf20);
    }

    public void encrypt(String userPassword, String ownerPassword, int permissions, int cryptoAlgorithm) {
        super.encrypt(userPassword, ownerPassword, permissions, cryptoAlgorithm);
    }

    public void encrypt(String userPassword, String ownerPassword, int permissions, int cryptoAlgorithm, boolean usePdf20) {
        super.encrypt(userPassword, ownerPassword, permissions, cryptoAlgorithm, usePdf20);
    }

    public void changePasswords(String ownerPassword, String newUserPassword, String newOwnerPassword) {
        super.changePasswords(ownerPassword, newUserPassword, newOwnerPassword);
    }

    public Document(String filename, String password, boolean isManagedStream) {
        super(filename, password, isManagedStream);
    }

    public boolean isLinearized() {
        return super.isLinearized();
    }

    public void setLinearized(boolean value) {
        super.setLinearized(value);
    }

    public void decrypt() {
        super.decrypt();
    }

    public int getPermissions() {
        return super.getPermissions();
    }

    public boolean isEncrypted() {
        return super.isEncrypted();
    }

    public void optimize() {
        super.optimize();
    }

    public void save() {
        super.save();
    }

    public void save(String outputFileName, int format) {
        super.save(outputFileName, format);
    }

    public void saveIncrementally(OutputStream output) {
        super.saveIncrementally(output);
    }

    void m2(Stream var1, int var2) {
        super.m2(var1, var2);
    }

    public void save(OutputStream outputStream, int format) {
        super.save(outputStream, format);
    }

    public void save(String outputFileName, SaveOptions options) {
        super.save(outputFileName, options);
    }

    void m1(Stream var1, SaveOptions var2) {
        super.m1(var1, var2);
    }

    public void save(OutputStream outputStream, SaveOptions options) {
        super.save(outputStream, options);
    }

    public Id getId() {
        return super.getId();
    }

    public z3 getMetadataStream() {
        return super.getMetadataStream();
    }

    public void suppressUpdate() {
        super.suppressUpdate();
    }

    public void resumeUpdate() {
        super.resumeUpdate();
    }

    public void dispose() {
        super.dispose();
    }

    public Color getBackground() {
        return super.getBackground();
    }

    public void setBackground(Color value) {
        super.setBackground(value);
    }

    public Copier getDefaultCopier() {
        return super.getDefaultCopier();
    }

    public void optimizeResources() {
        super.optimizeResources();
    }

    public void optimizeResources(Document.OptimizationOptions strategy) {
        super.optimizeResources(strategy);
    }

    public boolean getOptimizeSize() {
        return super.getOptimizeSize();
    }

    public void setOptimizeSize(boolean value) {
        super.setOptimizeSize(value);
    }

    public boolean getIgnoreCorruptedObjects() {
        return super.getIgnoreCorruptedObjects();
    }

    public void setIgnoreCorruptedObjects(boolean value) {
        super.setIgnoreCorruptedObjects(value);
    }

    public Object getCatalogValue(String key) {
        return super.getCatalogValue(key);
    }

    public PageLabelCollection getPageLabels() {
        return super.getPageLabels();
    }

    public void freeMemory() {
        super.freeMemory();
    }

    public boolean isAbsentFontTryToSubstitute() {
        return super.isAbsentFontTryToSubstitute();
    }

    public void setAbsentFontTryToSubstitute(boolean setAbsentFontTryToSubstitute) {
        super.setAbsentFontTryToSubstitute(setAbsentFontTryToSubstitute);
    }

    public boolean check(boolean doRepair) {
        return super.check(doRepair);
    }

    private static class z1 implements Document.IDocumentFontUtilities {
        private Document m1;

        public z1(Document var1) {
            this.m1 = var1;
        }

        public void subsetFonts(byte subsetStrategy) {
            z5.m3(this.m1).m1(subsetStrategy);
        }
    }

    public interface IDocumentFontUtilities {
        void subsetFonts(byte var1);
    }

    public static final class FontSubsetStrategy extends z65 {
        public static final byte SubsetEmbeddedFontsOnly = 0;
        public static final byte SubsetAllFonts = 1;

        private FontSubsetStrategy() {
        }

        static {
            z65.register(new com.aspose.pdf.internal.ms.System.z65.z5(Document.FontSubsetStrategy.class, Byte.class) {
                {
                    this.m1("SubsetEmbeddedFontsOnly", 0L);
                    this.m1("SubsetAllFonts", 1L);
                }
            });
        }
    }

    public static class OptimizationOptions {
        private boolean m1 = false;
        private boolean m2 = false;
        private boolean m3 = false;
        private boolean m4 = false;
        private boolean m5 = false;
        private boolean m6 = false;
        private boolean m7 = false;
        private boolean m8 = false;
        private int m9 = 100;
        private int m10 = 6000;
        private int m11 = 0;
        private int m12 = 0;

        public OptimizationOptions() {
        }

        public boolean getLinkDuplcateStreams() {
            return this.m1;
        }

        public void setLinkDuplcateStreams(boolean value) {
            this.m1 = value;
        }

        public boolean getAllowReusePageContent() {
            return this.m7;
        }

        public void setAllowReusePageContent(boolean value) {
            this.m7 = value;
        }

        public boolean getRemoveUnusedStreams() {
            return this.m2;
        }

        public void setRemoveUnusedStreams(boolean value) {
            this.m2 = value;
        }

        public boolean getRemoveUnusedObjects() {
            return this.m3;
        }

        public void setRemoveUnusedObjects(boolean value) {
            this.m3 = value;
        }

        public boolean isCompressImages() {
            return this.m4;
        }

        public void setCompressImages(boolean value) {
            this.m4 = value;
        }

        public boolean isResizeImages() {
            return this.m5;
        }

        public void setResizeImages(boolean value) {
            this.m5 = value;
        }

        public int getImageQuality() {
            return this.m9;
        }

        public void setImageQuality(int value) {
            if (value > 0 && value <= 100) {
                this.m9 = value;
            } else {
                throw new com.aspose.pdf.internal.ms.System.z9("Image quality value must be in range [0...100]");
            }
        }

        public int getMaxResoultion() {
            return this.m10;
        }

        public void setMaxResoultion(int value) {
            this.m10 = value;
        }

        public boolean isUnembedFonts() {
            return this.m6;
        }

        public void setUnembedFonts(boolean value) {
            this.m6 = value;
        }

        public boolean isRemovePrivateInfo() {
            return this.m8;
        }

        public void setRemovePrivateInfo(boolean value) {
            this.m8 = value;
        }

        public static Document.OptimizationOptions all() {
            Document.OptimizationOptions var0 = new Document.OptimizationOptions();
            var0.setLinkDuplcateStreams(true);
            var0.setRemoveUnusedObjects(true);
            var0.setRemoveUnusedStreams(true);
            return var0;
        }

        public int getResolution() {
            return this.m11;
        }

        public void setResolution(int dpi) {
            this.m11 = dpi;
        }

        public int getMaximumImageDimension() {
            return this.m12;
        }

        public void setMaximumImageDimension(int dimension) {
            this.m12 = dimension;
        }
    }

    public interface CallBackGetHocr {
        String invoke(BufferedImage var1);
    }
}

As you can see, the code path of the call to setLocalFontPaths is unchanged.

@mtassinari

Thanks for adding more details to the scenario.

We are testing the scenario in our environment and will get back to you with results shortly. Please be patient.

@mtassinari,

We have logged an investigation under the ticket ID PDFJAVA-37466 in our issue tracking system. We have linked your post to this ticket and will keep you informed regarding any available updates.

The issues you have found earlier (filed as PDFJAVA-37466) have been fixed in Aspose.PDF for Java 18.4. This message was posted using BugNotificationTool from Downloads module by asad.ali