@WorkerThread
  private static LottieResult<LottieComposition> fromZipStreamSyncInternal(@Nullable Context context, ZipInputStream inputStream,
      @Nullable String cacheKey) {
    LottieComposition composition = null;
    Map<String, Bitmap> images = new HashMap<>();
    Map<String, Typeface> fonts = new HashMap<>();

    try {
      final LottieComposition cachedComposition = cacheKey == null ? null : LottieCompositionCache.getInstance().get(cacheKey);
      if (cachedComposition != null) {
        return new LottieResult<>(cachedComposition);
      }
      ZipEntry entry = inputStream.getNextEntry();
      while (entry != null) {
        final String entryName = entry.getName();
        if (entryName.contains("__MACOSX")) {
          inputStream.closeEntry();
        } else if (entry.getName().equalsIgnoreCase("manifest.json")) { //ignore .lottie manifest
          inputStream.closeEntry();
        } else if (entry.getName().contains(".json")) {
          JsonReader reader = JsonReader.of(buffer(source(inputStream)));
          composition = LottieCompositionFactory.fromJsonReaderSyncInternal(reader, null, false).getValue();
        } else if (entryName.contains(".png") || entryName.contains(".webp") || entryName.contains(".jpg") || entryName.contains(".jpeg")) {
          String[] splitName = entryName.split("/");
          String name = splitName[splitName.length - 1];
          images.put(name, BitmapFactory.decodeStream(inputStream));
        } else if (entryName.contains(".ttf") || entryName.contains(".otf")) {
          String[] splitName = entryName.split("/");
          String fileName = splitName[splitName.length - 1];
          String fontFamily = fileName.split("\\.")[0];

          if (context == null) {
            return new LottieResult<>(
                new IllegalStateException("Unable to extract font " + fontFamily + " please pass a non-null Context parameter"));
          }

          File tempFile = new File(context.getCacheDir(), fileName);
          try (FileOutputStream fos = new FileOutputStream(tempFile)) {
            try (OutputStream output = new FileOutputStream(tempFile)) {
              byte[] buffer = new byte[4 * 1024];
              int read;
              while ((read = inputStream.read(buffer)) != -1) {
                output.write(buffer, 0, read);
              }
              output.flush();
            }
          } catch (Throwable e) {
            Logger.warning("Unable to save font " + fontFamily + " to the temporary file: " + fileName + ". ", e);
          }
          Typeface typeface = Typeface.createFromFile(tempFile);
          if (!tempFile.delete()) {
            Logger.warning("Failed to delete temp font file " + tempFile.getAbsolutePath() + ".");
          }
          fonts.put(fontFamily, typeface);
        } else {
          inputStream.closeEntry();
        }

        entry = inputStream.getNextEntry();
      }
    } catch (IOException e) {
      return new LottieResult<>(e);
    }


    if (composition == null) {
      return new LottieResult<>(new IllegalArgumentException("Unable to parse composition"));
    }

    for (Map.Entry<String, Bitmap> e : images.entrySet()) {
      LottieImageAsset imageAsset = findImageAssetForFileName(composition, e.getKey());
      if (imageAsset != null) {
        imageAsset.setBitmap(Utils.resizeBitmapIfNeeded(e.getValue(), imageAsset.getWidth(), imageAsset.getHeight()));
      }
    }

    for (Map.Entry<String, Typeface> e : fonts.entrySet()) {
      boolean found = false;
      for (Font font : composition.getFonts().values()) {
        if (font.getFamily().equals(e.getKey())) {
          found = true;
          font.setTypeface(e.getValue());
        }
      }
      if (!found) {
        Logger.warning("Parsed font for " + e.getKey() + " however it was not found in the animation.");
      }
    }

    if (images.isEmpty()) {
      for (Map.Entry<String, LottieImageAsset> entry : composition.getImages().entrySet()) {
        LottieImageAsset asset = entry.getValue();
        if (asset == null) {
          return null;
        }
        String filename = asset.getFileName();
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inScaled = true;
        opts.inDensity = 160;

        if (filename.startsWith("data:") && filename.indexOf("base64,") > 0) {
          // Contents look like a base64 data URI, with the format data:image/png;base64,<data>.
          byte[] data;
          try {
            data = Base64.decode(filename.substring(filename.indexOf(',') + 1), Base64.DEFAULT);
          } catch (IllegalArgumentException e) {
            Logger.warning("data URL did not have correct base64 format.", e);
            return null;
          }
          Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length, opts);
          if (bitmap != null) {
            bitmap = Utils.resizeBitmapIfNeeded(bitmap, asset.getWidth(), asset.getHeight());
            asset.setBitmap(bitmap);
          }
        }
      }
    }

    if (cacheKey != null) {
      LottieCompositionCache.getInstance().put(cacheKey, composition);
    }
    return new LottieResult<>(composition);
  }
Parses a zip input stream into a Lottie composition.
Your zip file should just be a folder with your json file and images zipped together.
It will automatically store and configure any images inside the animation if they exist.

@param context is optional and only needed if your zip file contains ttf or otf fonts. If yours doesn't, you may pass null.
               Embedded fonts may be .ttf or .otf files, can be in subdirectories, but must have the same name as the
               font family (fFamily) in your animation file.
lottie/src/main/java/com/airbnb/lottie/LottieCompositionFactory.java