package org.asamk.signal.manager.util; import com.fasterxml.jackson.databind.ObjectMapper; import org.asamk.signal.manager.api.Pair; import org.asamk.signal.manager.api.StickerPackInvalidException; import org.asamk.signal.manager.storage.stickerPacks.JsonStickerPack; import org.whispersystems.signalservice.api.messages.SignalServiceStickerManifestUpload; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.Optional; import java.util.zip.ZipFile; public class StickerUtils { public static SignalServiceStickerManifestUpload getSignalServiceStickerManifestUpload( final File file ) throws IOException, StickerPackInvalidException { ZipFile zip = null; String rootPath = null; if (file.getName().endsWith(".zip")) { zip = new ZipFile(file); } else if (file.getName().equals("manifest.json")) { rootPath = file.getParent(); } else { throw new StickerPackInvalidException("Could not find manifest.json"); } var pack = parseStickerPack(rootPath, zip); if (pack.stickers() == null) { throw new StickerPackInvalidException("Must set a 'stickers' field."); } if (pack.stickers().isEmpty()) { throw new StickerPackInvalidException("Must include stickers."); } var stickers = new ArrayList(pack.stickers().size()); for (var sticker : pack.stickers()) { if (sticker.file() == null) { throw new StickerPackInvalidException("Must set a 'file' field on each sticker."); } Pair data; try { data = getInputStreamAndLength(rootPath, zip, sticker.file()); } catch (IOException ignored) { throw new StickerPackInvalidException("Could not find find " + sticker.file()); } var contentType = sticker.contentType() != null && !sticker.contentType().isEmpty() ? sticker.contentType() : getContentType(rootPath, zip, sticker.file()); var stickerInfo = new SignalServiceStickerManifestUpload.StickerInfo(data.first(), data.second(), Optional.ofNullable(sticker.emoji()).orElse(""), contentType); stickers.add(stickerInfo); } SignalServiceStickerManifestUpload.StickerInfo cover = null; if (pack.cover() != null) { if (pack.cover().file() == null) { throw new StickerPackInvalidException("Must set a 'file' field on the cover."); } Pair data; try { data = getInputStreamAndLength(rootPath, zip, pack.cover().file()); } catch (IOException ignored) { throw new StickerPackInvalidException("Could not find find " + pack.cover().file()); } var contentType = pack.cover().contentType() != null && !pack.cover().contentType().isEmpty() ? pack.cover() .contentType() : getContentType(rootPath, zip, pack.cover().file()); cover = new SignalServiceStickerManifestUpload.StickerInfo(data.first(), data.second(), Optional.ofNullable(pack.cover().emoji()).orElse(""), contentType); } return new SignalServiceStickerManifestUpload(pack.title(), pack.author(), cover, stickers); } private static JsonStickerPack parseStickerPack(String rootPath, ZipFile zip) throws IOException { InputStream inputStream; if (zip != null) { inputStream = zip.getInputStream(zip.getEntry("manifest.json")); } else { inputStream = new FileInputStream((new File(rootPath, "manifest.json"))); } return new ObjectMapper().readValue(inputStream, JsonStickerPack.class); } private static Pair getInputStreamAndLength( final String rootPath, final ZipFile zip, final String subfile ) throws IOException { if (zip != null) { final var entry = zip.getEntry(subfile); return new Pair<>(zip.getInputStream(entry), entry.getSize()); } else { final var file = new File(rootPath, subfile); return new Pair<>(new FileInputStream(file), file.length()); } } private static String getContentType( final String rootPath, final ZipFile zip, final String subfile ) throws IOException { if (zip != null) { final var entry = zip.getEntry(subfile); try (InputStream bufferedStream = new BufferedInputStream(zip.getInputStream(entry))) { return MimeUtils.getStreamMimeType(bufferedStream).orElse(null); } } else { final var file = new File(rootPath, subfile); return MimeUtils.getFileMimeType(file).orElse(null); } } }