From 674f6e236132c4e2c5876459ef707da2413e72b2 Mon Sep 17 00:00:00 2001 From: Matt Morley Date: Sat, 6 Dec 2025 13:51:14 -0800 Subject: [PATCH] [NFC] Kill stupid while loop copy in PhotonJNICommon (#2219) ## Description We can avoid copying files by chunks just using `Files.copy`. This should be NFC, just makes the code cleaner ## Meta Merge checklist: - [x] Pull Request title is [short, imperative summary](https://cbea.ms/git-commit/) of proposed changes - [ ] The description documents the _what_ and _why_ - [ ] If this PR changes behavior or adds a feature, user documentation is updated - [ ] If this PR touches photon-serde, all messages have been regenerated and hashes have not changed unexpectedly - [ ] If this PR touches configuration, this is backwards compatible with settings back to v2025.3.2 - [ ] If this PR touches pipeline settings or anything related to data exchange, the frontend typing is updated - [ ] If this PR addresses a bug, a regression test for it is added --- .../org/photonvision/jni/PhotonJNICommon.java | 51 ++++++++----------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/photon-core/src/main/java/org/photonvision/jni/PhotonJNICommon.java b/photon-core/src/main/java/org/photonvision/jni/PhotonJNICommon.java index 1938cdee1..d9807f979 100644 --- a/photon-core/src/main/java/org/photonvision/jni/PhotonJNICommon.java +++ b/photon-core/src/main/java/org/photonvision/jni/PhotonJNICommon.java @@ -17,9 +17,9 @@ package org.photonvision.jni; -import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; import java.util.List; import org.photonvision.common.hardware.Platform; import org.photonvision.common.logging.LogGroup; @@ -35,42 +35,35 @@ public abstract class PhotonJNICommon { protected static synchronized void forceLoad( PhotonJNICommon instance, Class clazz, List libraries) throws IOException { if (instance.isLoaded()) return; - if (logger == null) logger = new Logger(clazz, LogGroup.Camera); + if (logger == null) logger = new Logger(clazz, LogGroup.General); for (var libraryName : libraries) { - try { - // We always extract the shared object (we could hash each so, but that's a lot of work) - var arch_name = Platform.getNativeLibraryFolderName(); - var nativeLibName = System.mapLibraryName(libraryName); - var in = clazz.getResourceAsStream("/nativelibraries/" + arch_name + "/" + nativeLibName); - + logger.info("Loading " + libraryName); + // We always extract the shared object (we could hash each so, but that's a lot + // of work) + var arch_name = Platform.getNativeLibraryFolderName(); + var nativeLibName = System.mapLibraryName(libraryName); + try (var in = + clazz.getResourceAsStream("/nativelibraries/" + arch_name + "/" + nativeLibName)) { if (in == null) { + logger.error("Could not find " + libraryName); instance.setLoaded(false); return; } - // It's important that we don't mangle the names of these files on Windows at least - File temp = new File(System.getProperty("java.io.tmpdir"), nativeLibName); - FileOutputStream fos = new FileOutputStream(temp); + // It's important that we don't mangle the names of these files + var temp = Files.createTempDirectory("nativeExtract").resolve(nativeLibName); + Files.copy(in, temp, StandardCopyOption.REPLACE_EXISTING); - int read = -1; - byte[] buffer = new byte[1024]; - while ((read = in.read(buffer)) != -1) { - fos.write(buffer, 0, read); + try { + System.load(temp.toAbsolutePath().toString()); + logger.info("Successfully loaded shared object " + temp.getFileName()); + } catch (UnsatisfiedLinkError e) { + logger.error("Couldn't load shared object " + libraryName, e); + e.printStackTrace(); + instance.setLoaded(false); + return; } - fos.close(); - in.close(); - - System.load(temp.getAbsolutePath()); - - logger.info("Successfully loaded shared object " + temp.getName()); - - } catch (UnsatisfiedLinkError e) { - logger.error("Couldn't load shared object " + libraryName, e); - e.printStackTrace(); - // logger.error(System.getProperty("java.library.path")); - instance.setLoaded(false); - return; } } instance.setLoaded(true);