public void publicizeResources(File arscFile) throws AndrolibException {
    byte[] data = new byte[(int) arscFile.length()];

    InputStream in = null;
    OutputStream out = null;
    try {
      in = new FileInputStream(arscFile);
      in.read(data);

      publicizeResources(data);

      out = new FileOutputStream(arscFile);
      out.write(data);
    } catch (IOException ex) {
      throw new AndrolibException(ex);
    } finally {
      if (in != null) {
        try {
          in.close();
        } catch (IOException ex) {
        }
      }
      if (out != null) {
        try {
          out.close();
        } catch (IOException ex) {
        }
      }
    }
  }
 public void decodeSourcesSmali(
     File apkFile,
     File outDir,
     String filename,
     boolean debug,
     String debugLinePrefix,
     boolean bakdeb,
     int api)
     throws AndrolibException {
   try {
     File smaliDir;
     if (filename.equalsIgnoreCase("classes.dex")) {
       smaliDir = new File(outDir, SMALI_DIRNAME);
     } else {
       smaliDir =
           new File(outDir, SMALI_DIRNAME + "_" + filename.substring(0, filename.indexOf(".")));
     }
     OS.rmdir(smaliDir);
     smaliDir.mkdirs();
     LOGGER.info("Baksmaling " + filename + "...");
     SmaliDecoder.decode(apkFile, smaliDir, filename, debug, debugLinePrefix, bakdeb, api);
   } catch (BrutException ex) {
     throw new AndrolibException(ex);
   }
 }
 private File getFrameworkDir() throws AndrolibException {
   File dir =
       new File(
           System.getProperty("user.home")
               + File.separatorChar
               + "apktool"
               + File.separatorChar
               + "framework");
   if (!dir.exists()) {
     if (!dir.mkdirs()) {
       throw new AndrolibException("Can't create directory: " + dir);
     }
   }
   return dir;
 }
  public boolean buildManifest(ExtFile appDir, Map<String, Object> usesFramework)
      throws BrutException {
    try {
      if (!new File(appDir, "AndroidManifest.xml").exists()) {
        return false;
      }
      if (!apkOptions.forceBuildAll) {
        LOGGER.info("Checking whether resources has changed...");
      }

      File apkDir = new File(appDir, APK_DIRNAME);

      if (apkOptions.debugMode) {
        mAndRes.remove_application_debug(new File(apkDir, "AndroidManifest.xml").getAbsolutePath());
      }

      if (apkOptions.forceBuildAll
          || isModified(
              newFiles(APK_MANIFEST_FILENAMES, appDir), newFiles(APK_MANIFEST_FILENAMES, apkDir))) {
        LOGGER.info("Building AndroidManifest.xml...");

        File apkFile = File.createTempFile("APKTOOL", null);
        apkFile.delete();

        File ninePatch = new File(appDir, "9patch");
        if (!ninePatch.exists()) {
          ninePatch = null;
        }

        mAndRes.aaptPackage(
            apkFile,
            new File(appDir, "AndroidManifest.xml"),
            null,
            ninePatch,
            null,
            parseUsesFramework(usesFramework));

        Directory tmpDir = new ExtFile(apkFile).getDirectory();
        tmpDir.copyToDir(apkDir, APK_MANIFEST_FILENAMES);
      }
      return true;
    } catch (IOException | DirectoryException ex) {
      throw new AndrolibException(ex);
    } catch (AndrolibException ex) {
      LOGGER.warning("Parse AndroidManifest.xml failed, treat it as raw file.");
      return buildManifestRaw(appDir);
    }
  }
  public boolean detectWhetherAppIsFramework(File appDir) throws AndrolibException {
    File publicXml = new File(appDir, "res/values/public.xml");
    if (!publicXml.exists()) {
      return false;
    }

    Iterator<String> it;
    try {
      it = IOUtils.lineIterator(new FileReader(new File(appDir, "res/values/public.xml")));
    } catch (FileNotFoundException ex) {
      throw new AndrolibException("Could not detect whether app is framework one", ex);
    }
    it.next();
    it.next();
    return it.next().contains("0x01");
  }
 public void buildLib(File appDir) throws AndrolibException {
   File working = new File(appDir, "lib");
   if (!working.exists()) {
     return;
   }
   File stored = new File(appDir, APK_DIRNAME + "/lib");
   if (apkOptions.forceBuildAll || isModified(working, stored)) {
     LOGGER.info("Copying libs...");
     try {
       OS.rmdir(stored);
       OS.cpdir(working, stored);
     } catch (BrutException ex) {
       throw new AndrolibException(ex);
     }
   }
 }
 public boolean buildSourcesJava(File appDir) throws AndrolibException {
   File javaDir = new File(appDir, "src");
   if (!javaDir.exists()) {
     return false;
   }
   File dex = new File(appDir, APK_DIRNAME + "/classes.dex");
   if (!apkOptions.forceBuildAll) {
     LOGGER.info("Checking whether sources has changed...");
   }
   if (apkOptions.forceBuildAll || isModified(javaDir, dex)) {
     LOGGER.info("Building java sources...");
     dex.delete();
     new AndrolibJava().build(javaDir, dex);
   }
   return true;
 }
 public boolean buildSourcesSmali(File appDir, String folder, String filename)
     throws AndrolibException {
   ExtFile smaliDir = new ExtFile(appDir, folder);
   if (!smaliDir.exists()) {
     return false;
   }
   File dex = new File(appDir, APK_DIRNAME + "/" + filename);
   if (!apkOptions.forceBuildAll) {
     LOGGER.info("Checking whether sources has changed...");
   }
   if (apkOptions.forceBuildAll || isModified(smaliDir, dex)) {
     LOGGER.info("Smaling " + folder + " folder into " + filename + "...");
     dex.delete();
     SmaliBuilder.build(smaliDir, dex, apkOptions.debugMode);
   }
   return true;
 }
 public boolean buildSourcesRaw(File appDir, String filename) throws AndrolibException {
   File working = new File(appDir, filename);
   if (!working.exists()) {
     return false;
   }
   File stored = new File(appDir, APK_DIRNAME + "/" + filename);
   if (apkOptions.forceBuildAll || isModified(working, stored)) {
     LOGGER.info("Copying " + appDir.toString() + " " + filename + " file...");
     try {
       BrutIO.copyAndClose(new FileInputStream(working), new FileOutputStream(stored));
       return true;
     } catch (IOException ex) {
       throw new AndrolibException(ex);
     }
   }
   return true;
 }
  private void insertFile(
      Path apkPath, Map<String, String> zip_properties, File insert, String method, Path location)
      throws AndrolibException, IOException {
    // ZipFileSystem only writes at .close()
    // http://mail.openjdk.java.net/pipermail/nio-dev/2012-July/001764.html
    try (FileSystem fs = FileSystems.newFileSystem(apkPath, null)) {
      Path root = fs.getPath("/");

      // in order to get the path relative to the zip, we strip off the absolute path, minus what we
      // already have in the zip. thus /var/files/apktool/apk/unknown/folder/file => /folder/file
      Path dest =
          fs.getPath(root.toString(), insert.getAbsolutePath().replace(location.toString(), ""));
      Path newFile = Paths.get(insert.getAbsolutePath());
      Files.copy(newFile, dest, StandardCopyOption.REPLACE_EXISTING);
      fs.close();
    }
  }
  public File getFrameworkApk(int id, String frameTag) throws AndrolibException {
    File dir = getFrameworkDir();
    File apk;

    if (frameTag != null) {
      apk = new File(dir, String.valueOf(id) + '-' + frameTag + ".apk");
      if (apk.exists()) {
        return apk;
      }
    }

    apk = new File(dir, String.valueOf(id) + ".apk");
    if (apk.exists()) {
      return apk;
    }

    if (id == 1) {
      InputStream in = null;
      OutputStream out = null;
      try {
        in = AndrolibResources.class.getResourceAsStream("/brut/androlib/android-framework.jar");
        out = new FileOutputStream(apk);
        IOUtils.copy(in, out);
        return apk;
      } catch (IOException ex) {
        throw new AndrolibException(ex);
      } finally {
        if (in != null) {
          try {
            in.close();
          } catch (IOException ex) {
          }
        }
        if (out != null) {
          try {
            out.close();
          } catch (IOException ex) {
          }
        }
      }
    }

    throw new CantFindFrameworkResException(id);
  }
  public void writeOriginalFiles(ExtFile apkFile, File outDir) throws AndrolibException {
    LOGGER.info("Copying original files...");
    File originalDir = new File(outDir, "original");
    if (!originalDir.exists()) {
      originalDir.mkdirs();
    }

    try {
      Directory in = apkFile.getDirectory();
      if (in.containsFile("AndroidManifest.xml")) {
        in.copyToDir(originalDir, "AndroidManifest.xml");
      }
      if (in.containsDir("META-INF")) {
        in.copyToDir(originalDir, "META-INF");
      }
    } catch (DirectoryException ex) {
      throw new AndrolibException(ex);
    }
  }
 public void buildCopyOriginalFiles(File appDir) throws AndrolibException {
   if (apkOptions.copyOriginalFiles) {
     File originalDir = new File(appDir, "original");
     if (originalDir.exists()) {
       try {
         LOGGER.info("Copy original files...");
         Directory in = (new ExtFile(originalDir)).getDirectory();
         if (in.containsFile("AndroidManifest.xml")) {
           LOGGER.info("Copy AndroidManifest.xml...");
           in.copyToDir(new File(appDir, APK_DIRNAME), "AndroidManifest.xml");
         }
         if (in.containsDir("META-INF")) {
           LOGGER.info("Copy META-INF...");
           in.copyToDir(new File(appDir, APK_DIRNAME), "META-INF");
         }
       } catch (DirectoryException ex) {
         throw new AndrolibException(ex);
       }
     }
   }
 }
 public void buildApk(File appDir, File outApk) throws AndrolibException {
   LOGGER.info("Building apk file...");
   if (outApk.exists()) {
     outApk.delete();
   } else {
     File outDir = outApk.getParentFile();
     if (outDir != null && !outDir.exists()) {
       outDir.mkdirs();
     }
   }
   File assetDir = new File(appDir, "assets");
   if (!assetDir.exists()) {
     assetDir = null;
   }
   mAndRes.aaptPackage(outApk, null, null, new File(appDir, APK_DIRNAME), assetDir, null);
 }
  private void insertFolder(
      Path apkPath, Map<String, String> zip_properties, File insert, String method, Path location)
      throws AndrolibException, IOException {
    try (FileSystem fs = FileSystems.newFileSystem(apkPath, null)) {
      Path root = fs.getPath("/");
      Path dest =
          fs.getPath(root.toString(), insert.getAbsolutePath().replace(location.toString(), ""));
      Path parent = dest.normalize();

      // check for folder existing in apkFileSystem
      if (parent != null && Files.notExists(parent)) {
        if (!Files.isDirectory(parent, LinkOption.NOFOLLOW_LINKS)) {
          Files.createDirectories(parent);
        }
      }
      fs.close();
    }
  }
  public boolean buildResourcesFull(File appDir, Map<String, Object> usesFramework)
      throws AndrolibException {
    try {
      if (!new File(appDir, "res").exists()) {
        return false;
      }
      if (!apkOptions.forceBuildAll) {
        LOGGER.info("Checking whether resources has changed...");
      }
      File apkDir = new File(appDir, APK_DIRNAME);
      if (apkOptions.forceBuildAll
          || isModified(
              newFiles(APP_RESOURCES_FILENAMES, appDir),
              newFiles(APK_RESOURCES_FILENAMES, apkDir))) {
        LOGGER.info("Building resources...");

        File apkFile = File.createTempFile("APKTOOL", null);
        apkFile.delete();

        File ninePatch = new File(appDir, "9patch");
        if (!ninePatch.exists()) {
          ninePatch = null;
        }
        mAndRes.aaptPackage(
            apkFile,
            new File(appDir, "AndroidManifest.xml"),
            new File(appDir, "res"),
            ninePatch,
            null,
            parseUsesFramework(usesFramework));

        Directory tmpDir = new ExtFile(apkFile).getDirectory();
        tmpDir.copyToDir(
            apkDir,
            tmpDir.containsDir("res")
                ? APK_RESOURCES_FILENAMES
                : APK_RESOURCES_WITHOUT_RES_FILENAMES);

        // delete tmpDir
        apkFile.delete();
      }
      return true;
    } catch (IOException | BrutException ex) {
      throw new AndrolibException(ex);
    }
  }
  public void buildUnknownFiles(File appDir, File outFile, Map<String, Object> meta)
      throws AndrolibException {
    File file;
    Path globalPath = Paths.get(appDir.getPath() + File.separatorChar + UNK_DIRNAME);

    if (meta.containsKey("unknownFiles")) {
      LOGGER.info("Copying unknown files/dir...");

      Map<String, String> files = (Map<String, String>) meta.get("unknownFiles");

      try {
        // set our filesystem options
        Map<String, String> zip_properties = new HashMap<>();
        zip_properties.put("create", "false");
        zip_properties.put("encoding", "UTF-8");

        // create filesystem
        Path path = Paths.get(outFile.getAbsolutePath());

        // loop through files inside
        for (Map.Entry<String, String> entry : files.entrySet()) {

          file = new File(globalPath.toFile(), entry.getKey());
          if (file.isFile() && file.exists()) {
            insertFolder(
                path,
                zip_properties,
                file.getParentFile(),
                entry.getValue(),
                globalPath.toAbsolutePath());

            insertFile(path, zip_properties, file, entry.getValue(), globalPath.toAbsolutePath());
          }
        }
      } catch (IOException ex) {
        throw new AndrolibException(ex);
      }
    }
  }
  public void aaptPackage(
      File apkFile,
      File manifest,
      File resDir,
      File rawDir,
      File assetDir,
      File[] include,
      boolean update,
      boolean framework)
      throws AndrolibException {
    List<String> cmd = new ArrayList<String>();

    cmd.add("aapt");
    cmd.add("p");
    cmd.add("-v"); // mega debug mode.@todo REMOVE ON FINAL
    if (update) {
      cmd.add("-u");
    }
    if (mMinSdkVersion != null) {
      cmd.add("--min-sdk-version");
      cmd.add(mMinSdkVersion);
    }
    if (mTargetSdkVersion != null) {
      cmd.add("--target-sdk-version");
      cmd.add(mTargetSdkVersion);
    }
    if (mMaxSdkVersion != null) {
      cmd.add("--max-sdk-version");
      cmd.add(mMaxSdkVersion);
    }
    cmd.add("-F");
    cmd.add(apkFile.getAbsolutePath());

    if (framework) {
      cmd.add("-x");
      //            cmd.add("-0");
      //            cmd.add("arsc");
    }

    if (include != null) {
      for (File file : include) {
        cmd.add("-I");
        cmd.add(file.getPath());
      }
    }
    if (resDir != null) {
      cmd.add("-S");
      cmd.add(resDir.getAbsolutePath());
    }
    if (manifest != null) {
      cmd.add("-M");
      cmd.add(manifest.getAbsolutePath());
    }
    if (assetDir != null) {
      cmd.add("-A");
      cmd.add(assetDir.getAbsolutePath());
    }
    if (rawDir != null) {
      cmd.add(rawDir.getAbsolutePath());
    }

    try {
      OS.exec(cmd.toArray(new String[0]));
    } catch (BrutException ex) {
      throw new AndrolibException(ex);
    }
  }
 private boolean isModified(File working, File stored) {
   return !stored.exists()
       || BrutIO.recursiveModifiedTime(working) > BrutIO.recursiveModifiedTime(stored);
 }