Add YouTube 14.44

Update parsing of configuration files as well.

Change-Id: I9d63a69448ff7e60d243a8b47ad300209ee62b38
diff --git a/build.gradle b/build.gradle
index 89e6798..2e64458 100644
--- a/build.gradle
+++ b/build.gradle
@@ -413,7 +413,8 @@
         "youtube/youtube.android_12.17",
         "youtube/youtube.android_12.22",
         "youtube/youtube.android_13.37",
-        "youtube/youtube.android_14.19"
+        "youtube/youtube.android_14.19",
+        "youtube/youtube.android_14.44"
     ],
 ]
 
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index 0f62be2..0652a33 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -57,9 +57,8 @@
       "target",
       "maximuminlinedcodelength");
 
-  private static final List<String> IGNORED_OPTIONAL_SINGLE_ARG_OPTIONS = ImmutableList.of(
-      "runtype",
-      "laststageoutput");
+  private static final List<String> IGNORED_OPTIONAL_SINGLE_ARG_OPTIONS =
+      ImmutableList.of("runtype", "laststageoutput", "maximumremovedandroidloglevel");
 
   private static final List<String> IGNORED_FLAG_OPTIONS = ImmutableList.of(
       "forceprocessing",
@@ -249,6 +248,9 @@
       } else if (acceptString("checkdiscard")) {
         ProguardCheckDiscardRule rule = parseCheckDiscardRule(optionStart);
         configurationBuilder.addRule(rule);
+      } else if (acceptString("checkenumstringsdiscarded")) {
+        // Not supported, ignore.
+        parseCheckDiscardRule(optionStart);
       } else if (acceptString("keepdirectories")) {
         configurationBuilder.enableKeepDirectories();
         parsePathFilter(configurationBuilder::addKeepDirectories);
@@ -501,7 +503,8 @@
       return true;
     }
 
