[Android] Prevent sending group of folder lists with null items from the ML to the app

Nicolas Pomepuy git at videolan.org
Fri Sep 11 07:09:29 UTC 2026


vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Tue May 13 14:21:19 2025 +0200| [b2f5a272616a77f5b06eaf5d75c375a0120f8202] | committer: Nicolas Pomepuy

Prevent sending group of folder lists with null items from the ML to the app

> https://code.videolan.org/videolan/vlc-android/commit/b2f5a272616a77f5b06eaf5d75c375a0120f8202
---

 .../videolan/medialibrary/MedialibraryImpl.java    |  4 +--
 .../src/org/videolan/medialibrary/Tools.java       | 26 ++++++++++++++++
 .../test/org/videolan/medialibrary/ToolsTest.java  | 36 ++++++++++++++++++++--
 3 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/medialibrary/src/org/videolan/medialibrary/MedialibraryImpl.java b/medialibrary/src/org/videolan/medialibrary/MedialibraryImpl.java
index beae616148..157866fd8a 100644
--- a/medialibrary/src/org/videolan/medialibrary/MedialibraryImpl.java
+++ b/medialibrary/src/org/videolan/medialibrary/MedialibraryImpl.java
@@ -240,7 +240,7 @@ public class MedialibraryImpl extends Medialibrary {
     @Override
     @WorkerThread
     public VideoGroup[] getVideoGroups(int sort, boolean desc, boolean includeMissing, boolean onlyFavorites, int nbItems, int offset) {
-        return mIsInitiated ? nativeGetVideoGroups(sort, desc, includeMissing, onlyFavorites, nbItems, offset) : new VideoGroup[0];
+        return mIsInitiated ? Tools.cleanupArray(nativeGetVideoGroups(sort, desc, includeMissing, onlyFavorites, nbItems, offset)) : new VideoGroup[0];
     }
 
     @Override
@@ -483,7 +483,7 @@ public class MedialibraryImpl extends Medialibrary {
     @NonNull
     @WorkerThread
     public Folder[] getFolders(int type, int sort, boolean desc, boolean includeMissing, boolean onlyFavorites, int nbItems, int offset) {
-        return mIsInitiated ? nativeGetFolders(type, sort, desc, includeMissing, onlyFavorites, nbItems, offset) : new Folder[0];
+        return mIsInitiated ? Tools.cleanupArray(nativeGetFolders(type, sort, desc, includeMissing, onlyFavorites, nbItems, offset)) : new Folder[0];
     }
 
     @Override
diff --git a/medialibrary/src/org/videolan/medialibrary/Tools.java b/medialibrary/src/org/videolan/medialibrary/Tools.java
index 6b7c0cb136..800dc01d4d 100644
--- a/medialibrary/src/org/videolan/medialibrary/Tools.java
+++ b/medialibrary/src/org/videolan/medialibrary/Tools.java
@@ -13,6 +13,7 @@ import org.videolan.medialibrary.media.MediaLibraryItem;
 
 import java.text.DecimalFormat;
 import java.text.NumberFormat;
+import java.util.Arrays;
 import java.util.Locale;
 import java.util.regex.Pattern;
 
@@ -161,4 +162,29 @@ public class Tools {
     public static Boolean hasSubString(String source, String substring) {
         return Pattern.compile(Pattern.quote(substring), Pattern.CASE_INSENSITIVE).matcher(source).find();
     }
+
+    /**
+     * Removes null items from an array.
+     * This method is optimized to avoid allocations if the array is already "clean"
+     * and handles empty or null input safely.
+     *
+     * @param source The source array to clean
+     * @param <T> The type of the array elements
+     * @return A new array without nulls, or the original array if it was already clean or null/empty.
+     */
+    public static <T> T[] cleanupArray(T[] source) {
+        if (source == null || source.length == 0) return source;
+        int count = 0;
+        // Count non-null items first to determine the final size
+        for (T s : source) if (s != null) count++;
+        // If the array is already clean, return it as-is to save an allocation
+        if (count == source.length) return source;
+        // Create a new array of the same type and proper size
+        T[] result = Arrays.copyOf(source, count);
+        if (count == 0) return result;
+        int i = 0;
+        // Fill the new array with non-null items
+        for (T s : source) if (s != null) result[i++] = s;
+        return result;
+    }
 }
diff --git a/medialibrary/test/org/videolan/medialibrary/ToolsTest.java b/medialibrary/test/org/videolan/medialibrary/ToolsTest.java
index 7e3a41400a..bb5955ab13 100644
--- a/medialibrary/test/org/videolan/medialibrary/ToolsTest.java
+++ b/medialibrary/test/org/videolan/medialibrary/ToolsTest.java
@@ -1,6 +1,12 @@
 package org.videolan.medialibrary;
 
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
 import org.junit.Test;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ExecutionException;
@@ -8,7 +14,6 @@ import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
-import static org.junit.Assert.assertEquals;
 
 public class ToolsTest {
 
@@ -56,4 +61,31 @@ public class ToolsTest {
         exec.awaitTermination(10, TimeUnit.SECONDS);
     }
 
-}
\ No newline at end of file
+    @Test
+    public void testCleanupArray() {
+        // Test with null
+        assertNull(Tools.cleanupArray(null));
+
+        // Test with empty array
+        String[] empty = new String[0];
+        assertSame(empty, Tools.cleanupArray(empty));
+
+        // Test with no nulls - should return same instance
+        String[] noNulls = {"a", "b", "c"};
+        assertSame(noNulls, Tools.cleanupArray(noNulls));
+
+        // Test with mixed nulls
+        String[] mixed = {"a", null, "b", null, "c"};
+        String[] expectedMixed = {"a", "b", "c"};
+        assertArrayEquals(expectedMixed, Tools.cleanupArray(mixed));
+
+        // Test with only nulls
+        String[] onlyNulls = {null, null};
+        assertEquals(0, Tools.cleanupArray(onlyNulls).length);
+
+        // Test with different types to ensure reflection works
+        Integer[] ints = {1, null, 2};
+        Integer[] expectedInts = {1, 2};
+        assertArrayEquals(expectedInts, Tools.cleanupArray(ints));
+    }
+}



More information about the Android mailing list