public static void unzip(InputStream input, Path destDir) {
    long totalSizeArchive = 0;
    int totalEntryArchive = 0;
    try (var zip = new ZipInputStream(input)) {
      ZipEntry entry;
      while ((entry = zip.getNextEntry()) != null) {
        Path targetDirResolved = destDir.resolve(entry.getName());
        Path destination = targetDirResolved.normalize();
        if (!destination.startsWith(destDir)) {
          throw new IOException("Bad zip entry: " + entry.getName());
        }
        if (entry.isDirectory()) {
          FileUtils.createDirectory(destDir);
        } else {
          createParentDirectories(destination);

          // Instead of Files.copy, read 2kB at a time to prevent zip bomb attack, see https://rules.sonarsource.com/java/RSPEC-5042
          int nBytes;
          byte[] buffer = new byte[2048];
          int totalSizeEntry = 0;

          try (
            var out = Files.newOutputStream(destination, StandardOpenOption.CREATE_NEW,
              WRITE)
          ) {
            totalEntryArchive++;
            while ((nBytes = zip.read(buffer)) > 0) {
              out.write(buffer, 0, nBytes);
              totalSizeEntry += nBytes;
              totalSizeArchive += nBytes;

              double compressionRatio = totalSizeEntry * 1d / entry.getCompressedSize();
              if (compressionRatio > ZIP_THRESHOLD_RATIO) {
                throw new IOException(
                  "Ratio between compressed and uncompressed data is highly suspicious " +
                    FORMAT.numeric(compressionRatio) +
                    "x, looks like a Zip Bomb Attack");
              }
            }

            if (totalSizeArchive > ZIP_THRESHOLD_SIZE) {
              throw new IOException("The uncompressed data size " + FORMAT.storage(totalSizeArchive) +
                "B is too much for the application resource capacity");
            }

            if (totalEntryArchive > ZIP_THRESHOLD_ENTRIES) {
              throw new IOException("Too many entries in this archive " + FORMAT.integer(totalEntryArchive) +
                ", can lead to inodes exhaustion of the system");
            }
          }
        }
      }
    } catch (IOException e) {
      throw new UncheckedIOException(e);
    }
  }
Unzips a zip file from an input stream to {@code destDir}.

@throws UncheckedIOException if an IO exception occurs
planetiler-core/src/main/java/com/onthegomap/planetiler/util/FileUtils.java