-    private boolean parseIgnoredOption(TextPosition optionStart) {
+    private boolean parseIgnoredOption(TextPosition optionStart)
+        throws ProguardRuleParserException {
       return Iterables.any(IGNORED_SINGLE_ARG_OPTIONS, this::skipOptionWithSingleArg)
           || Iterables.any(
               IGNORED_OPTIONAL_SINGLE_ARG_OPTIONS, this::skipOptionWithOptionalSingleArg)
@@ -596,7 +599,8 @@
 
     }
 
-    private boolean parseOptimizationOption(TextPosition optionStart) {
+    private boolean parseOptimizationOption(TextPosition optionStart)
+        throws ProguardRuleParserException {
       if (!acceptString("optimizations")) {
         return false;
       }
@@ -609,11 +613,19 @@
       return true;
     }
 
-    private void skipOptimizationName() {
+    private void skipOptimizationName() throws ProguardRuleParserException {
+      char quote = acceptQuoteIfPresent();
+      if (isQuote(quote)) {
+        skipWhitespace();
+      }
       if (acceptChar('!')) {
         skipWhitespace();
       }
       acceptString(next -> Character.isAlphabetic(next) || next == '/' || next == '*');
+      if (isQuote(quote)) {
+        skipWhitespace();
+        expectClosingQuote(quote);
+      }
     }
 
     private void skipSingleArgument() {
@@ -1745,14 +1757,22 @@
     private List<String> acceptPatternList() throws ProguardRuleParserException {
       List<String> patterns = new ArrayList<>();
       skipWhitespace();
+      char quote = acceptQuoteIfPresent();
       String pattern = acceptPattern();
+      if (isQuote(quote)) {
+        expectClosingQuote(quote);
+      }
       while (pattern != null) {
         patterns.add(pattern);
         skipWhitespace();
-        TextPosition start = getPosition();
         if (acceptChar(',')) {
           skipWhitespace();
+          TextPosition start = getPosition();
+          quote = acceptQuoteIfPresent();
           pattern = acceptPattern();
+          if (isQuote(quote)) {
+            expectClosingQuote(quote);
+          }
           if (pattern == null) {
             throw parseError("Expected list element", start);
           }
diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
index fae56af..1a37fc5 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -1044,16 +1044,38 @@
         ImmutableList.of(
             "-optimizations",
             "-optimizations xxx",
+            "-optimizations \"xxx\"",
+            "-optimizations 'xxx'",
             "-optimizations     xxx",
+            "-optimizations \"    xxx\"",
+            "-optimizations '    xxx'",
             "-optimizations xxx/yyy",
+            "-optimizations \"xxx/yyy\"",
+            "-optimizations 'xxx/yyy'",
             "-optimizations     xxx/yyy",
+            "-optimizations \"    xxx/yyy\"",
+            "-optimizations '    xxx/yyy'",
             "-optimizations xxx/yyy,zzz*",
+            "-optimizations \"xxx/yyy\",\"zzz*\"",
+            "-optimizations 'xxx/yyy','zzz*'",
             "-optimizations xxx/yyy  ,  zzz*",
+            "-optimizations \"xxx/yyy  \",\"  zzz*\"",
+            "-optimizations 'xxx/yyy  ','  zzz*'",
             "-optimizations !xxx",
+            "-optimizations \"!xxx\"",
+            "-optimizations '!xxx'",
             "-optimizations   !  xxx",
+            "-optimizations \"  !  xxx\"",
+            "-optimizations '  !  xxx'",
             "-optimizations !xxx,!yyy",
+            "-optimizations \"!xxx\",\"!yyy\"",
+            "-optimizations '!xxx','!yyy'",
             "-optimizations   !  xxx,  !  yyy",
-            "-optimizations !code/simplification/advanced,code/simplification/*")) {
+            "-optimizations \"  !  xxx\", \" !  yyy\"",
+            "-optimizations '  !  xxx', ' !  yyy'",
+            "-optimizations !code/simplification/advanced,code/simplification/*",
+            "-optimizations \"!code/simplification/advanced\",\"code/simplification/*\"",
+            "-optimizations '!code/simplification/advanced','code/simplification/*'")) {
       reset();
       Path proguardConfig = writeTextToTempFile(option);
       parser.parse(proguardConfig);
@@ -1294,11 +1316,21 @@
   public void parseKeepattributes() {
     List<String> xxxYYY = ImmutableList.of("xxx", "yyy");
     testKeepattributes(xxxYYY, "-keepattributes xxx,yyy");
+    testKeepattributes(xxxYYY, "-keepattributes \"xxx\",\"yyy\"");
+    testKeepattributes(xxxYYY, "-keepattributes 'xxx','yyy'");
     testKeepattributes(xxxYYY, "-keepattributes xxx, yyy");
+    testKeepattributes(xxxYYY, "-keepattributes \"xxx\", \"yyy\"");
+    testKeepattributes(xxxYYY, "-keepattributes 'xxx', 'yyy'");
     testKeepattributes(xxxYYY, "-keepattributes xxx ,yyy");
     testKeepattributes(xxxYYY, "-keepattributes xxx   ,   yyy");
+    testKeepattributes(xxxYYY, "-keepattributes \"xxx\"   ,   \"yyy\"");
+    testKeepattributes(xxxYYY, "-keepattributes 'xxx'   ,   'yyy'");
     testKeepattributes(xxxYYY, "-keepattributes       xxx   ,   yyy     ");
+    testKeepattributes(xxxYYY, "-keepattributes       \"xxx\"   ,   \"yyy\"     ");
+    testKeepattributes(xxxYYY, "-keepattributes       'xxx'   ,   'yyy'     ");
     testKeepattributes(xxxYYY, "-keepattributes       xxx   ,   yyy     \n");
+    testKeepattributes(xxxYYY, "-keepattributes       \"xxx\"   ,   \"yyy\"     \n");
+    testKeepattributes(xxxYYY, "-keepattributes       'xxx'   ,   'yyy'     \n");
     String config =
         "-keepattributes Exceptions,InnerClasses,Signature,Deprecated,\n"
             + "          SourceFile,LineNumberTable,*Annotation*,EnclosingMethod\n";
@@ -1306,6 +1338,14 @@
         "Exceptions", "InnerClasses", "Signature", "Deprecated",
         "SourceFile", "LineNumberTable", "*Annotation*", "EnclosingMethod");
     testKeepattributes(expected, config);
+    config =
+        "-keepattributes \"Exceptions\",\"InnerClasses\",\"Signature\",\"Deprecated\",\n"
+            + "          \"SourceFile\",\"LineNumberTable\",\"*Annotation*\",\"EnclosingMethod\"\n";
+    testKeepattributes(expected, config);
+    config =
+        "-keepattributes 'Exceptions','InnerClasses','Signature','Deprecated',\n"
+            + "          'SourceFile','LineNumberTable','*Annotation*','EnclosingMethod'\n";
+    testKeepattributes(expected, config);
   }
 
   private void testKeeppackagenames(ProguardPackageNameList expected, String config) {
@@ -2872,4 +2912,14 @@
     MatchSpecificType specificTypeMatcher = (MatchSpecificType) singleClassNameList.className;
     assertEquals("foo.bar$Baz", specificTypeMatcher.type.toSourceString());
   }
+
+  @Test
+  public void parseCheckenumstringsdiscarded() throws Exception {
+    Path proguardConfig =
+        writeTextToTempFile("-checkenumstringsdiscarded @com.example.SomeAnnotation enum *");
+    ProguardConfigurationParser parser =
+        new ProguardConfigurationParser(new DexItemFactory(), reporter);
+    parser.parse(proguardConfig);
+    verifyParserEndsCleanly();
+  }
 }
\ No newline at end of file
diff --git a/third_party/youtube/youtube.android_14.44.tar.gz.sha1 b/third_party/youtube/youtube.android_14.44.tar.gz.sha1
new file mode 100644
index 0000000..bdf9586
--- /dev/null
+++ b/third_party/youtube/youtube.android_14.44.tar.gz.sha1
@@ -0,0 +1 @@
+368f0029be6a0a2629ba8f05ea6954a3a859115e
\ No newline at end of file
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index d93e3c0..32ff432 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -15,7 +15,7 @@
 import gmscore_data
 import golem
 import nest_data
-from sanitize_libraries import SanitizeLibraries
+from sanitize_libraries import SanitizeLibraries, SanitizeLibrariesInPgconf
 import toolhelper
 import utils
 import youtube_data
@@ -386,6 +386,19 @@
     return 'deploy' if options.compiler == 'r8' else 'proguarded'
   return options.type
 
+def check_no_injars_and_no_libraryjars(pgconfs):
+  # Ensure that there are no -injars or -libraryjars in the configuration.
+  for pgconf in pgconfs:
+    pgconf_dirname = os.path.abspath(os.path.dirname(pgconf))
+    with open(pgconf) as pgconf_file:
+      for line in pgconf_file:
+        trimmed = line.strip()
+        if trimmed.startswith('-injars'):
+          raise Exception("Unexpected -injars found in " + pgconf)
+        elif trimmed.startswith('-libraryjars'):
+          raise Exception("Unexpected -libraryjars found in " + pgconf)
+
+
 def run_with_options(options, args, extra_args=None, stdout=None, quiet=False):
   if extra_args is None:
     extra_args = []
@@ -451,11 +464,20 @@
     if 'pgconf' in values and not options.k:
       sanitized_lib_path = os.path.join(
           os.path.abspath(outdir), 'sanitized_lib.jar')
-      sanitized_pgconf_path = os.path.join(
-          os.path.abspath(outdir), 'sanitized.config')
-      SanitizeLibraries(
-          sanitized_lib_path, sanitized_pgconf_path, values['pgconf'])
-      args.extend(['--pg-conf', sanitized_pgconf_path])
+      if 'no_inputs_in_pgconf' in values and values['no_inputs_in_pgconf']:
+        check_no_injars_and_no_libraryjars(values['pgconf'])
+        SanitizeLibraries(
+          sanitized_lib_path, values['libraries'], values['inputs'])
+        args.extend(['--lib', sanitized_lib_path])
+        for lib in values['pgconf']:
+          args.extend(['--pg-conf', lib])
+        args.extend(values['inputs'])
+      else:
+        sanitized_pgconf_path = os.path.join(
+            os.path.abspath(outdir), 'sanitized.config')
+        SanitizeLibrariesInPgconf(
+            sanitized_lib_path, sanitized_pgconf_path, values['pgconf'])
+        args.extend(['--pg-conf', sanitized_pgconf_path])
       app_provided_pg_conf = True
     if options.k:
       args.extend(['--pg-conf', options.k])
@@ -470,7 +492,8 @@
       extra_args.append('-Dcom.android.tools.r8.generatedMessageLiteShrinking=1')
       extra_args.append('-Dcom.android.tools.r8.stringSwitchConversion=1')
 
-  if not options.no_libraries and 'libraries' in values:
+  if (not options.no_libraries and 'libraries' in values
+      'no_inputs_in_pgconf' in values and not values['no_inputs_in_pgconf']):
     for lib in values['libraries']:
       args.extend(['--lib', lib])
 
diff --git a/tools/sanitize_libraries.py b/tools/sanitize_libraries.py
index e67a06e..87aa887 100755
--- a/tools/sanitize_libraries.py
+++ b/tools/sanitize_libraries.py
@@ -13,7 +13,8 @@
 # To make these apps work with R8 simulate program classes before library
 # classes by creating a new library jar which have all the provided library
 # classes which are not also in program classes.
-def SanitizeLibraries(sanitized_lib_path, sanitized_pgconf_path, pgconfs):
+def SanitizeLibrariesInPgconf(
+    sanitized_lib_path, sanitized_pgconf_path, pgconfs):
 
   injars = []
   libraryjars = []
@@ -44,6 +45,11 @@
           else:
             sanitized_pgconf.write(line)
 
+  SanitizeLibraries(sanitized_lib_path, libraryjars, injars)
+
+
+def SanitizeLibraries(sanitized_lib_path, libraryjars, injars):
+
   program_entries = set()
   library_entries = set()
 
@@ -61,7 +67,6 @@
            library_entries.add(zipinfo.filename)
            output_zf.writestr(zipinfo, input_zf.read(zipinfo))
 
-  return sanitized_pgconf_path
 
 def main(argv):
   if (len(argv) < 3):
diff --git a/tools/youtube_data.py b/tools/youtube_data.py
index 94a97ce..f8e936f 100644
--- a/tools/youtube_data.py
+++ b/tools/youtube_data.py
@@ -24,6 +24,9 @@
 V14_19_BASE = os.path.join(BASE, 'youtube.android_14.19')
 V14_19_PREFIX = os.path.join(V14_19_BASE, 'YouTubeRelease')
 
+V14_44_BASE = os.path.join(BASE, 'youtube.android_14.44')
+V14_44_PREFIX = os.path.join(V14_44_BASE, 'YouTubeRelease')
+
 # NOTE: we always use android.jar for SDK v25, later we might want to revise it
 #       to use proper android.jar version for each of youtube version separately.
 ANDROID_JAR = utils.get_android_jar(25)
@@ -146,4 +149,35 @@
       'min-api' : ANDROID_L_API,
     }
   },
+  '14.44': {
+    'dex' : {
+      'inputs': [os.path.join(V14_44_BASE, 'YouTubeRelease_unsigned.apk')],
+      'pgmap': '%s_proguard.map' % V14_44_PREFIX,
+      'libraries' : [ANDROID_JAR],
+      'min-api' : ANDROID_L_API,
+    },
+    'deploy' : {
+      # -injars and -libraryjars are no longer used in the configuration. Instead
+      # they are taken directly from 'inputs' and 'libraries'.
+      'no_inputs_in_pgconf': True,
+      'inputs': ['%s_deploy.jar' % V14_44_PREFIX],
+      'libraries' : [os.path.join(V14_44_BASE, 'legacy_YouTubeRelease_combined_library_jars.jar')],
+      'pgconf': [
+          '%s_proguard.config' % V14_44_PREFIX,
+          '%s/proguardsettings/YouTubeRelease_proguard.config' % utils.THIRD_PARTY],
+      'proto-shrinking': 1,
+      # Build for native multi dex, as Currently R8 cannot meet the main-dex
+      # constraints.
+      #'maindexrules' : [
+      #    os.path.join(V14_44_BASE, 'mainDexClasses.rules'),
+      #    os.path.join(V14_44_BASE, 'main-dex-classes-release-optimized.cfg'),
+      #    os.path.join(V14_44_BASE, 'main_dex_YouTubeRelease_proguard.cfg')],
+      'min-api' : ANDROID_L_API,
+    },
+    'proguarded' : {
+      'inputs': ['%s_proguard.jar' % V14_44_PREFIX],
+      'pgmap': '%s_proguard.map' % V14_44_PREFIX,
+      'min-api' : ANDROID_L_API,
+    }
+  },
 }