15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#ifndef MEDIA_CDM_PPAPI_CDM_FILE_IO_IMPL_H_
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#define MEDIA_CDM_PPAPI_CDM_FILE_IO_IMPL_H_
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <algorithm>
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string>
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <vector>
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/basictypes.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "media/cdm/ppapi/api/content_decryption_module.h"
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/c/ppb_file_io.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/file_io.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/file_ref.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/instance.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/module.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/cpp/private/isolated_file_system_private.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ppapi/utility/completion_callback_factory.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace media {
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Due to PPAPI limitations, all functions must be called on the main thread.
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class CdmFileIOImpl : public cdm::FileIO {
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // A class that helps release |file_lock_map_|.
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // There should be only one instance of ResourceTracker in a process. Also,
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // ResourceTracker should outlive all CdmFileIOImpl instances.
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  class ResourceTracker {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)   public:
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ResourceTracker();
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ~ResourceTracker();
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)   private:
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DISALLOW_COPY_AND_ASSIGN(ResourceTracker);
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CdmFileIOImpl(cdm::FileIOClient* client, PP_Instance pp_instance);
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // cdm::FileIO implementation.
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void Open(const char* file_name, uint32_t file_name_size) OVERRIDE;
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void Read() OVERRIDE;
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void Write(const uint8_t* data, uint32_t data_size) OVERRIDE;
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void Close() OVERRIDE;
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  enum State {
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FILE_UNOPENED,
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OPENING_FILE_SYSTEM,
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OPENING_FILE,
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FILE_OPENED,
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    READING_FILE,
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WRITING_FILE,
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    FILE_CLOSED
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  enum ErrorType {
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OPEN_WHILE_IN_USE,
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    READ_WHILE_IN_USE,
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WRITE_WHILE_IN_USE,
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    OPEN_ERROR,
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    READ_ERROR,
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WRITE_ERROR
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Always use Close() to release |this| object.
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~CdmFileIOImpl();
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |file_id_| -> |is_file_lock_acquired_| map.
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Design detail:
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // - We never erase an entry from this map.
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // - Pros: When the same file is read or written repeatedly, we don't need to
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //   insert/erase the entry repeatedly, which is expensive.
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // - Cons: If there are a lot of one-off files used, this map will be
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //   unnecessarily large. But this should be a rare case.
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // - Ideally we could use unordered_map for this. But unordered_set is only
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //   available in C++11.
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  typedef std::map<std::string, bool> FileLockMap;
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // File lock map shared by all CdmFileIOImpl objects to prevent read/write
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // race. A CdmFileIOImpl object tries to acquire a lock before opening a
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // file. If the file open failed, the lock is released. Otherwise, the
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // CdmFileIOImpl object holds the lock until Close() is called.
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // TODO(xhwang): Investigate the following cases and make sure we are good:
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // - This assumes all CDM instances run in the same process for a given file
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //   system.
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // - When multiple CDM instances are running in different profiles (e.g.
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //   normal/incognito window, multiple profiles), we may be overlocking.
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static FileLockMap* file_lock_map_;
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Sets |file_id_|. Returns false if |file_id_| cannot be set (e.g. origin URL
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // cannot be fetched).
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool SetFileID();
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Acquires the file lock. Returns true if the lock is successfully acquired.
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // After the lock is acquired, other cdm::FileIO objects in the same process
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // and in the same origin will get kInUse when trying to open the same file.
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool AcquireFileLock();
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Releases the file lock so that the file can be opened by other cdm::FileIO
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // objects.
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void ReleaseFileLock();
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OpenFileSystem();
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OnFileSystemOpened(int32_t result, pp::FileSystem file_system);
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OpenFile();
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OnFileOpened(int32_t result);
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void ReadFile();
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OnFileRead(int32_t bytes_read);
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void SetLength(uint32_t length);
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OnLengthSet(int32_t result);
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void WriteFile();
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OnFileWritten(int32_t bytes_written);
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void CloseFile();
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Calls client_->OnXxxxComplete with kError asynchronously. In some cases we
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // could actually call them synchronously, but since these errors shouldn't
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // happen in normal cases, we are not optimizing such cases.
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void OnError(ErrorType error_type);
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Callback to notify client of error asynchronously.
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void NotifyClientOfError(int32_t result, ErrorType error_type);
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  State state_;
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Non-owning pointer.
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  cdm::FileIOClient* const client_;
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const pp::InstanceHandle pp_instance_handle_;
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string file_name_;
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // A string ID that uniquely identifies a file in the user's profile.
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // It consists of the origin of the document URL (including scheme, host and
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // port, delimited by colons) and the |file_name_|.
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // For example: http:example.com:8080/foo_file.txt
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string file_id_;
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pp::IsolatedFileSystemPrivate isolated_file_system_;
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pp::FileSystem file_system_;
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pp::FileIO file_io_;
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pp::FileRef file_ref_;
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  pp::CompletionCallbackFactory<CdmFileIOImpl> callback_factory_;
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // A temporary buffer to hold (partial) data to write or the data that has
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // been read. The size of |io_buffer_| is always "bytes to write" or "bytes to
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // read". Use "char" instead of "unit8_t" because PPB_FileIO uses char* for
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // binary data read and write.
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<char> io_buffer_;
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Offset into the file for reading/writing data. When writing data to the
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // file, this is also the offset to the |io_buffer_|.
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t io_offset_;
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Buffer to hold all read data requested. This buffer is passed to |client_|
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // when read completes.
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<char> cumulative_read_buffer_;
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(CdmFileIOImpl);
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace media
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif  // MEDIA_CDM_PPAPI_CDM_FILE_IO_IMPL_H_
167