1 /* 2 * Copyright 2022 Google LLC 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.android.libraries.mobiledatadownload.file.common.internal; 17 18 import android.net.Uri; 19 import android.text.TextUtils; 20 import com.google.common.base.Joiner; 21 import com.google.common.base.Splitter; 22 import com.google.common.collect.ImmutableList; 23 import java.util.List; 24 import java.util.regex.Matcher; 25 import java.util.regex.Pattern; 26 import javax.annotation.Nullable; 27 28 /** 29 * The fragment parser, unfortunately, is rather large in code size. This class provides some 30 * lighter utilities for accessing and manipulating the transform fragment param. It provides a 31 * strict subset of the functionality in {@link Fragment}. 32 * 33 * <p>In particular, it does not support 34 * 35 * <ul> 36 * <li>Encoded transform names. 37 * <li>Parsing transform params. 38 * </ul> 39 */ 40 public final class LiteTransformFragments { 41 42 private static final Pattern XFORM_NAME_PATTERN = Pattern.compile("(\\w+).*"); 43 private static final String XFORM_FRAGMENT_PREFIX = "transform="; 44 45 /** 46 * Parses URI fragment, returning the names of the transforms that are enabled. Has the following 47 * limitations: 48 * 49 * <ul> 50 * <li>Ignores subparams. To access those, use {@link Fragment} from your transform. 51 * <li>Requires the fragment start with "transform=". 52 * <li>Requires encoded transform name to contain only word chars (ie, \w). 53 * </ul> 54 */ parseTransformNames(Uri uri)55 public static ImmutableList<String> parseTransformNames(Uri uri) { 56 ImmutableList.Builder<String> builder = ImmutableList.builder(); 57 for (String spec : parseTransformSpecs(uri)) { 58 builder.add(parseSpecName(spec)); 59 } 60 return builder.build(); 61 } 62 63 /** 64 * Parses URI fragment, returning the transforms specs found. Has the following limitations: 65 * 66 * <ul> 67 * <li>Requires the fragment start with "transform=". 68 * </ul> 69 * 70 * @return List of encoded transform specs - eg "integrity(sha256=abc123)" 71 */ parseTransformSpecs(Uri uri)72 public static ImmutableList<String> parseTransformSpecs(Uri uri) { 73 String fragment = uri.getEncodedFragment(); 74 if (TextUtils.isEmpty(fragment) || !fragment.startsWith(XFORM_FRAGMENT_PREFIX)) { 75 return ImmutableList.of(); 76 } 77 String specs = fragment.substring(XFORM_FRAGMENT_PREFIX.length()); 78 return ImmutableList.copyOf(Splitter.on("+").omitEmptyStrings().split(specs)); 79 } 80 81 /** 82 * Parse the name from an encoded transform spec. For example, "integrity(sha256=abc123)" would 83 * return "integrity". Has the following limitations: 84 * 85 * <ul> 86 * <li>Ignores subparams. To access those, use {@link Fragment} from your transform. 87 * <li>Requires encoded transform name to contain only word chars (ie, \w). 88 * </ul> 89 */ parseSpecName(String encodedSpec)90 public static String parseSpecName(String encodedSpec) { 91 Matcher matcher = XFORM_NAME_PATTERN.matcher(encodedSpec); 92 if (!matcher.matches()) { 93 throw new IllegalArgumentException("Invalid fragment spec: " + encodedSpec); 94 } 95 return matcher.group(1); 96 } 97 98 /** 99 * Joins the encoded transform specs to produce an encoded transform fragment suitable for adding 100 * to a Uri with {@link Uri.Builder#encodedFragment}. 101 */ 102 @Nullable joinTransformSpecs(List<String> encodedSpecs)103 public static String joinTransformSpecs(List<String> encodedSpecs) { 104 if (encodedSpecs.isEmpty()) { 105 return null; 106 } 107 return XFORM_FRAGMENT_PREFIX + Joiner.on("+").join(encodedSpecs); 108 } 109 LiteTransformFragments()110 private LiteTransformFragments() {} 111 } 112