Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for gzipped json files #2435

Merged
merged 5 commits into from
Dec 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
.idea/androidTestResultsUserPreferences.xml
.idea/appInsightsSettings.xml
.idea/migrations.xml
.idea/deploymentTargetSelector.xml

# Gradle
.idea/**/gradle.xml
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import android.graphics.BitmapFactory;
import android.graphics.Typeface;
import android.util.Base64;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.annotation.RawRes;
Expand Down Expand Up @@ -41,7 +42,7 @@
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

Expand All @@ -57,6 +58,7 @@
*/
@SuppressWarnings({"WeakerAccess", "unused", "NullAway"})
public class LottieCompositionFactory {

/**
* Keep a map of cache keys to in-progress tasks and return them for new requests.
* Without this, simultaneous requests to parse a composition will trigger multiple parallel
Expand All @@ -69,7 +71,8 @@ public class LottieCompositionFactory {
* reference magic bytes for zip compressed files.
* useful to determine if an InputStream is a zip file or not
*/
private static final byte[] MAGIC = new byte[]{0x50, 0x4b, 0x03, 0x04};
private static final byte[] ZIP_MAGIC = new byte[]{0x50, 0x4b, 0x03, 0x04};
private static final byte[] GZIP_MAGIC = new byte[]{0x1f, (byte) 0x8b, 0x08};


private LottieCompositionFactory() {
Expand Down Expand Up @@ -222,10 +225,13 @@ public static LottieResult<LottieComposition> fromAssetSync(Context context, Str
return new LottieResult<>(cachedComposition);
}
try {
if (fileName.endsWith(".zip") || fileName.endsWith(".lottie")) {
return fromZipStreamSync(context, new ZipInputStream(context.getAssets().open(fileName)), cacheKey);
BufferedSource source = Okio.buffer(source(context.getAssets().open(fileName)));
if (isZipCompressed(source)) {
return fromZipStreamSync(context, new ZipInputStream(source.inputStream()), cacheKey);
} else if (isGzipCompressed(source)) {
return fromJsonInputStreamSync(new GZIPInputStream(source.inputStream()), cacheKey);
}
return fromJsonInputStreamSync(context.getAssets().open(fileName), cacheKey);
return fromJsonInputStreamSync(source.inputStream(), cacheKey);
} catch (IOException e) {
return new LottieResult<>(e);
}
Expand Down Expand Up @@ -298,6 +304,13 @@ public static LottieResult<LottieComposition> fromRawResSync(Context context, @R
BufferedSource source = Okio.buffer(source(context.getResources().openRawResource(rawRes)));
if (isZipCompressed(source)) {
return fromZipStreamSync(context, new ZipInputStream(source.inputStream()), cacheKey);
} else if (isGzipCompressed(source)) {
try {
return fromJsonInputStreamSync(new GZIPInputStream(source.inputStream()), cacheKey);
} catch (IOException e) {
// This shouldn't happen because we check the header for magic bytes.
return new LottieResult<>(e);
}
}
return fromJsonInputStreamSync(source.inputStream(), cacheKey);
} catch (Resources.NotFoundException e) {
Expand Down Expand Up @@ -402,7 +415,8 @@ public static LottieResult<LottieComposition> fromJsonReaderSync(com.airbnb.lott
}

@WorkerThread
public static LottieResult<LottieComposition> fromJsonReaderSync(com.airbnb.lottie.parser.moshi.JsonReader reader, @Nullable String cacheKey, boolean close) {
public static LottieResult<LottieComposition> fromJsonReaderSync(com.airbnb.lottie.parser.moshi.JsonReader reader, @Nullable String cacheKey,
boolean close) {
return fromJsonReaderSyncInternal(reader, cacheKey, close);
}

Expand Down Expand Up @@ -641,9 +655,20 @@ private static LottieResult<LottieComposition> fromZipStreamSyncInternal(Context
* Check if a given InputStream points to a .zip compressed file
*/
private static Boolean isZipCompressed(BufferedSource inputSource) {
return matchesMagicBytes(inputSource, ZIP_MAGIC);
}

/**
* Check if a given InputStream points to a .gzip compressed file
*/
private static Boolean isGzipCompressed(BufferedSource inputSource) {
return matchesMagicBytes(inputSource, GZIP_MAGIC);
}

private static Boolean matchesMagicBytes(BufferedSource inputSource, byte[] magic) {
try {
BufferedSource peek = inputSource.peek();
for (byte b : MAGIC) {
for (byte b : magic) {
if (peek.readByte() != b) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class AssetsTestCase : SnapshotTestCase {
listAssets(assets, pathWithPrefix)
return@forEach
}
if (!animation.endsWith(".json") && !animation.endsWith(".zip")) return@forEach
if (!animation.endsWith(".json") && !animation.endsWith(".zip") && !animation.endsWith(".tgs")) return@forEach
assets += pathWithPrefix
}
return assets
Expand All @@ -47,4 +47,4 @@ class AssetsTestCase : SnapshotTestCase {
send(asset to composition)
}
}
}
}
Binary file added snapshot-tests/src/main/assets/Tests/winners.tgs
Binary file not shown.