content: /*
   * This file is part of LSPosed.
   *
   * LSPosed is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * LSPosed is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with LSPosed.  If not, see <https://www.gnu.org/licenses/>.
   *
   * Copyright (C) 2020 EdXposed Contributors
   * Copyright (C) 2021 LSPosed Contributors
   */
  
  package de.robv.android.xposed.services;
  
  import java.io.BufferedInputStream;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.IOException;
  import java.io.InputStream;
  
  /**
   * @hide
   */
  public final class DirectAccessService extends BaseService {
      @Override
      public boolean hasDirectFileAccess() {
          return true;
      }
  
      @SuppressWarnings("RedundantIfStatement")
      @Override
      public boolean checkFileAccess(String filename, int mode) {
          File file = new File(filename);
          if (mode == F_OK && !file.exists()) return false;
          if ((mode & R_OK) != 0 && !file.canRead()) return false;
          if ((mode & W_OK) != 0 && !file.canWrite()) return false;
          if ((mode & X_OK) != 0 && !file.canExecute()) return false;
          return true;
      }
  
      @Override
      public boolean checkFileExists(String filename) {
          return new File(filename).exists();
      }
  
      @Override
      public FileResult statFile(String filename) throws IOException {
          File file = new File(filename);
          return new FileResult(file.length(), file.lastModified());
      }
  
      @Override
      public byte[] readFile(String filename) throws IOException {
          File file = new File(filename);
          byte content[] = new byte[(int) file.length()];
          FileInputStream fis = new FileInputStream(file);
          fis.read(content);
          fis.close();
          return content;
      }
  
      @Override
      public FileResult readFile(String filename, long previousSize, long previousTime) throws IOException {
          File file = new File(filename);
          long size = file.length();
          long time = file.lastModified();
          if (previousSize == size && previousTime == time)
              return new FileResult(size, time);
          return new FileResult(readFile(filename), size, time);
      }
  
      @Override
      public FileResult readFile(String filename, int offset, int length, long previousSize, long previousTime) throws IOException {
          File file = new File(filename);
          long size = file.length();
          long time = file.lastModified();
          if (previousSize == size && previousTime == time)
              return new FileResult(size, time);
  
          // Shortcut for the simple case
          if (offset <= 0 && length <= 0)
              return new FileResult(readFile(filename), size, time);
  
          // Check range
          if (offset > 0 && offset >= size) {
              throw new IllegalArgumentException("Offset " + offset + " is out of range for " + filename);
          } else if (offset < 0) {
              offset = 0;
          }
  
          if (length > 0 && (offset + length) > size) {
              throw new IllegalArgumentException("Length " + length + " is out of range for " + filename);
          } else if (length <= 0) {
              length = (int) (size - offset);
          }
  
          byte content[] = new byte[length];
          FileInputStream fis = new FileInputStream(file);
          fis.skip(offset);
          fis.read(content);
          fis.close();
          return new FileResult(content, size, time);
      }
  
      /**
       * {@inheritDoc}
       * <p>This implementation returns a BufferedInputStream instead of loading the file into memory.
       */
      @Override
      public InputStream getFileInputStream(String filename) throws IOException {
          return new BufferedInputStream(new FileInputStream(filename), 16 * 1024);
      }
  
      /**
       * {@inheritDoc}
       * <p>This implementation returns a BufferedInputStream instead of loading the file into memory.
       */
      @Override
      public FileResult getFileInputStream(String filename, long previousSize, long previousTime) throws IOException {
          File file = new File(filename);
          long size = file.length();
          long time = file.lastModified();
          if (previousSize == size && previousTime == time)
              return new FileResult(size, time);
          return new FileResult(new BufferedInputStream(new FileInputStream(filename), 16 * 1024), size, time);
      }
  }
  