Do not resolve file names against output directory twice.

Bug:
Change-Id: Ic4abf7c53a0b0e2860685a715bafe73ef0a0ee38
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 876f685..4806485 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -184,11 +184,12 @@
           .write(outputSink, executor);
       CompilationResult output = new CompilationResult(outputSink, app, appInfo);
       options.printWarnings();
-      outputSink.close();
       return output;
     } catch (ExecutionException e) {
       R8.unwrapExecutionException(e);
       throw new AssertionError(e); // unwrapping method should have thrown
+    } finally {
+      outputSink.close();
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 0ed71b8..3d5f7d7 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -350,11 +350,11 @@
           options);
 
       options.printWarnings();
-      outputSink.close();
     } catch (ExecutionException e) {
       unwrapExecutionException(e);
       throw new AssertionError(e); // unwrapping method should have thrown
     } finally {
+      outputSink.close();
       // Dump timings.
       if (options.printTimes) {
         timing.report();
diff --git a/src/main/java/com/android/tools/r8/utils/DirectoryOutputSink.java b/src/main/java/com/android/tools/r8/utils/DirectoryOutputSink.java
index adedfde..56e0ea1 100644
--- a/src/main/java/com/android/tools/r8/utils/DirectoryOutputSink.java
+++ b/src/main/java/com/android/tools/r8/utils/DirectoryOutputSink.java
@@ -35,7 +35,7 @@
   @Override
   public void writeDexFile(byte[] contents, Set<String> classDescriptors, int fileId)
       throws IOException {
-    Path target = outputDirectory.resolve(getOutputPath(fileId));
+    Path target = outputDirectory.resolve(getOutputFileName(fileId));
     Files.createDirectories(target.getParent());
     writeToFile(target, null, contents);
   }
@@ -43,7 +43,7 @@
   @Override
   public void writeDexFile(byte[] contents, Set<String> classDescriptors, String primaryClassName)
       throws IOException {
-    Path target = outputDirectory.resolve(getOutputPath(primaryClassName));
+    Path target = outputDirectory.resolve(getOutputFileName(primaryClassName));
     Files.createDirectories(target.getParent());
     writeToFile(target, null, contents);
   }
@@ -52,17 +52,4 @@
   public void close() throws IOException {
     // Intentionally left empty.
   }
-
-  private Path getOutputPath(int index) {
-    String file = index == 0 ? "classes.dex" : ("classes" + (index + 1) + ".dex");
-    return outputDirectory.resolve(file);
-  }
-
-  private Path getOutputPath(String classDescriptor) throws IOException {
-    assert classDescriptor != null && DescriptorUtils.isClassDescriptor(classDescriptor);
-    Path result = outputDirectory
-        .resolve(classDescriptor.substring(1, classDescriptor.length() - 1) + ".dex");
-    Files.createDirectories(result.getParent());
-    return result;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/FileSystemOutputSink.java b/src/main/java/com/android/tools/r8/utils/FileSystemOutputSink.java
index e7cfc28..e007147 100644
--- a/src/main/java/com/android/tools/r8/utils/FileSystemOutputSink.java
+++ b/src/main/java/com/android/tools/r8/utils/FileSystemOutputSink.java
@@ -8,7 +8,6 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.nio.file.StandardOpenOption;
 
 public abstract class FileSystemOutputSink implements OutputSink {
@@ -28,17 +27,17 @@
     }
   }
 
-  protected Path getOutputFileName(int index) {
-    String file = index == 0 ? "classes.dex" : ("classes" + (index + 1) + ".dex");
-    return Paths.get(file);
+  String getOutputFileName(int index) {
+    return index == 0 ? "classes.dex" : ("classes" + (index + 1) + FileUtils.DEX_EXTENSION);
   }
 
-  protected Path getOutputFileName(String classDescriptor) throws IOException {
+  String getOutputFileName(String classDescriptor) throws IOException {
     assert classDescriptor != null && DescriptorUtils.isClassDescriptor(classDescriptor);
-    Path result = Paths.get(classDescriptor.substring(1, classDescriptor.length() - 1) + ".dex");
-    return result;
+    return DescriptorUtils.getClassBinaryNameFromDescriptor(classDescriptor)
+        + FileUtils.DEX_EXTENSION;
   }
 
+
   @Override
   public void writePrintUsedInformation(byte[] contents) throws IOException {
     writeToFile(options.proguardConfiguration.getPrintUsageFile(), System.out, contents);
@@ -67,7 +66,9 @@
               closer,
               output,
               defValue,
-              StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
+              StandardOpenOption.CREATE,
+              StandardOpenOption.TRUNCATE_EXISTING,
+              StandardOpenOption.WRITE);
       outputStream.write(contents);
     }
   }
diff --git a/src/main/java/com/android/tools/r8/utils/FileUtils.java b/src/main/java/com/android/tools/r8/utils/FileUtils.java
index a292423..809a6d4 100644
--- a/src/main/java/com/android/tools/r8/utils/FileUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/FileUtils.java
@@ -118,10 +118,10 @@
 
   static boolean isClassesDexFile(Path file) {
     String name = file.getFileName().toString().toLowerCase();
-    if (!name.startsWith("classes") || !name.endsWith(".dex")) {
+    if (!name.startsWith("classes") || !name.endsWith(DEX_EXTENSION)) {
       return false;
     }
-    String numeral = name.substring("classes".length(), name.length() - ".dex".length());
+    String numeral = name.substring("classes".length(), name.length() - DEX_EXTENSION.length());
     if (numeral.isEmpty()) {
       return true;
     }
diff --git a/src/main/java/com/android/tools/r8/utils/ZipFileOutputSink.java b/src/main/java/com/android/tools/r8/utils/ZipFileOutputSink.java
index 0feb485..d290b56 100644
--- a/src/main/java/com/android/tools/r8/utils/ZipFileOutputSink.java
+++ b/src/main/java/com/android/tools/r8/utils/ZipFileOutputSink.java
@@ -39,8 +39,8 @@
     outputStream.close();
   }
 
-  private synchronized void writeToZipFile(Path outputPath, byte[] content) throws IOException {
-    ZipEntry zipEntry = new ZipEntry(outputPath.toString());
+  private synchronized void writeToZipFile(String outputPath, byte[] content) throws IOException {
+    ZipEntry zipEntry = new ZipEntry(outputPath);
     zipEntry.setSize(content.length);
     outputStream.putNextEntry(zipEntry);
     outputStream.write(content);
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
index 546d9eb..c8ca57e 100644
--- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
@@ -274,7 +274,6 @@
     D8IncrementalTestRunner test = test(testName, testPackage, mainClass);
     test.compileClassesTogether(inputJarFile, out);
 
-
     String[] topLevelDir = out.toFile().list();
     assert topLevelDir != null;
     assertEquals(1, topLevelDir.length);
diff --git a/src/test/java/com/android/tools/r8/R8EntryPointTests.java b/src/test/java/com/android/tools/r8/R8EntryPointTests.java
index e2cb5d6..5ad82de 100644
--- a/src/test/java/com/android/tools/r8/R8EntryPointTests.java
+++ b/src/test/java/com/android/tools/r8/R8EntryPointTests.java
@@ -98,6 +98,25 @@
   }
 
   @Test
+  public void testMainRelativeDir() throws IOException, InterruptedException {
+    temp.newFolder("outdex");
+    Path out = Paths.get("outdex");
+    Path workingDir = temp.getRoot().toPath();
+    ProcessResult r8 = ToolHelper.forkR8(workingDir,
+        "--lib", Paths.get(ToolHelper.getDefaultAndroidJar()).toAbsolutePath().toString(),
+        "--output", out.toString(),
+        "--pg-conf", PROGUARD_FLAGS.toAbsolutePath().toString(),
+        "--pg-conf", testFlags.toAbsolutePath().toString(),
+        INPUT_JAR.toAbsolutePath().toString());
+    Assert.assertEquals(0, r8.exitCode);
+    Assert.assertTrue(
+        Files.isRegularFile(workingDir.resolve(out).resolve(ToolHelper.DEFAULT_DEX_FILENAME)));
+    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(MAPPING)));
+    Assert.assertTrue(Files.isRegularFile(testFlags.getParent().resolve(SEEDS)));
+  }
+
+
+  @Test
   public void testMainZip() throws IOException, InterruptedException {
     Path out = temp.newFolder("outdex").toPath().resolve("dex.zip");
     ProcessResult r8 = ToolHelper.forkR8(Paths.get("."),