Created
March 6, 2026 21:46
-
-
Save asdf913/106e9b1e1c4c315e73e691ac22d5eced to your computer and use it in GitHub Desktop.
Get Font File Paths. This program will invoke native function based on the operating system.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package test2; | |
| import java.io.File; | |
| import java.net.URI; | |
| import java.net.URISyntaxException; | |
| import java.nio.file.FileSystems; | |
| import java.nio.file.Path; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.Collection; | |
| import java.util.List; | |
| import java.util.Objects; | |
| import java.util.function.Predicate; | |
| import org.apache.commons.io.FileUtils; | |
| import org.apache.commons.io.filefilter.IOFileFilter; | |
| import org.apache.commons.io.filefilter.TrueFileFilter; | |
| import org.apache.commons.lang3.ObjectUtils; | |
| import org.apache.commons.lang3.function.FailableFunction; | |
| import com.sun.jna.Library; | |
| import com.sun.jna.Memory; | |
| import com.sun.jna.Native; | |
| import com.sun.jna.Pointer; | |
| import com.sun.jna.Structure; | |
| import com.sun.jna.platform.win32.KnownFolders; | |
| import com.sun.jna.platform.win32.Shell32Util; | |
| import com.sun.jna.ptr.PointerByReference; | |
| public class GetFontFilePaths { | |
| private interface CoreText extends Library { | |
| Pointer CTFontManagerCopyAvailableFontURLs(); | |
| private static Pointer CTFontManagerCopyAvailableFontURLs(final CoreText instance) { | |
| return instance != null ? instance.CTFontManagerCopyAvailableFontURLs() : null; | |
| } | |
| } | |
| private interface CoreFoundation extends Library { | |
| void CFRelease(final Pointer obj); | |
| long CFArrayGetCount(final Pointer array); | |
| Pointer CFArrayGetValueAtIndex(final Pointer array, final long index); | |
| Pointer CFURLGetString(final Pointer anURL); | |
| long CFStringGetLength(final Pointer str); | |
| long CFStringGetMaximumSizeForEncoding(final long length, final int encoding); | |
| boolean CFStringGetCString(final Pointer theString, final Pointer buffer, final long bufferSize, | |
| final int encoding); | |
| private static void CFRelease(final CoreFoundation instance, final Pointer obj) { | |
| if (instance != null) { | |
| instance.CFRelease(obj); | |
| } | |
| } | |
| } | |
| private interface FontConfig extends Library { | |
| Pointer FcInitLoadConfigAndFonts(); | |
| Pointer FcPatternCreate(); | |
| Pointer FcObjectSetBuild(final String s1, final String s2, final String s3, final String s4, final Pointer p); | |
| Pointer FcFontList(final Pointer config, final Pointer pat, final Pointer os); | |
| void FcFontSetDestroy(final Pointer fs); | |
| int FcPatternGetString(final Pointer p, final String object, final int n, final PointerByReference s); | |
| private static int FcPatternGetString(final FontConfig instance, final Pointer p, final String object, | |
| final int n, final PointerByReference s) { | |
| return instance != null ? instance.FcPatternGetString(p, object, n, s) : 0; | |
| } | |
| private static void FcFontSetDestroy(final FontConfig instance, final Pointer fs) { | |
| if (instance != null) { | |
| instance.FcFontSetDestroy(fs); | |
| } | |
| } | |
| class FcFontSet extends Structure { | |
| public int nfont; | |
| public Pointer fonts; | |
| private FcFontSet(final Pointer pointer) { | |
| super(pointer); | |
| } | |
| @Override | |
| protected List<String> getFieldOrder() { | |
| return Arrays.asList("nfont", "fonts"); | |
| } | |
| @Override | |
| public boolean equals(final Object o) { | |
| return super.equals(o); | |
| } | |
| @Override | |
| public int hashCode() { | |
| return super.hashCode(); | |
| } | |
| } | |
| } | |
| public static void main(final String[] args) throws URISyntaxException { | |
| // | |
| final String name = getName(getClass(FileSystems.getDefault())); | |
| // | |
| System.out.println(name); | |
| // | |
| Iterable<File> files = null; | |
| // | |
| if (Objects.equals(name, "sun.nio.fs.WindowsFileSystem")) { | |
| // | |
| final IOFileFilter ioFileFilter = TrueFileFilter.INSTANCE; | |
| // | |
| files = testAndApply(x -> and(x, GetFontFilePaths::exists, GetFontFilePaths::isDirectory), | |
| toFile(testAndApply(Objects::nonNull, Shell32Util.getKnownFolderPath(KnownFolders.FOLDERID_Fonts), | |
| Path::of, null)), | |
| x -> FileUtils.listFiles(x, ioFileFilter, ioFileFilter), null); | |
| // | |
| } else if (Objects.equals(name, "sun.nio.fs.MacOSXFileSystem")) { | |
| // | |
| files = CTFontManagerCopyAvailableFontURLs(); | |
| // | |
| } else if (Objects.equals(name, "sun.nio.fs.LinuxFileSystem")) { | |
| // | |
| files = FcFontList(); | |
| // | |
| } // if | |
| // | |
| System.out.println(files); | |
| // | |
| } | |
| private static Iterable<File> FcFontList() { | |
| // | |
| if (!Objects.equals(getName(getClass(FileSystems.getDefault())), "sun.nio.fs.LinuxFileSystem")) { | |
| // | |
| return null; | |
| // | |
| } // if | |
| // | |
| Collection<File> collection = null; | |
| // | |
| final FontConfig fc = Native.load("fontconfig", FontConfig.class); | |
| // | |
| Pointer fsPtr = null; | |
| // | |
| try { | |
| // | |
| if (fc != null) { | |
| // | |
| fsPtr = fc.FcFontList(fc.FcInitLoadConfigAndFonts(), fc.FcPatternCreate(), | |
| fc.FcObjectSetBuild("family", "style", "lang", "file", null)); | |
| // | |
| } // if | |
| // | |
| final FontConfig.FcFontSet fontSet = new FontConfig.FcFontSet(fsPtr); | |
| // | |
| fontSet.read(); | |
| // | |
| PointerByReference fileRef = null; | |
| // | |
| File file = null; | |
| // | |
| for (int i = 0; i < fontSet.nfont; i++) { | |
| // | |
| if (FontConfig.FcPatternGetString(fc, getPointer(fontSet.fonts, i * Native.POINTER_SIZE), "file", 0, | |
| fileRef = new PointerByReference()) == 0 | |
| && exists(file = testAndApply(Objects::nonNull, getString(fileRef.getValue(), 0), File::new, | |
| null)) | |
| && isFile(file)) { | |
| // | |
| add(collection = ObjectUtils.getIfNull(collection, ArrayList::new), file); | |
| // | |
| } // if | |
| // | |
| } // for | |
| // | |
| } finally { | |
| // | |
| FontConfig.FcFontSetDestroy(fc, fsPtr); | |
| // | |
| } // try | |
| // | |
| return collection; | |
| // | |
| } | |
| private static boolean isFile(final File instance) { | |
| return instance != null && instance.isFile(); | |
| } | |
| private static String getString(final Pointer instance, final long offset) { | |
| return instance != null ? instance.getString(offset) : null; | |
| } | |
| private static Pointer getPointer(final Pointer instance, final long offset) { | |
| return instance != null ? instance.getPointer(offset) : null; | |
| } | |
| private static Iterable<File> CTFontManagerCopyAvailableFontURLs() throws URISyntaxException { | |
| // | |
| if (!Objects.equals(getName(getClass(FileSystems.getDefault())), "sun.nio.fs.MacOSXFileSystem")) { | |
| // | |
| return null; | |
| // | |
| } // if | |
| // | |
| List<File> list = null; | |
| // | |
| final CoreFoundation coreFoundation = Native.load("CoreFoundation", CoreFoundation.class); | |
| // | |
| Pointer ctFontManagerCopyAvailableFontURLs = null; | |
| // | |
| try { | |
| // | |
| if ((ctFontManagerCopyAvailableFontURLs = CoreText | |
| .CTFontManagerCopyAvailableFontURLs(Native.load("CoreText", CoreText.class))) != null | |
| && coreFoundation != null) { | |
| // | |
| final long cfArrayGetCount = coreFoundation.CFArrayGetCount(ctFontManagerCopyAvailableFontURLs); | |
| // | |
| for (long i = 0; i < cfArrayGetCount; i++) { | |
| // | |
| add(list = ObjectUtils.getIfNull(list, ArrayList::new), | |
| testAndApply(Objects::nonNull, | |
| getPath(testAndApply(Objects::nonNull, | |
| cfStringToString(coreFoundation, | |
| coreFoundation.CFURLGetString(coreFoundation.CFArrayGetValueAtIndex( | |
| ctFontManagerCopyAvailableFontURLs, i))), | |
| URI::new, null)), | |
| File::new, null)); | |
| // | |
| } // for | |
| // | |
| } // if | |
| // | |
| } finally { | |
| // | |
| CoreFoundation.CFRelease(coreFoundation, ctFontManagerCopyAvailableFontURLs); | |
| // | |
| } // try | |
| // | |
| return list; | |
| // | |
| } | |
| private static <E> void add(final Collection<E> items, final E item) { | |
| if (items != null) { | |
| items.add(item); | |
| } | |
| } | |
| private static String getPath(final URI instance) { | |
| return instance != null ? instance.getPath() : null; | |
| } | |
| private static String cfStringToString(final CoreFoundation coreFoundation, final Pointer cfStr) { | |
| // | |
| if (cfStr == null) { | |
| // | |
| return null; | |
| // | |
| } // if | |
| // | |
| final int kCFStringEncodingUTF8 = 0x08000100; | |
| // | |
| final long length = coreFoundation != null ? coreFoundation.CFStringGetLength(cfStr) : 0; | |
| // | |
| final long maxSize = (coreFoundation != null | |
| ? coreFoundation.CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) | |
| : 0) + 1; | |
| // | |
| try (final Memory buffer = new Memory(maxSize)) { | |
| // | |
| if (coreFoundation != null | |
| && coreFoundation.CFStringGetCString(cfStr, buffer, maxSize, kCFStringEncodingUTF8)) { | |
| // | |
| return buffer.getString(0, "UTF-8"); | |
| // | |
| } // if | |
| // | |
| } // try | |
| // | |
| return null; | |
| // | |
| } | |
| private static <T> boolean and(final T value, final Predicate<T> a, final Predicate<T> b) { | |
| return test(a, value) && test(b, value); | |
| } | |
| private static boolean isDirectory(final File instance) { | |
| // | |
| if (instance == null || instance.getPath() == null) { | |
| // | |
| return false; | |
| // | |
| } // if | |
| // | |
| return instance.isDirectory(); | |
| // | |
| } | |
| private static boolean exists(final File instance) { | |
| return instance != null && instance.exists(); | |
| } | |
| private static File toFile(final Path instance) { | |
| return instance != null ? instance.toFile() : null; | |
| } | |
| private static <T, R, E extends Exception> R testAndApply(final Predicate<T> predicate, final T value, | |
| final FailableFunction<T, R, E> functionTrue, final FailableFunction<T, R, E> functionFalse) throws E { | |
| return test(predicate, value) ? apply(functionTrue, value) : apply(functionFalse, value); | |
| } | |
| private static final <T> boolean test(final Predicate<T> instance, final T value) { | |
| return instance != null && instance.test(value); | |
| } | |
| private static <T, R, E extends Throwable> R apply(final FailableFunction<T, R, E> instance, final T value) | |
| throws E { | |
| return instance != null ? instance.apply(value) : null; | |
| } | |
| private static String getName(final Class<?> instance) { | |
| return instance != null ? instance.getName() : null; | |
| } | |
| private static Class<?> getClass(final Object instance) { | |
| return instance != null ? instance.getClass() : null; | |
| } | |
| } |
Author
asdf913
commented
Mar 6, 2026
| MacOSX | CTFontManagerCopyAvailableFontURLs() | Apple Developer Documentation |
|---|---|
| Linux | Fontconfig Developers Reference, Version 2.17.1 |
| Microsoft Windows | SHGetKnownFolderPath function (shlobj_core.h) - Win32 apps | Microsoft Learn |
Author
<dependencies> <!-- https://mvnrepository.com/artifact/net.java.dev.jna/jna-platform --> <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna-platform</artifactId> <version>5.18.1</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.21.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.20.0</version> </dependency> <!--https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-collections4</artifactId> <version>4.5.0</version> </dependency> </dependencies>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment