| // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 | package com.android.tools.r8.naming; | 
 |  | 
 | import static com.android.tools.r8.position.TextPosition.UNKNOWN_COLUMN; | 
 |  | 
 | import com.android.tools.r8.origin.PathOrigin; | 
 | import com.android.tools.r8.position.TextPosition; | 
 | import com.android.tools.r8.utils.ExceptionDiagnostic; | 
 | import com.android.tools.r8.utils.Reporter; | 
 | import com.android.tools.r8.utils.StringDiagnostic; | 
 | import com.google.common.collect.ImmutableList; | 
 | import com.google.common.collect.ImmutableList.Builder; | 
 | import java.io.BufferedReader; | 
 | import java.io.IOException; | 
 | import java.nio.file.Files; | 
 | import java.nio.file.Path; | 
 | import java.util.HashSet; | 
 | import java.util.Set; | 
 |  | 
 | public class DictionaryReader implements AutoCloseable { | 
 |  | 
 |   private final BufferedReader reader; | 
 |   private final Path path; | 
 |  | 
 |   public DictionaryReader(Path path) throws IOException { | 
 |     this.path = path; | 
 |     this.reader = Files.newBufferedReader(path); | 
 |   } | 
 |  | 
 |   public String readName(Reporter reporter) throws IOException { | 
 |     assert reader != null; | 
 |  | 
 |     StringBuilder name = new StringBuilder(); | 
 |     int readCharAsInt; | 
 |     int lineNumber = 1; | 
 |  | 
 |     while ((readCharAsInt = reader.read()) != -1) { | 
 |       char readChar = (char) readCharAsInt; | 
 |  | 
 |       if ((name.length() != 0 && Character.isJavaIdentifierPart(readChar)) | 
 |           || (name.length() == 0 && Character.isJavaIdentifierStart(readChar))) { | 
 |         name.append(readChar); | 
 |       } else { | 
 |         boolean isCommentChar = readChar == '#'; | 
 |         boolean isValidEndOfLineInput = readChar == '\n' || readChar == '\r'; | 
 |         if (isCommentChar || isValidEndOfLineInput) { | 
 |           if (isCommentChar) { | 
 |             reader.readLine(); | 
 |           } | 
 |           lineNumber++; | 
 |         } | 
 |         if (isValidEndOfLineInput && name.length() != 0) { | 
 |           return name.toString(); | 
 |         } | 
 |         name = new StringBuilder(); | 
 |         // An illegal character was in the input. We discard the entire line instead of returning as | 
 |         // much as possible, to ensure us not throwing an error in the case of duplicates. | 
 |         if (!isValidEndOfLineInput) { | 
 |           reporter.info( | 
 |               new StringDiagnostic( | 
 |                   "Invalid character in dictionary '" + readChar + "'", | 
 |                   new PathOrigin(path), | 
 |                   new TextPosition(0, lineNumber, UNKNOWN_COLUMN))); | 
 |           reader.readLine(); | 
 |           lineNumber++; | 
 |         } | 
 |       } | 
 |     } | 
 |  | 
 |     return name.toString(); | 
 |   } | 
 |  | 
 |   @Override | 
 |   public void close() throws IOException { | 
 |     if (reader != null) { | 
 |       reader.close(); | 
 |     } | 
 |   } | 
 |  | 
 |   public static ImmutableList<String> readAllNames(Path path, Reporter reporter) { | 
 |     if (path != null) { | 
 |       Set<String> seenNames = new HashSet<>(); | 
 |       Builder<String> namesBuilder = new ImmutableList.Builder<String>(); | 
 |       try (DictionaryReader reader = new DictionaryReader(path);) { | 
 |         String name = reader.readName(reporter); | 
 |         while (!name.isEmpty()) { | 
 |           if (!seenNames.add(name)) { | 
 |             reporter.error( | 
 |                 new StringDiagnostic( | 
 |                     "Duplicate entry for '" + name + "' in dictionary", new PathOrigin(path))); | 
 |           } | 
 |           namesBuilder.add(name); | 
 |           name = reader.readName(reporter); | 
 |         } | 
 |       } catch (IOException e) { | 
 |         reporter.error(new ExceptionDiagnostic(e, new PathOrigin(path))); | 
 |       } | 
 |       return namesBuilder.build(); | 
 |     } else { | 
 |       return ImmutableList.of(); | 
 |     } | 
 |   } | 
 | } |