diff --git a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java index 783c0a29..de8f6c06 100644 --- a/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java +++ b/app/src/main/java/com/wireguard/android/fragment/TunnelListFragment.java @@ -43,8 +43,10 @@ import com.wireguard.android.widget.fab.FloatingActionsMenuRecyclerViewScrollLis import com.wireguard.config.Config; import com.wireguard.config.ParseException; +import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Collection; @@ -122,7 +124,8 @@ public class TunnelListFragment extends BaseFragment { throw new IllegalArgumentException("File must be .conf or .zip"); if (isZip) { - try (ZipInputStream zip = new ZipInputStream(contentResolver.openInputStream(uri))) { + try (ZipInputStream zip = new ZipInputStream(contentResolver.openInputStream(uri)); + BufferedReader reader = new BufferedReader(new InputStreamReader(zip))) { ZipEntry entry; while ((entry = zip.getNextEntry()) != null) { if (entry.isDirectory()) @@ -140,7 +143,7 @@ public class TunnelListFragment extends BaseFragment { continue; Config config = null; try { - config = Config.parse(zip); + config = Config.parse(reader); } catch (Exception e) { throwables.add(e); } diff --git a/app/src/main/java/com/wireguard/config/Config.java b/app/src/main/java/com/wireguard/config/Config.java index 7645583d..6c9d7ba3 100644 --- a/app/src/main/java/com/wireguard/config/Config.java +++ b/app/src/main/java/com/wireguard/config/Config.java @@ -43,50 +43,59 @@ public final class Config { * @return a {@code Config} instance representing the supplied configuration */ public static Config parse(final InputStream stream) throws IOException, ParseException { + return parse(new BufferedReader(new InputStreamReader(stream))); + } + + /** + * Parses an series of "Interface" and "Peer" sections into a {@code Config}. Throws + * {@link ParseException} if the input is not well-formed or contains unparseable sections. + * + * @param reader a BufferedReader of UTF-8 text that is interpreted as a WireGuard configuration file + * @return a {@code Config} instance representing the supplied configuration + */ + public static Config parse(final BufferedReader reader) throws IOException, ParseException { final Builder builder = new Builder(); - try (final BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) { - final Collection interfaceLines = new ArrayList<>(); - final Collection peerLines = new ArrayList<>(); - boolean inInterfaceSection = false; - boolean inPeerSection = false; - @Nullable String line; - while ((line = reader.readLine()) != null) { - final int commentIndex = line.indexOf('#'); - if (commentIndex != -1) - line = line.substring(0, commentIndex); - line = line.trim(); - if (line.isEmpty()) - continue; - if (line.startsWith("[")) { - // Consume all [Peer] lines read so far. - if (inPeerSection) { - builder.parsePeer(peerLines); - peerLines.clear(); - } - if ("[Interface]".equalsIgnoreCase(line)) { - inInterfaceSection = true; - inPeerSection = false; - } else if ("[Peer]".equalsIgnoreCase(line)) { - inInterfaceSection = false; - inPeerSection = true; - } else { - throw new ParseException("top level", line, "Unknown section name"); - } - } else if (inInterfaceSection) { - interfaceLines.add(line); - } else if (inPeerSection) { - peerLines.add(line); - } else { - throw new ParseException("top level", line, "Expected [Interface] or [Peer]"); + final Collection interfaceLines = new ArrayList<>(); + final Collection peerLines = new ArrayList<>(); + boolean inInterfaceSection = false; + boolean inPeerSection = false; + @Nullable String line; + while ((line = reader.readLine()) != null) { + final int commentIndex = line.indexOf('#'); + if (commentIndex != -1) + line = line.substring(0, commentIndex); + line = line.trim(); + if (line.isEmpty()) + continue; + if (line.startsWith("[")) { + // Consume all [Peer] lines read so far. + if (inPeerSection) { + builder.parsePeer(peerLines); + peerLines.clear(); } + if ("[Interface]".equalsIgnoreCase(line)) { + inInterfaceSection = true; + inPeerSection = false; + } else if ("[Peer]".equalsIgnoreCase(line)) { + inInterfaceSection = false; + inPeerSection = true; + } else { + throw new ParseException("top level", line, "Unknown section name"); + } + } else if (inInterfaceSection) { + interfaceLines.add(line); + } else if (inPeerSection) { + peerLines.add(line); + } else { + throw new ParseException("top level", line, "Expected [Interface] or [Peer]"); } - if (inPeerSection) - builder.parsePeer(peerLines); - else if (!inInterfaceSection) - throw new ParseException("top level", "", "Empty configuration"); - // Combine all [Interface] sections in the file. - builder.parseInterface(interfaceLines); } + if (inPeerSection) + builder.parsePeer(peerLines); + else if (!inInterfaceSection) + throw new ParseException("top level", "", "Empty configuration"); + // Combine all [Interface] sections in the file. + builder.parseInterface(interfaceLines); return builder.build(); }