text: // Copyright 2018 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef EXTENSIONS_BROWSER_IMAGE_SANITIZER_H_
  #define EXTENSIONS_BROWSER_IMAGE_SANITIZER_H_
  
  #include <cstdint>
  #include <memory>
  #include <set>
  #include <tuple>
  #include <vector>
  
  #include "base/files/file_path.h"
  #include "base/macros.h"
  #include "base/memory/weak_ptr.h"
  #include "base/time/time.h"
  #include "mojo/public/cpp/bindings/remote.h"
  #include "services/data_decoder/public/mojom/image_decoder.mojom.h"
  
  class SkBitmap;
  
  namespace data_decoder {
  class DataDecoder;
  }
  
  namespace extensions {
  
  // This class takes potentially unsafe images and decodes them in a sandboxed
  // process, then reencodes them so that they can later be safely used in the
  // browser process.
  class ImageSanitizer {
   public:
    enum class Status {
      kSuccess = 0,
      kImagePathError,
      kFileReadError,
      kFileDeleteError,
      kDecodingError,
      kEncodingError,
      kFileWriteError,
    };
  
    class Client : public base::RefCountedThreadSafe<Client> {
     public:
      // Asks the client for a DataDecoder.  Pushing the ownership of the
      // DataDecoder to Client implementations help ensure that the same decoder
      // can be reused across different decoding kinds (including non-image
      // decoding).
      virtual data_decoder::DataDecoder* GetDataDecoder() = 0;
  
      // Callback invoked exactly once - when the image sanitization is done. If
      // status is an error, |path| points to the file that caused the error.
      virtual void OnImageSanitizationDone(Status status,
                                           const base::FilePath& path) = 0;
  
      // Callback invoked on a background thread 0..N times (once per image from
      // `image_relative_paths`) whenever an image has been successfully decoded.
      virtual void OnImageDecoded(const base::FilePath& path, SkBitmap image) = 0;
  
     protected:
      friend class base::RefCountedThreadSafe<Client>;
      virtual ~Client();
    };
  
    // Creates an ImageSanitizer and starts the sanitization of the images in
    // |image_relative_paths|. These paths should be relative and not reference
    // their parent dir or an kImagePathError will be reported to |done_callback|.
    // These relative paths are resolved against |image_dir|.
    //
    // |client| provides the DataDecoder to use for image decoding.  |client|'s
    // OnImageDecoded and OnImageSanitizationDone methods will be called with
    // sanitization results (if the returned ImageSanitizer instance is deleted
    // then these callback methods are not called and the sanitization stops
    // promptly (some background tasks may still run)).
    static std::unique_ptr<ImageSanitizer> CreateAndStart(
        scoped_refptr<Client> client,
        const base::FilePath& image_dir,
        const std::set<base::FilePath>& image_relative_paths,
        const scoped_refptr<base::SequencedTaskRunner>& task_runner);
  
    ImageSanitizer(const ImageSanitizer&) = delete;
    ImageSanitizer& operator=(const ImageSanitizer&) = delete;
  
    ~ImageSanitizer();
  
   private:
    ImageSanitizer(
        scoped_refptr<Client> client,
        const base::FilePath& image_dir,
        const std::set<base::FilePath>& image_relative_paths,
        const scoped_refptr<base::SequencedTaskRunner>& io_task_runner);
  
    void Start();
  
    void ImageFileRead(
        const base::FilePath& image_path,
        std::tuple<std::vector<uint8_t>, bool, bool> read_and_delete_result);
  
    void ImageDecoded(const base::FilePath& image_path,
                      const SkBitmap& decoded_image);
  
    void ImageReencoded(const base::FilePath& image_path,
                        std::pair<bool, std::vector<unsigned char>> result);
  
    void ImageWritten(const base::FilePath& image_path,
                      int expected_size,
                      int actual_size);
  
    void ReportSuccess();
    void ReportError(Status status, const base::FilePath& path);
  
    void CleanUp();
  
    base::FilePath image_dir_;
    std::set<base::FilePath> image_paths_;
    scoped_refptr<Client> client_;
    scoped_refptr<base::SequencedTaskRunner> io_task_runner_;
    base::WeakPtrFactory<ImageSanitizer> weak_factory_{this};
  };
  
  }  // namespace extensions
  
  #endif  // EXTENSIONS_BROWSER_IMAGE_SANITIZER_H_
  