Skip to content

Instantly share code, notes, and snippets.

@asdf913
Created March 6, 2026 21:46
Show Gist options
  • Select an option

  • Save asdf913/106e9b1e1c4c315e73e691ac22d5eced to your computer and use it in GitHub Desktop.

Select an option

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.
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;
}
}
@asdf913
Copy link
Author

asdf913 commented Mar 6, 2026

<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