1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/media_galleries/fileapi/supported_image_type_validator.h"
6
7#include "base/bind.h"
8#include "base/callback.h"
9#include "base/files/file.h"
10#include "base/location.h"
11#include "base/logging.h"
12#include "base/memory/scoped_ptr.h"
13#include "base/memory/weak_ptr.h"
14#include "base/stl_util.h"
15#include "base/threading/thread_restrictions.h"
16#include "chrome/browser/image_decoder.h"
17#include "content/public/browser/browser_thread.h"
18
19using content::BrowserThread;
20
21namespace {
22
23// Arbitrary limit to sanity check the file size.
24const int kMaxImageFileSize = 50*1014*1024;
25
26scoped_ptr<std::string> ReadOnFileThread(const base::FilePath& path) {
27  base::ThreadRestrictions::AssertIOAllowed();
28  scoped_ptr<std::string> result;
29
30  base::File file(path, base::File::FLAG_OPEN | base::File::FLAG_READ);
31  if (!file.IsValid())
32    return result.Pass();
33
34  base::File::Info file_info;
35  if (!file.GetInfo(&file_info) ||
36      file_info.size > kMaxImageFileSize) {
37    return result.Pass();
38  }
39
40  result.reset(new std::string);
41  result->resize(file_info.size);
42  if (file.Read(0, string_as_array(result.get()), file_info.size) !=
43      file_info.size) {
44    result.reset();
45  }
46
47  return result.Pass();
48}
49
50class ImageDecoderDelegateAdapter : public ImageDecoder::Delegate {
51 public:
52  ImageDecoderDelegateAdapter(
53      scoped_ptr<std::string> data,
54      const storage::CopyOrMoveFileValidator::ResultCallback& callback)
55      : data_(data.Pass()), callback_(callback) {
56    DCHECK(data_);
57  }
58
59  const std::string& data() {
60    return *data_;
61  }
62
63  // ImageDecoder::Delegate methods.
64  virtual void OnImageDecoded(const ImageDecoder* /*decoder*/,
65                              const SkBitmap& /*decoded_image*/) OVERRIDE {
66    callback_.Run(base::File::FILE_OK);
67    delete this;
68  }
69
70  virtual void OnDecodeImageFailed(const ImageDecoder* /*decoder*/) OVERRIDE {
71    callback_.Run(base::File::FILE_ERROR_SECURITY);
72    delete this;
73  }
74
75 private:
76  scoped_ptr<std::string> data_;
77  storage::CopyOrMoveFileValidator::ResultCallback callback_;
78
79  DISALLOW_COPY_AND_ASSIGN(ImageDecoderDelegateAdapter);
80};
81
82}  // namespace
83
84SupportedImageTypeValidator::~SupportedImageTypeValidator() {}
85
86// static
87bool SupportedImageTypeValidator::SupportsFileType(const base::FilePath& path) {
88  base::FilePath::StringType extension = path.Extension();
89  return extension == FILE_PATH_LITERAL(".bmp") ||
90         extension == FILE_PATH_LITERAL(".gif") ||
91         extension == FILE_PATH_LITERAL(".jfif") ||
92         extension == FILE_PATH_LITERAL(".jpeg") ||
93         extension == FILE_PATH_LITERAL(".jpg") ||
94         extension == FILE_PATH_LITERAL(".pjp") ||
95         extension == FILE_PATH_LITERAL(".pjpeg") ||
96         extension == FILE_PATH_LITERAL(".png") ||
97         extension == FILE_PATH_LITERAL(".webp");
98}
99
100void SupportedImageTypeValidator::StartPreWriteValidation(
101    const ResultCallback& result_callback) {
102  DCHECK_CURRENTLY_ON(BrowserThread::IO);
103  DCHECK(callback_.is_null());
104  callback_ = result_callback;
105
106  BrowserThread::PostTaskAndReplyWithResult(
107      BrowserThread::FILE,
108      FROM_HERE,
109      base::Bind(&ReadOnFileThread, path_),
110      base::Bind(&SupportedImageTypeValidator::OnFileOpen,
111                 weak_factory_.GetWeakPtr()));
112}
113
114SupportedImageTypeValidator::SupportedImageTypeValidator(
115    const base::FilePath& path)
116    : path_(path),
117      weak_factory_(this) {
118}
119
120void SupportedImageTypeValidator::OnFileOpen(scoped_ptr<std::string> data) {
121  DCHECK_CURRENTLY_ON(BrowserThread::IO);
122  if (!data.get()) {
123    callback_.Run(base::File::FILE_ERROR_SECURITY);
124    return;
125  }
126
127  // |adapter| will delete itself after a completion message is received.
128  ImageDecoderDelegateAdapter* adapter =
129      new ImageDecoderDelegateAdapter(data.Pass(), callback_);
130  decoder_ = new ImageDecoder(adapter, adapter->data(),
131                              ImageDecoder::DEFAULT_CODEC);
132  decoder_->Start(content::BrowserThread::GetMessageLoopProxyForThread(
133      BrowserThread::IO));
134}
135