This source file includes following definitions.
- file_thread_
- Init
- HandleMessage
- OpenFileSystem
- Save
- Load
- Delete
- List
- ListCallback
- MakeDir
- ShowErrorMessage
- ShowStatusMessage
- CreateInstance
- CreateModule
#define __STDC_LIMIT_MACROS
#include <sstream>
#include <string>
#include "ppapi/c/pp_stdint.h"
#include "ppapi/c/ppb_file_io.h"
#include "ppapi/cpp/directory_entry.h"
#include "ppapi/cpp/file_io.h"
#include "ppapi/cpp/file_ref.h"
#include "ppapi/cpp/file_system.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/message_loop.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"
#include "ppapi/utility/completion_callback_factory.h"
#include "ppapi/utility/threading/simple_thread.h"
#ifndef INT32_MAX
#define INT32_MAX (0x7FFFFFFF)
#endif
#ifdef WIN32
#undef min
#undef max
#undef PostMessage
#pragma warning(disable : 4355)
#endif
namespace {
const char* const kLoadPrefix = "ld";
const char* const kSavePrefix = "sv";
const char* const kDeletePrefix = "de";
const char* const kListPrefix = "ls";
const char* const kMakeDirPrefix = "md";
}
class FileIoInstance : public pp::Instance {
public:
explicit FileIoInstance(PP_Instance instance)
: pp::Instance(instance),
callback_factory_(this),
file_system_(this, PP_FILESYSTEMTYPE_LOCALPERSISTENT),
file_system_ready_(false),
file_thread_(this) {}
virtual ~FileIoInstance() { file_thread_.Join(); }
virtual bool Init(uint32_t ,
const char * [],
const char * []) {
file_thread_.Start();
file_thread_.message_loop().PostWork(
callback_factory_.NewCallback(&FileIoInstance::OpenFileSystem));
return true;
}
private:
pp::CompletionCallbackFactory<FileIoInstance> callback_factory_;
pp::FileSystem file_system_;
bool file_system_ready_;
pp::SimpleThread file_thread_;
virtual void HandleMessage(const pp::Var& var_message) {
if (!var_message.is_string())
return;
std::string message = var_message.AsString();
std::string instruction;
std::string file_name;
std::stringstream reader(message);
int file_name_length;
reader >> instruction >> file_name_length;
file_name.resize(file_name_length);
reader.ignore(1);
reader.read(&file_name[0], file_name_length);
if (file_name.length() == 0 || file_name[0] != '/') {
ShowStatusMessage("File name must begin with /");
return;
}
if (instruction == kLoadPrefix) {
file_thread_.message_loop().PostWork(
callback_factory_.NewCallback(&FileIoInstance::Load, file_name));
} else if (instruction == kSavePrefix) {
reader.ignore(1);
std::string file_text = message.substr(reader.tellg());
file_thread_.message_loop().PostWork(callback_factory_.NewCallback(
&FileIoInstance::Save, file_name, file_text));
} else if (instruction == kDeletePrefix) {
file_thread_.message_loop().PostWork(
callback_factory_.NewCallback(&FileIoInstance::Delete, file_name));
} else if (instruction == kListPrefix) {
const std::string& dir_name = file_name;
file_thread_.message_loop().PostWork(
callback_factory_.NewCallback(&FileIoInstance::List, dir_name));
} else if (instruction == kMakeDirPrefix) {
const std::string& dir_name = file_name;
file_thread_.message_loop().PostWork(
callback_factory_.NewCallback(&FileIoInstance::MakeDir, dir_name));
}
}
void OpenFileSystem(int32_t ) {
int32_t rv = file_system_.Open(1024 * 1024, pp::BlockUntilComplete());
if (rv == PP_OK) {
file_system_ready_ = true;
PostMessage("READY|");
} else {
ShowErrorMessage("Failed to open file system", rv);
}
}
void Save(int32_t ,
const std::string& file_name,
const std::string& file_contents) {
if (!file_system_ready_) {
ShowErrorMessage("File system is not open", PP_ERROR_FAILED);
return;
}
pp::FileRef ref(file_system_, file_name.c_str());
pp::FileIO file(this);
int32_t open_result =
file.Open(ref,
PP_FILEOPENFLAG_WRITE | PP_FILEOPENFLAG_CREATE |
PP_FILEOPENFLAG_TRUNCATE,
pp::BlockUntilComplete());
if (open_result != PP_OK) {
ShowErrorMessage("File open for write failed", open_result);
return;
}
if (!file_contents.empty()) {
if (file_contents.length() > INT32_MAX) {
ShowErrorMessage("File too big", PP_ERROR_FILETOOBIG);
return;
}
int64_t offset = 0;
int32_t bytes_written = 0;
do {
bytes_written = file.Write(offset,
file_contents.data() + offset,
file_contents.length(),
pp::BlockUntilComplete());
if (bytes_written > 0) {
offset += bytes_written;
} else {
ShowErrorMessage("File write failed", bytes_written);
return;
}
} while (bytes_written < static_cast<int64_t>(file_contents.length()));
}
int32_t flush_result = file.Flush(pp::BlockUntilComplete());
if (flush_result != PP_OK) {
ShowErrorMessage("File fail to flush", flush_result);
return;
}
ShowStatusMessage("Save success");
}
void Load(int32_t , const std::string& file_name) {
if (!file_system_ready_) {
ShowErrorMessage("File system is not open", PP_ERROR_FAILED);
return;
}
pp::FileRef ref(file_system_, file_name.c_str());
pp::FileIO file(this);
int32_t open_result =
file.Open(ref, PP_FILEOPENFLAG_READ, pp::BlockUntilComplete());
if (open_result == PP_ERROR_FILENOTFOUND) {
ShowErrorMessage("File not found", open_result);
return;
} else if (open_result != PP_OK) {
ShowErrorMessage("File open for read failed", open_result);
return;
}
PP_FileInfo info;
int32_t query_result = file.Query(&info, pp::BlockUntilComplete());
if (query_result != PP_OK) {
ShowErrorMessage("File query failed", query_result);
return;
}
if (info.size > INT32_MAX) {
ShowErrorMessage("File too big", PP_ERROR_FILETOOBIG);
return;
}
std::vector<char> data(info.size);
int64_t offset = 0;
int32_t bytes_read = 0;
int32_t bytes_to_read = info.size;
while (bytes_to_read > 0) {
bytes_read = file.Read(offset,
&data[offset],
data.size() - offset,
pp::BlockUntilComplete());
if (bytes_read > 0) {
offset += bytes_read;
bytes_to_read -= bytes_read;
} else if (bytes_read < 0) {
ShowErrorMessage("File read failed", bytes_read);
return;
}
}
std::string string_data(data.begin(), data.end());
PostMessage("DISP|" + string_data);
ShowStatusMessage("Load success");
}
void Delete(int32_t , const std::string& file_name) {
if (!file_system_ready_) {
ShowErrorMessage("File system is not open", PP_ERROR_FAILED);
return;
}
pp::FileRef ref(file_system_, file_name.c_str());
int32_t result = ref.Delete(pp::BlockUntilComplete());
if (result == PP_ERROR_FILENOTFOUND) {
ShowStatusMessage("File/Directory not found");
return;
} else if (result != PP_OK) {
ShowErrorMessage("Deletion failed", result);
return;
}
ShowStatusMessage("Delete success");
}
void List(int32_t , const std::string& dir_name) {
if (!file_system_ready_) {
ShowErrorMessage("File system is not open", PP_ERROR_FAILED);
return;
}
pp::FileRef ref(file_system_, dir_name.c_str());
ref.ReadDirectoryEntries(callback_factory_.NewCallbackWithOutput(
&FileIoInstance::ListCallback, ref));
}
void ListCallback(int32_t result,
const std::vector<pp::DirectoryEntry>& entries,
pp::FileRef ) {
if (result != PP_OK) {
ShowErrorMessage("List failed", result);
return;
}
std::stringstream ss;
ss << "LIST";
for (size_t i = 0; i < entries.size(); ++i) {
pp::Var name = entries[i].file_ref().GetName();
if (name.is_string()) {
ss << "|" << name.AsString();
}
}
PostMessage(ss.str());
ShowStatusMessage("List success");
}
void MakeDir(int32_t , const std::string& dir_name) {
if (!file_system_ready_) {
ShowErrorMessage("File system is not open", PP_ERROR_FAILED);
return;
}
pp::FileRef ref(file_system_, dir_name.c_str());
int32_t result = ref.MakeDirectory(
PP_MAKEDIRECTORYFLAG_NONE, pp::BlockUntilComplete());
if (result != PP_OK) {
ShowErrorMessage("Make directory failed", result);
return;
}
ShowStatusMessage("Make directory success");
}
void ShowErrorMessage(const std::string& message, int32_t result) {
std::stringstream ss;
ss << "ERR|" << message << " -- Error #: " << result;
PostMessage(ss.str());
}
void ShowStatusMessage(const std::string& message) {
std::stringstream ss;
ss << "STAT|" << message;
PostMessage(ss.str());
}
};
class FileIoModule : public pp::Module {
public:
FileIoModule() : pp::Module() {}
virtual ~FileIoModule() {}
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new FileIoInstance(instance);
}
};
namespace pp {
Module* CreateModule() { return new FileIoModule(); }
}