From ddf94ae2ca9d4ec493eaab9bb01c639baffb7926 Mon Sep 17 00:00:00 2001 From: Emux Date: Mon, 22 Feb 2021 14:06:03 +0200 Subject: [PATCH] ZipXmlThemeResourceProvider: add method to just scan zip for xml themes (#807) --- .../oscim/android/test/MapsforgeActivity.java | 23 ++++---- .../ZipXmlThemeResourceProviderTest.java | 14 +++++ .../theme/ZipXmlThemeResourceProvider.java | 53 +++++++++++++++++-- 3 files changed, 75 insertions(+), 15 deletions(-) diff --git a/vtm-android-example/src/org/oscim/android/test/MapsforgeActivity.java b/vtm-android-example/src/org/oscim/android/test/MapsforgeActivity.java index f0adacbf..0f469237 100644 --- a/vtm-android-example/src/org/oscim/android/test/MapsforgeActivity.java +++ b/vtm-android-example/src/org/oscim/android/test/MapsforgeActivity.java @@ -238,10 +238,9 @@ public class MapsforgeActivity extends MapActivity { return; try { - Uri uri = data.getData(); + final Uri uri = data.getData(); - final ZipXmlThemeResourceProvider resourceProvider = new ZipXmlThemeResourceProvider(new ZipInputStream(new BufferedInputStream(getContentResolver().openInputStream(uri)))); - final List xmlThemes = resourceProvider.getXmlThemes(); + final List xmlThemes = ZipXmlThemeResourceProvider.scanXmlThemes(new ZipInputStream(new BufferedInputStream(getContentResolver().openInputStream(uri)))); if (xmlThemes.isEmpty()) return; @@ -250,13 +249,17 @@ public class MapsforgeActivity extends MapActivity { builder.setSingleChoiceItems(xmlThemes.toArray(new String[0]), -1, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - ThemeFile theme = new ZipRenderTheme(xmlThemes.get(which), resourceProvider); - if (mTheme != null) - mTheme.dispose(); - mTheme = mMap.setTheme(theme); - mapsforgeTheme(mTheme); - mMenu.findItem(R.id.theme_external_archive).setChecked(true); + try { + dialog.dismiss(); + ThemeFile theme = new ZipRenderTheme(xmlThemes.get(which), new ZipXmlThemeResourceProvider(new ZipInputStream(new BufferedInputStream(getContentResolver().openInputStream(uri))))); + if (mTheme != null) + mTheme.dispose(); + mTheme = mMap.setTheme(theme); + mapsforgeTheme(mTheme); + mMenu.findItem(R.id.theme_external_archive).setChecked(true); + } catch (IOException e) { + e.printStackTrace(); + } } }); builder.show(); diff --git a/vtm-tests/test/org/oscim/theme/ZipXmlThemeResourceProviderTest.java b/vtm-tests/test/org/oscim/theme/ZipXmlThemeResourceProviderTest.java index b1563781..1f3aa065 100644 --- a/vtm-tests/test/org/oscim/theme/ZipXmlThemeResourceProviderTest.java +++ b/vtm-tests/test/org/oscim/theme/ZipXmlThemeResourceProviderTest.java @@ -83,4 +83,18 @@ public class ZipXmlThemeResourceProviderTest { public void openEmpty() throws IOException { Assert.assertTrue(new ZipXmlThemeResourceProvider(null).getXmlThemes().isEmpty()); } + + @Test + public void scanZipForXmlThemes() throws IOException { + ZipInputStream zis = new ZipInputStream(new BufferedInputStream(ZipXmlThemeResourceProviderTest.class.getResourceAsStream("/xmlthemetest.zip"))); + Assert.assertNotNull(zis); + + List xmlThemes = ZipXmlThemeResourceProvider.scanXmlThemes(zis); + + Assert.assertEquals(4, xmlThemes.size()); + Assert.assertTrue(xmlThemes.contains("one.xml")); + Assert.assertTrue(xmlThemes.contains("two.xml")); + Assert.assertTrue(xmlThemes.contains("res/three.xml")); + Assert.assertTrue(xmlThemes.contains("res/sub/four.xml")); + } } diff --git a/vtm/src/org/oscim/theme/ZipXmlThemeResourceProvider.java b/vtm/src/org/oscim/theme/ZipXmlThemeResourceProvider.java index 94dddbda..aaed1399 100644 --- a/vtm/src/org/oscim/theme/ZipXmlThemeResourceProvider.java +++ b/vtm/src/org/oscim/theme/ZipXmlThemeResourceProvider.java @@ -60,12 +60,9 @@ public class ZipXmlThemeResourceProvider implements XmlThemeResourceProvider { continue; } byte[] entry = streamToBytes(zipInputStream, (int) zipEntry.getSize()); - String fileName = zipEntry.getName(); - if (fileName.startsWith("/")) { - fileName = fileName.substring(1); - } + String fileName = zipEntryName(zipEntry.getName()); files.put(fileName, entry); - if (fileName.toLowerCase(Locale.ROOT).endsWith(".xml")) { + if (isXmlTheme(fileName)) { xmlThemes.add(fileName); } } @@ -112,6 +109,45 @@ public class ZipXmlThemeResourceProvider implements XmlThemeResourceProvider { return xmlThemes; } + private static boolean isXmlTheme(String fileName) { + return fileName.toLowerCase(Locale.ROOT).endsWith(".xml"); + } + + /** + * Scans a given zip stream for contained xml themes without actually reading and storing its content in memory. + *

+ * This method is useful to find out which xml themes are available across multiple zip files + * without actually have to read them all into memory. + * + * @param zipInputStream zip stream to read resources from + * @return the XML theme paths in the archive + * @throws IOException if a problem occurs reading the stream + */ + public static List scanXmlThemes(ZipInputStream zipInputStream) throws IOException { + if (zipInputStream == null) { + return Collections.emptyList(); + } + + List xmlThemes = new ArrayList<>(); + + try { + ZipEntry zipEntry; + while ((zipEntry = zipInputStream.getNextEntry()) != null) { + if (zipEntry.isDirectory()) { + continue; + } + String fileName = zipEntryName(zipEntry.getName()); + if (isXmlTheme(fileName)) { + xmlThemes.add(fileName); + } + } + } finally { + IOUtils.closeQuietly(zipInputStream); + } + + return xmlThemes; + } + private static byte[] streamToBytes(InputStream in, int size) throws IOException { byte[] bytes = new byte[size]; int count, offset = 0; @@ -121,4 +157,11 @@ public class ZipXmlThemeResourceProvider implements XmlThemeResourceProvider { } return bytes; } + + private static String zipEntryName(String name) { + if (name.startsWith("/")) { + return name.substring(1); + } + return name; + } }