summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/test/ppapi/ppapi_browsertest.cc3
-rw-r--r--ppapi/api/ppb_file_io.idl32
-rw-r--r--ppapi/c/ppb_file_io.h68
-rw-r--r--ppapi/cpp/array_output.h2
-rw-r--r--ppapi/cpp/file_io.cc162
-rw-r--r--ppapi/cpp/file_io.h52
-rw-r--r--ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_file_io.cc3
-rw-r--r--ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c92
-rw-r--r--ppapi/proxy/ppb_file_io_proxy.cc14
-rw-r--r--ppapi/shared_impl/array_writer.h21
-rw-r--r--ppapi/shared_impl/ppb_file_io_shared.cc49
-rw-r--r--ppapi/shared_impl/ppb_file_io_shared.h17
-rw-r--r--ppapi/tests/test_file_io.cc168
-rw-r--r--ppapi/tests/test_file_io.h2
-rw-r--r--ppapi/tests/test_utils.h52
-rw-r--r--ppapi/thunk/interfaces_ppb_public_stable.h1
-rw-r--r--ppapi/thunk/ppb_file_io_api.h4
-rw-r--r--ppapi/thunk/ppb_file_io_thunk.cc34
-rw-r--r--webkit/plugins/ppapi/ppb_file_io_impl.cc8
-rw-r--r--webkit/plugins/ppapi/ppb_file_io_impl.h4
20 files changed, 701 insertions, 87 deletions
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index fed7521..01c07ed 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -510,6 +510,7 @@ TEST_PPAPI_IN_PROCESS_VIA_HTTP(FileIO_ParallelReads)
TEST_PPAPI_IN_PROCESS_VIA_HTTP(FileIO_ParallelWrites)
TEST_PPAPI_IN_PROCESS_VIA_HTTP(FileIO_NotAllowMixedReadWrite)
TEST_PPAPI_IN_PROCESS_VIA_HTTP(FileIO_ReadWriteSetLength)
+TEST_PPAPI_IN_PROCESS_VIA_HTTP(FileIO_ReadToArrayWriteSetLength)
TEST_PPAPI_IN_PROCESS_VIA_HTTP(FileIO_TouchQuery)
TEST_PPAPI_IN_PROCESS_VIA_HTTP(FileIO_WillWriteWillSetLength)
@@ -519,6 +520,7 @@ TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(FileIO_ParallelReads)
TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(FileIO_ParallelWrites)
TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(FileIO_NotAllowMixedReadWrite)
TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(FileIO_ReadWriteSetLength)
+TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(FileIO_ReadToArrayWriteSetLength)
TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(FileIO_TouchQuery)
TEST_PPAPI_OUT_OF_PROCESS_VIA_HTTP(FileIO_WillWriteWillSetLength)
@@ -552,6 +554,7 @@ TEST_PPAPI_NACL_VIA_HTTP(FileIO_ParallelWrites)
TEST_PPAPI_NACL_VIA_HTTP(FileIO_NotAllowMixedReadWrite)
TEST_PPAPI_NACL_VIA_HTTP(MAYBE_NACL_FileIO_TouchQuery)
TEST_PPAPI_NACL_VIA_HTTP(FileIO_ReadWriteSetLength)
+TEST_PPAPI_NACL_VIA_HTTP(FileIO_ReadToArrayWriteSetLength)
// The following test requires PPB_FileIO_Trusted, not available in NaCl.
TEST_PPAPI_NACL_VIA_HTTP(DISABLED_FileIO_WillWriteWillSetLength)
diff --git a/ppapi/api/ppb_file_io.idl b/ppapi/api/ppb_file_io.idl
index 58f3f13..23e97ca 100644
--- a/ppapi/api/ppb_file_io.idl
+++ b/ppapi/api/ppb_file_io.idl
@@ -9,7 +9,8 @@
*/
label Chrome {
- M14 = 1.0
+ M14 = 1.0,
+ M25 = 1.1
};
/**
@@ -145,6 +146,8 @@ interface PPB_FileIO {
* large enough to hold the specified number of bytes to read. This function
* might perform a partial read.
*
+ * ReadToArray() is preferred to Read() when doing asynchronous operations.
+ *
* @param[in] file_io A <code>PP_Resource</code> corresponding to a file
* FileIO.
* @param[in] offset The offset into the file.
@@ -240,5 +243,32 @@ interface PPB_FileIO {
* FileIO.
*/
void Close([in] PP_Resource file_io);
+
+ /**
+ * ReadToArray() reads from an offset in the file. A PP_ArrayOutput must be
+ * provided so that output will be stored in its allocated buffer. This
+ * function might perform a partial read.
+ *
+ * @param[in] file_io A <code>PP_Resource</code> corresponding to a file
+ * FileIO.
+ * @param[in] offset The offset into the file.
+ * @param[in] max_read_length The maximum number of bytes to read from
+ * <code>offset</code>.
+ * @param[in] output A <code>PP_ArrayOutput</code> to hold the output data.
+ * @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
+ * completion of ReadToArray().
+ *
+ * @return The number of bytes read or an error code from
+ * <code>pp_errors.h</code>. If the return value is 0, then end-of-file was
+ * reached. It is valid to call ReadToArray() multiple times with a completion
+ * callback to queue up parallel reads from the file, but pending reads
+ * cannot be interleaved with other operations.
+ */
+ [version = 1.1]
+ int32_t ReadToArray([in] PP_Resource file_io,
+ [in] int64_t offset,
+ [in] int32_t max_read_length,
+ [inout] PP_ArrayOutput output,
+ [in] PP_CompletionCallback callback);
};
diff --git a/ppapi/c/ppb_file_io.h b/ppapi/c/ppb_file_io.h
index 4b9db95..43fcdb9 100644
--- a/ppapi/c/ppb_file_io.h
+++ b/ppapi/c/ppb_file_io.h
@@ -3,11 +3,12 @@
* found in the LICENSE file.
*/
-/* From ppb_file_io.idl modified Wed Feb 15 15:55:56 2012. */
+/* From ppb_file_io.idl modified Thu Nov 15 08:08:30 2012. */
#ifndef PPAPI_C_PPB_FILE_IO_H_
#define PPAPI_C_PPB_FILE_IO_H_
+#include "ppapi/c/pp_array_output.h"
#include "ppapi/c/pp_bool.h"
#include "ppapi/c/pp_completion_callback.h"
#include "ppapi/c/pp_file_info.h"
@@ -18,7 +19,8 @@
#include "ppapi/c/pp_time.h"
#define PPB_FILEIO_INTERFACE_1_0 "PPB_FileIO;1.0"
-#define PPB_FILEIO_INTERFACE PPB_FILEIO_INTERFACE_1_0
+#define PPB_FILEIO_INTERFACE_1_1 "PPB_FileIO;1.1"
+#define PPB_FILEIO_INTERFACE PPB_FILEIO_INTERFACE_1_1
/**
* @file
@@ -73,7 +75,7 @@ PP_COMPILE_ASSERT_SIZE_IN_BYTES(PP_FileOpenFlags, 4);
* The <code>PPB_FileIO</code> struct is used to operate on a regular file
* (PP_FileType_Regular).
*/
-struct PPB_FileIO_1_0 {
+struct PPB_FileIO_1_1 {
/**
* Create() creates a new FileIO object.
*
@@ -161,6 +163,8 @@ struct PPB_FileIO_1_0 {
* large enough to hold the specified number of bytes to read. This function
* might perform a partial read.
*
+ * ReadToArray() is preferred to Read() when doing asynchronous operations.
+ *
* @param[in] file_io A <code>PP_Resource</code> corresponding to a file
* FileIO.
* @param[in] offset The offset into the file.
@@ -252,9 +256,65 @@ struct PPB_FileIO_1_0 {
* FileIO.
*/
void (*Close)(PP_Resource file_io);
+ /**
+ * ReadToArray() reads from an offset in the file. A PP_ArrayOutput must be
+ * provided so that output will be stored in its allocated buffer. This
+ * function might perform a partial read.
+ *
+ * @param[in] file_io A <code>PP_Resource</code> corresponding to a file
+ * FileIO.
+ * @param[in] offset The offset into the file.
+ * @param[in] max_read_length The maximum number of bytes to read from
+ * <code>offset</code>.
+ * @param[in] output A <code>PP_ArrayOutput</code> to hold the output data.
+ * @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
+ * completion of ReadToArray().
+ *
+ * @return The number of bytes read or an error code from
+ * <code>pp_errors.h</code>. If the return value is 0, then end-of-file was
+ * reached. It is valid to call ReadToArray() multiple times with a completion
+ * callback to queue up parallel reads from the file, but pending reads
+ * cannot be interleaved with other operations.
+ */
+ int32_t (*ReadToArray)(PP_Resource file_io,
+ int64_t offset,
+ int32_t max_read_length,
+ struct PP_ArrayOutput* output,
+ struct PP_CompletionCallback callback);
};
-typedef struct PPB_FileIO_1_0 PPB_FileIO;
+typedef struct PPB_FileIO_1_1 PPB_FileIO;
+
+struct PPB_FileIO_1_0 {
+ PP_Resource (*Create)(PP_Instance instance);
+ PP_Bool (*IsFileIO)(PP_Resource resource);
+ int32_t (*Open)(PP_Resource file_io,
+ PP_Resource file_ref,
+ int32_t open_flags,
+ struct PP_CompletionCallback callback);
+ int32_t (*Query)(PP_Resource file_io,
+ struct PP_FileInfo* info,
+ struct PP_CompletionCallback callback);
+ int32_t (*Touch)(PP_Resource file_io,
+ PP_Time last_access_time,
+ PP_Time last_modified_time,
+ struct PP_CompletionCallback callback);
+ int32_t (*Read)(PP_Resource file_io,
+ int64_t offset,
+ char* buffer,
+ int32_t bytes_to_read,
+ struct PP_CompletionCallback callback);
+ int32_t (*Write)(PP_Resource file_io,
+ int64_t offset,
+ const char* buffer,
+ int32_t bytes_to_write,
+ struct PP_CompletionCallback callback);
+ int32_t (*SetLength)(PP_Resource file_io,
+ int64_t length,
+ struct PP_CompletionCallback callback);
+ int32_t (*Flush)(PP_Resource file_io, struct PP_CompletionCallback callback);
+ void (*Close)(PP_Resource file_io);
+};
/**
* @}
*/
diff --git a/ppapi/cpp/array_output.h b/ppapi/cpp/array_output.h
index 57fa790..fe0bbc3 100644
--- a/ppapi/cpp/array_output.h
+++ b/ppapi/cpp/array_output.h
@@ -176,7 +176,7 @@ template<typename T>
class ArrayOutputAdapterWithStorage : public ArrayOutputAdapter<T> {
public:
ArrayOutputAdapterWithStorage() {
- set_output(&output_storage_);
+ this->set_output(&output_storage_);
}
std::vector<T>& output() { return output_storage_; }
diff --git a/ppapi/cpp/file_io.cc b/ppapi/cpp/file_io.cc
index e596577..faaf284 100644
--- a/ppapi/cpp/file_io.cc
+++ b/ppapi/cpp/file_io.cc
@@ -4,9 +4,12 @@
#include "ppapi/cpp/file_io.h"
+#include <string.h> // memcpy
+
#include "ppapi/c/ppb_file_io.h"
#include "ppapi/c/pp_errors.h"
#include "ppapi/cpp/completion_callback.h"
+#include "ppapi/cpp/dev/resource_array_dev.h"
#include "ppapi/cpp/file_ref.h"
#include "ppapi/cpp/instance_handle.h"
#include "ppapi/cpp/module.h"
@@ -20,16 +23,23 @@ template <> const char* interface_name<PPB_FileIO_1_0>() {
return PPB_FILEIO_INTERFACE_1_0;
}
+template <> const char* interface_name<PPB_FileIO_1_1>() {
+ return PPB_FILEIO_INTERFACE_1_1;
+}
+
} // namespace
FileIO::FileIO() {
}
FileIO::FileIO(const InstanceHandle& instance) {
- if (!has_interface<PPB_FileIO_1_0>())
- return;
- PassRefFromConstructor(get_interface<PPB_FileIO_1_0>()->Create(
- instance.pp_instance()));
+ if (has_interface<PPB_FileIO_1_1>()) {
+ PassRefFromConstructor(get_interface<PPB_FileIO_1_1>()->Create(
+ instance.pp_instance()));
+ } else if (has_interface<PPB_FileIO_1_0>()) {
+ PassRefFromConstructor(get_interface<PPB_FileIO_1_0>()->Create(
+ instance.pp_instance()));
+ }
}
FileIO::FileIO(const FileIO& other)
@@ -39,71 +49,147 @@ FileIO::FileIO(const FileIO& other)
int32_t FileIO::Open(const FileRef& file_ref,
int32_t open_flags,
const CompletionCallback& cc) {
- if (!has_interface<PPB_FileIO_1_0>())
- return cc.MayForce(PP_ERROR_NOINTERFACE);
- return get_interface<PPB_FileIO_1_0>()->Open(
- pp_resource(), file_ref.pp_resource(), open_flags,
- cc.pp_completion_callback());
+ if (has_interface<PPB_FileIO_1_1>()) {
+ return get_interface<PPB_FileIO_1_1>()->Open(
+ pp_resource(), file_ref.pp_resource(), open_flags,
+ cc.pp_completion_callback());
+ } else if (has_interface<PPB_FileIO_1_0>()) {
+ return get_interface<PPB_FileIO_1_0>()->Open(
+ pp_resource(), file_ref.pp_resource(), open_flags,
+ cc.pp_completion_callback());
+ }
+ return cc.MayForce(PP_ERROR_NOINTERFACE);
}
int32_t FileIO::Query(PP_FileInfo* result_buf,
const CompletionCallback& cc) {
- if (!has_interface<PPB_FileIO_1_0>())
- return cc.MayForce(PP_ERROR_NOINTERFACE);
- return get_interface<PPB_FileIO_1_0>()->Query(
- pp_resource(), result_buf, cc.pp_completion_callback());
+ if (has_interface<PPB_FileIO_1_1>()) {
+ return get_interface<PPB_FileIO_1_1>()->Query(
+ pp_resource(), result_buf, cc.pp_completion_callback());
+ } else if (has_interface<PPB_FileIO_1_0>()) {
+ return get_interface<PPB_FileIO_1_0>()->Query(
+ pp_resource(), result_buf, cc.pp_completion_callback());
+ }
+ return cc.MayForce(PP_ERROR_NOINTERFACE);
}
int32_t FileIO::Touch(PP_Time last_access_time,
PP_Time last_modified_time,
const CompletionCallback& cc) {
- if (!has_interface<PPB_FileIO_1_0>())
- return cc.MayForce(PP_ERROR_NOINTERFACE);
- return get_interface<PPB_FileIO_1_0>()->Touch(
- pp_resource(), last_access_time, last_modified_time,
- cc.pp_completion_callback());
+ if (has_interface<PPB_FileIO_1_1>()) {
+ return get_interface<PPB_FileIO_1_1>()->Touch(
+ pp_resource(), last_access_time, last_modified_time,
+ cc.pp_completion_callback());
+ } else if (has_interface<PPB_FileIO_1_0>()) {
+ return get_interface<PPB_FileIO_1_0>()->Touch(
+ pp_resource(), last_access_time, last_modified_time,
+ cc.pp_completion_callback());
+ }
+ return cc.MayForce(PP_ERROR_NOINTERFACE);
}
int32_t FileIO::Read(int64_t offset,
char* buffer,
int32_t bytes_to_read,
const CompletionCallback& cc) {
- if (!has_interface<PPB_FileIO_1_0>())
- return cc.MayForce(PP_ERROR_NOINTERFACE);
- return get_interface<PPB_FileIO_1_0>()->Read(pp_resource(),
- offset, buffer, bytes_to_read, cc.pp_completion_callback());
+ if (has_interface<PPB_FileIO_1_1>()) {
+ return get_interface<PPB_FileIO_1_1>()->Read(pp_resource(),
+ offset, buffer, bytes_to_read, cc.pp_completion_callback());
+ } else if (has_interface<PPB_FileIO_1_0>()) {
+ return get_interface<PPB_FileIO_1_0>()->Read(pp_resource(),
+ offset, buffer, bytes_to_read, cc.pp_completion_callback());
+ }
+ return cc.MayForce(PP_ERROR_NOINTERFACE);
+}
+
+int32_t FileIO::Read(
+ int32_t offset,
+ int32_t max_read_length,
+ const CompletionCallbackWithOutput< std::vector<char> >& cc) {
+ if (has_interface<PPB_FileIO_1_1>()) {
+ PP_ArrayOutput array_output = cc.output();
+ return get_interface<PPB_FileIO_1_1>()->ReadToArray(pp_resource(),
+ offset, max_read_length, &array_output,
+ cc.pp_completion_callback());
+ } else if (has_interface<PPB_FileIO_1_0>()) {
+ // Data for our callback wrapper. The callback handler will delete it and
+ // temp_buffer.
+ CallbackData1_0* data = new CallbackData1_0;
+ data->output = cc.output();
+ data->temp_buffer = max_read_length >= 0 ? new char[max_read_length] : NULL;
+ data->original_callback = cc.pp_completion_callback();
+
+ // Actual returned bytes might not equals to max_read_length. We need to
+ // read to a temporary buffer first and copy later to make sure the array
+ // buffer has correct size.
+ return get_interface<PPB_FileIO_1_0>()->Read(
+ pp_resource(), offset, data->temp_buffer, max_read_length,
+ PP_MakeCompletionCallback(&CallbackConverter, data));
+ }
+ return cc.MayForce(PP_ERROR_NOINTERFACE);
}
int32_t FileIO::Write(int64_t offset,
const char* buffer,
int32_t bytes_to_write,
const CompletionCallback& cc) {
- if (!has_interface<PPB_FileIO_1_0>())
- return cc.MayForce(PP_ERROR_NOINTERFACE);
- return get_interface<PPB_FileIO_1_0>()->Write(
- pp_resource(), offset, buffer, bytes_to_write,
- cc.pp_completion_callback());
+ if (has_interface<PPB_FileIO_1_1>()) {
+ return get_interface<PPB_FileIO_1_1>()->Write(
+ pp_resource(), offset, buffer, bytes_to_write,
+ cc.pp_completion_callback());
+ } else if (has_interface<PPB_FileIO_1_0>()) {
+ return get_interface<PPB_FileIO_1_0>()->Write(
+ pp_resource(), offset, buffer, bytes_to_write,
+ cc.pp_completion_callback());
+ }
+ return cc.MayForce(PP_ERROR_NOINTERFACE);
}
int32_t FileIO::SetLength(int64_t length,
const CompletionCallback& cc) {
- if (!has_interface<PPB_FileIO_1_0>())
- return cc.MayForce(PP_ERROR_NOINTERFACE);
- return get_interface<PPB_FileIO_1_0>()->SetLength(
- pp_resource(), length, cc.pp_completion_callback());
+ if (has_interface<PPB_FileIO_1_1>()) {
+ return get_interface<PPB_FileIO_1_1>()->SetLength(
+ pp_resource(), length, cc.pp_completion_callback());
+ } else if (has_interface<PPB_FileIO_1_0>()) {
+ return get_interface<PPB_FileIO_1_0>()->SetLength(
+ pp_resource(), length, cc.pp_completion_callback());
+ }
+ return cc.MayForce(PP_ERROR_NOINTERFACE);
}
int32_t FileIO::Flush(const CompletionCallback& cc) {
- if (!has_interface<PPB_FileIO_1_0>())
- return cc.MayForce(PP_ERROR_NOINTERFACE);
- return get_interface<PPB_FileIO_1_0>()->Flush(
- pp_resource(), cc.pp_completion_callback());
+ if (has_interface<PPB_FileIO_1_1>()) {
+ return get_interface<PPB_FileIO_1_1>()->Flush(
+ pp_resource(), cc.pp_completion_callback());
+ } else if (has_interface<PPB_FileIO_1_0>()) {
+ return get_interface<PPB_FileIO_1_0>()->Flush(
+ pp_resource(), cc.pp_completion_callback());
+ }
+ return cc.MayForce(PP_ERROR_NOINTERFACE);
}
void FileIO::Close() {
- if (!has_interface<PPB_FileIO_1_0>())
- return;
- get_interface<PPB_FileIO_1_0>()->Close(pp_resource());
+ if (has_interface<PPB_FileIO_1_1>())
+ get_interface<PPB_FileIO_1_1>()->Close(pp_resource());
+ else if (has_interface<PPB_FileIO_1_0>())
+ get_interface<PPB_FileIO_1_0>()->Close(pp_resource());
+}
+
+// static
+void FileIO::CallbackConverter(void* user_data, int32_t result) {
+ CallbackData1_0* data = static_cast<CallbackData1_0*>(user_data);
+
+ if (result >= 0) {
+ // Copy to the destination buffer owned by the callback.
+ char* buffer = static_cast<char*>(data->output.GetDataBuffer(
+ data->output.user_data, result, sizeof(char)));
+ memcpy(buffer, data->temp_buffer, result);
+ delete[] data->temp_buffer;
+ }
+
+ // Now execute the original callback.
+ PP_RunCompletionCallback(&data->original_callback, result);
+ delete data;
}
} // namespace pp
diff --git a/ppapi/cpp/file_io.h b/ppapi/cpp/file_io.h
index 0d8dcc9..3b93bfe 100644
--- a/ppapi/cpp/file_io.h
+++ b/ppapi/cpp/file_io.h
@@ -6,6 +6,7 @@
#define PPAPI_CPP_FILE_IO_H_
#include "ppapi/c/pp_time.h"
+#include "ppapi/cpp/completion_callback.h"
#include "ppapi/cpp/resource.h"
/// @file
@@ -15,7 +16,6 @@ struct PP_FileInfo;
namespace pp {
-class CompletionCallback;
class FileRef;
class InstanceHandle;
@@ -87,6 +87,19 @@ class FileIO : public Resource {
/// large enough to hold the specified number of bytes to read. This
/// function might perform a partial read.
///
+ /// <strong>Caveat:</strong> This Read() is potentially unsafe if you're using
+ /// a CompletionCallbackFactory to scope callbacks to the lifetime of your
+ /// class. When your class goes out of scope, the callback factory will not
+ /// actually cancel the callback, but will rather just skip issuing the
+ /// callback on your class. This means that if the FileIO object outlives
+ /// your class (if you made a copy saved somewhere else, for example), then
+ /// the browser will still try to write into your buffer when the
+ /// asynchronous read completes, potentially causing a crash.
+ ///
+ /// See the other version of Read() which avoids this problem by writing into
+ /// CompletionCallbackWithOutput, where the output buffer is automatically
+ /// managed by the callback.
+ ///
/// @param[in] offset The offset into the file.
/// @param[in] buffer The buffer to hold the specified number of bytes read.
/// @param[in] bytes_to_read The number of bytes to read from
@@ -103,6 +116,28 @@ class FileIO : public Resource {
int32_t bytes_to_read,
const CompletionCallback& cc);
+ /// Read() reads from an offset in the file. A PP_ArrayOutput must be
+ /// provided so that output will be stored in its allocated buffer. This
+ /// function might perform a partial read.
+ ///
+ /// @param[in] file_io A <code>PP_Resource</code> corresponding to a file
+ /// FileIO.
+ /// @param[in] offset The offset into the file.
+ /// @param[in] max_read_length The maximum number of bytes to read from
+ /// <code>offset</code>.
+ /// @param[in] output A <code>PP_ArrayOutput</code> to hold the output data.
+ /// @param[in] callback A <code>PP_CompletionCallback</code> to be called upon
+ /// completion of Read().
+ ///
+ /// @return The number of bytes read or an error code from
+ /// <code>pp_errors.h</code>. If the return value is 0, then end-of-file was
+ /// reached. It is valid to call Read() multiple times with a completion
+ /// callback to queue up parallel reads from the file, but pending reads
+ /// cannot be interleaved with other operations.
+ int32_t Read(int32_t offset,
+ int32_t max_read_length,
+ const CompletionCallbackWithOutput< std::vector<char> >& cc);
+
/// Write() writes to an offset in the file. This function might perform a
/// partial write. The FileIO object must have been opened with write access.
///
@@ -153,6 +188,21 @@ class FileIO : public Resource {
/// open, then it will be implicitly closed, so you are not required to call
/// Close().
void Close();
+
+ private:
+ struct CallbackData1_0 {
+ PP_ArrayOutput output;
+ char* temp_buffer;
+ PP_CompletionCallback original_callback;
+ };
+
+ // Provide backwards-compatability for older Read versions. Converts the
+ // old-style "char*" output buffer of 1.0 to the new "PP_ArrayOutput"
+ // interface in 1.1.
+ //
+ // This takes a heap-allocated CallbackData1_0 struct passed as the user data
+ // and deletes it when the call completes.
+ static void CallbackConverter(void* user_data, int32_t result);
};
} // namespace pp
diff --git a/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_file_io.cc b/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_file_io.cc
index 1cdfe7a..b538532 100644
--- a/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_file_io.cc
+++ b/ppapi/native_client/src/shared/ppapi_proxy/plugin_ppb_file_io.cc
@@ -295,7 +295,8 @@ const PPB_FileIO* PluginFileIO::GetInterface() {
Write,
SetLength,
Flush,
- Close
+ Close,
+ NULL // TODO: support ReadToArray
};
return &file_io_interface;
}
diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
index a3b055c..1231f031 100644
--- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
+++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/pnacl_shim.c
@@ -119,6 +119,7 @@ static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_AudioConfig_1_0;
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_AudioConfig_1_1;
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Core_1_0;
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_FileIO_1_0;
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_FileIO_1_1;
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_FileRef_1_0;
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_FileSystem_1_0;
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_Fullscreen_1_0;
@@ -356,6 +357,76 @@ void Pnacl_M14_PPB_FileIO_Close(PP_Resource file_io) {
/* End wrapper methods for PPB_FileIO_1_0 */
+/* Begin wrapper methods for PPB_FileIO_1_1 */
+
+static __attribute__((pnaclcall))
+PP_Resource Pnacl_M25_PPB_FileIO_Create(PP_Instance instance) {
+ const struct PPB_FileIO_1_1 *iface = Pnacl_WrapperInfo_PPB_FileIO_1_1.real_iface;
+ return iface->Create(instance);
+}
+
+static __attribute__((pnaclcall))
+PP_Bool Pnacl_M25_PPB_FileIO_IsFileIO(PP_Resource resource) {
+ const struct PPB_FileIO_1_1 *iface = Pnacl_WrapperInfo_PPB_FileIO_1_1.real_iface;
+ return iface->IsFileIO(resource);
+}
+
+static __attribute__((pnaclcall))
+int32_t Pnacl_M25_PPB_FileIO_Open(PP_Resource file_io, PP_Resource file_ref, int32_t open_flags, struct PP_CompletionCallback callback) {
+ const struct PPB_FileIO_1_1 *iface = Pnacl_WrapperInfo_PPB_FileIO_1_1.real_iface;
+ return iface->Open(file_io, file_ref, open_flags, callback);
+}
+
+static __attribute__((pnaclcall))
+int32_t Pnacl_M25_PPB_FileIO_Query(PP_Resource file_io, struct PP_FileInfo* info, struct PP_CompletionCallback callback) {
+ const struct PPB_FileIO_1_1 *iface = Pnacl_WrapperInfo_PPB_FileIO_1_1.real_iface;
+ return iface->Query(file_io, info, callback);
+}
+
+static __attribute__((pnaclcall))
+int32_t Pnacl_M25_PPB_FileIO_Touch(PP_Resource file_io, PP_Time last_access_time, PP_Time last_modified_time, struct PP_CompletionCallback callback) {
+ const struct PPB_FileIO_1_1 *iface = Pnacl_WrapperInfo_PPB_FileIO_1_1.real_iface;
+ return iface->Touch(file_io, last_access_time, last_modified_time, callback);
+}
+
+static __attribute__((pnaclcall))
+int32_t Pnacl_M25_PPB_FileIO_Read(PP_Resource file_io, int64_t offset, char* buffer, int32_t bytes_to_read, struct PP_CompletionCallback callback) {
+ const struct PPB_FileIO_1_1 *iface = Pnacl_WrapperInfo_PPB_FileIO_1_1.real_iface;
+ return iface->Read(file_io, offset, buffer, bytes_to_read, callback);
+}
+
+static __attribute__((pnaclcall))
+int32_t Pnacl_M25_PPB_FileIO_Write(PP_Resource file_io, int64_t offset, const char* buffer, int32_t bytes_to_write, struct PP_CompletionCallback callback) {
+ const struct PPB_FileIO_1_1 *iface = Pnacl_WrapperInfo_PPB_FileIO_1_1.real_iface;
+ return iface->Write(file_io, offset, buffer, bytes_to_write, callback);
+}
+
+static __attribute__((pnaclcall))
+int32_t Pnacl_M25_PPB_FileIO_SetLength(PP_Resource file_io, int64_t length, struct PP_CompletionCallback callback) {
+ const struct PPB_FileIO_1_1 *iface = Pnacl_WrapperInfo_PPB_FileIO_1_1.real_iface;
+ return iface->SetLength(file_io, length, callback);
+}
+
+static __attribute__((pnaclcall))
+int32_t Pnacl_M25_PPB_FileIO_Flush(PP_Resource file_io, struct PP_CompletionCallback callback) {
+ const struct PPB_FileIO_1_1 *iface = Pnacl_WrapperInfo_PPB_FileIO_1_1.real_iface;
+ return iface->Flush(file_io, callback);
+}
+
+static __attribute__((pnaclcall))
+void Pnacl_M25_PPB_FileIO_Close(PP_Resource file_io) {
+ const struct PPB_FileIO_1_1 *iface = Pnacl_WrapperInfo_PPB_FileIO_1_1.real_iface;
+ iface->Close(file_io);
+}
+
+static __attribute__((pnaclcall))
+int32_t Pnacl_M25_PPB_FileIO_ReadToArray(PP_Resource file_io, int64_t offset, int32_t max_read_length, struct PP_ArrayOutput* output, struct PP_CompletionCallback callback) {
+ const struct PPB_FileIO_1_1 *iface = Pnacl_WrapperInfo_PPB_FileIO_1_1.real_iface;
+ return iface->ReadToArray(file_io, offset, max_read_length, output, callback);
+}
+
+/* End wrapper methods for PPB_FileIO_1_1 */
+
/* Begin wrapper methods for PPB_FileRef_1_0 */
static __attribute__((pnaclcall))
@@ -3466,6 +3537,20 @@ struct PPB_FileIO_1_0 Pnacl_Wrappers_PPB_FileIO_1_0 = {
.Close = (void (*)(PP_Resource file_io))&Pnacl_M14_PPB_FileIO_Close
};
+struct PPB_FileIO_1_1 Pnacl_Wrappers_PPB_FileIO_1_1 = {
+ .Create = (PP_Resource (*)(PP_Instance instance))&Pnacl_M25_PPB_FileIO_Create,
+ .IsFileIO = (PP_Bool (*)(PP_Resource resource))&Pnacl_M25_PPB_FileIO_IsFileIO,
+ .Open = (int32_t (*)(PP_Resource file_io, PP_Resource file_ref, int32_t open_flags, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_FileIO_Open,
+ .Query = (int32_t (*)(PP_Resource file_io, struct PP_FileInfo* info, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_FileIO_Query,
+ .Touch = (int32_t (*)(PP_Resource file_io, PP_Time last_access_time, PP_Time last_modified_time, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_FileIO_Touch,
+ .Read = (int32_t (*)(PP_Resource file_io, int64_t offset, char* buffer, int32_t bytes_to_read, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_FileIO_Read,
+ .Write = (int32_t (*)(PP_Resource file_io, int64_t offset, const char* buffer, int32_t bytes_to_write, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_FileIO_Write,
+ .SetLength = (int32_t (*)(PP_Resource file_io, int64_t length, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_FileIO_SetLength,
+ .Flush = (int32_t (*)(PP_Resource file_io, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_FileIO_Flush,
+ .Close = (void (*)(PP_Resource file_io))&Pnacl_M25_PPB_FileIO_Close,
+ .ReadToArray = (int32_t (*)(PP_Resource file_io, int64_t offset, int32_t max_read_length, struct PP_ArrayOutput* output, struct PP_CompletionCallback callback))&Pnacl_M25_PPB_FileIO_ReadToArray
+};
+
struct PPB_FileRef_1_0 Pnacl_Wrappers_PPB_FileRef_1_0 = {
.Create = (PP_Resource (*)(PP_Resource file_system, const char* path))&Pnacl_M14_PPB_FileRef_Create,
.IsFileRef = (PP_Bool (*)(PP_Resource resource))&Pnacl_M14_PPB_FileRef_IsFileRef,
@@ -4266,6 +4351,12 @@ static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_FileIO_1_0 = {
.real_iface = NULL
};
+static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_FileIO_1_1 = {
+ .iface_macro = PPB_FILEIO_INTERFACE_1_1,
+ .wrapped_iface = (void *) &Pnacl_Wrappers_PPB_FileIO_1_1,
+ .real_iface = NULL
+};
+
static struct __PnaclWrapperInfo Pnacl_WrapperInfo_PPB_FileRef_1_0 = {
.iface_macro = PPB_FILEREF_INTERFACE_1_0,
.wrapped_iface = (void *) &Pnacl_Wrappers_PPB_FileRef_1_0,
@@ -5022,6 +5113,7 @@ static struct __PnaclWrapperInfo *s_ppb_wrappers[] = {
&Pnacl_WrapperInfo_PPB_AudioConfig_1_1,
&Pnacl_WrapperInfo_PPB_Core_1_0,
&Pnacl_WrapperInfo_PPB_FileIO_1_0,
+ &Pnacl_WrapperInfo_PPB_FileIO_1_1,
&Pnacl_WrapperInfo_PPB_FileRef_1_0,
&Pnacl_WrapperInfo_PPB_FileSystem_1_0,
&Pnacl_WrapperInfo_PPB_Fullscreen_1_0,
diff --git a/ppapi/proxy/ppb_file_io_proxy.cc b/ppapi/proxy/ppb_file_io_proxy.cc
index e367da4..002efdf 100644
--- a/ppapi/proxy/ppb_file_io_proxy.cc
+++ b/ppapi/proxy/ppb_file_io_proxy.cc
@@ -64,9 +64,9 @@ class FileIO : public PPB_FileIO_Shared {
scoped_refptr<TrackedCallback> callback) OVERRIDE;
virtual int32_t ReadValidated(
int64_t offset,
- char* buffer,
- int32_t bytes_to_read,
- scoped_refptr<TrackedCallback> callback) OVERRIDE;
+ const PP_ArrayOutput& output_array_buffer,
+ int32_t max_read_length,
+ scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
virtual int32_t WriteValidated(
int64_t offset,
const char* buffer,
@@ -154,12 +154,12 @@ int32_t FileIO::TouchValidated(PP_Time last_access_time,
}
int32_t FileIO::ReadValidated(int64_t offset,
- char* buffer,
- int32_t bytes_to_read,
+ const PP_ArrayOutput& output_array_buffer,
+ int32_t max_read_length,
scoped_refptr<TrackedCallback> callback) {
GetDispatcher()->Send(new PpapiHostMsg_PPBFileIO_Read(
- kApiID, host_resource(), offset, bytes_to_read));
- RegisterCallback(OPERATION_READ, callback, buffer, NULL);
+ kApiID, host_resource(), offset, max_read_length));
+ RegisterCallback(OPERATION_READ, callback, &output_array_buffer, NULL);
return PP_OK_COMPLETIONPENDING;
}
diff --git a/ppapi/shared_impl/array_writer.h b/ppapi/shared_impl/array_writer.h
index cabd0af..b761a07 100644
--- a/ppapi/shared_impl/array_writer.h
+++ b/ppapi/shared_impl/array_writer.h
@@ -38,7 +38,8 @@ class PPAPI_SHARED_EXPORT ArrayWriter {
// Sets the array output back to its is_null() state.
void Reset();
- // Copies the given vector of data to the plugin output array.
+ // StoreArray() and StoreVector() copy the given array/vector of data to the
+ // plugin output array.
//
// Returns true on success, false if the plugin reported allocation failure.
// In either case, the object will become is_null() immediately after the
@@ -48,27 +49,35 @@ class PPAPI_SHARED_EXPORT ArrayWriter {
// want to transfer a reference only on success. Likewise, if you have a
// structure of PP_Vars or a struct that contains a PP_Resource, we need to
// make sure that the right thing happens with the ref on success and failure.
- template<typename T>
- bool StoreVector(const std::vector<T>& input) {
+ template <typename T>
+ bool StoreArray(const T* input, uint32_t count) {
// Always call the alloc function, even on 0 array size.
void* dest = pp_array_output_.GetDataBuffer(
pp_array_output_.user_data,
- static_cast<uint32_t>(input.size()),
+ count,
sizeof(T));
// Regardless of success, we clear the output to prevent future calls on
// this same output object.
Reset();
- if (input.empty())
+ if (count == 0)
return true; // Allow plugin to return NULL on 0 elements.
if (!dest)
return false;
- memcpy(dest, &input[0], sizeof(T) * input.size());
+ if (input)
+ memcpy(dest, input, sizeof(T) * count);
return true;
}
+ // Copies the given array/vector of data to the plugin output array. See
+ // comment of StoreArray() for detail.
+ template<typename T>
+ bool StoreVector(const std::vector<T>& input) {
+ return StoreArray(input.size() ? &input[0] : NULL, input.size());
+ }
+
// Stores the given vector of resources as PP_Resources to the output vector,
// adding one reference to each.
//
diff --git a/ppapi/shared_impl/ppb_file_io_shared.cc b/ppapi/shared_impl/ppb_file_io_shared.cc
index b60e174..42a8d32 100644
--- a/ppapi/shared_impl/ppb_file_io_shared.cc
+++ b/ppapi/shared_impl/ppb_file_io_shared.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/message_loop.h"
#include "ppapi/c/pp_errors.h"
+#include "ppapi/shared_impl/array_writer.h"
#include "ppapi/shared_impl/file_type_conversion.h"
#include "ppapi/shared_impl/time_conversion.h"
#include "ppapi/thunk/enter.h"
@@ -21,9 +22,17 @@ using thunk::EnterResourceNoLock;
using thunk::PPB_FileIO_API;
using thunk::PPB_FileRef_API;
+namespace {
+
+// An adapter to let Read() share the same implementation with ReadToArray().
+void* DummyGetDataBuffer(void* user_data, uint32_t count, uint32_t size) {
+ return user_data;
+}
+
+} // namespace
+
PPB_FileIO_Shared::CallbackEntry::CallbackEntry()
- : read_buffer(NULL),
- info(NULL) {
+ : info(NULL) {
}
PPB_FileIO_Shared::CallbackEntry::CallbackEntry(const CallbackEntry& entry)
@@ -103,7 +112,21 @@ int32_t PPB_FileIO_Shared::Read(int64_t offset,
int32_t rv = CommonCallValidation(true, OPERATION_READ);
if (rv != PP_OK)
return rv;
- return ReadValidated(offset, buffer, bytes_to_read, callback);
+ PP_ArrayOutput buffer_adapter = { &DummyGetDataBuffer, buffer };
+ return ReadValidated(offset, buffer_adapter, bytes_to_read, callback);
+}
+
+int32_t PPB_FileIO_Shared::ReadToArray(
+ int64_t offset,
+ int32_t max_read_length,
+ PP_ArrayOutput* output_array_buffer,
+ scoped_refptr<TrackedCallback> callback) {
+ int32_t rv = CommonCallValidation(true, OPERATION_READ);
+ if (rv != PP_OK)
+ return rv;
+ if (!output_array_buffer)
+ return PP_ERROR_BADARGUMENT;
+ return ReadValidated(offset, *output_array_buffer, max_read_length, callback);
}
int32_t PPB_FileIO_Shared::Write(int64_t offset,
@@ -152,7 +175,7 @@ void PPB_FileIO_Shared::ExecuteQueryCallback(int32_t pp_error,
RunAndRemoveFirstPendingCallback(pp_error);
}
-void PPB_FileIO_Shared::ExecuteReadCallback(int32_t pp_error,
+void PPB_FileIO_Shared::ExecuteReadCallback(int32_t pp_error_or_bytes,
const char* data) {
if (pending_op_ != OPERATION_READ || callbacks_.empty()) {
NOTREACHED();
@@ -160,13 +183,14 @@ void PPB_FileIO_Shared::ExecuteReadCallback(int32_t pp_error,
}
// The result code contains the number of bytes if it's positive.
- if (pp_error > 0) {
- char* read_buffer = callbacks_.front().read_buffer;
- DCHECK(data);
- DCHECK(read_buffer);
- memcpy(read_buffer, data, pp_error);
+ ArrayWriter output;
+ output.set_pp_array_output(callbacks_.front().read_buffer);
+ if (output.is_valid()) {
+ output.StoreArray(data, std::max(0, pp_error_or_bytes));
}
- RunAndRemoveFirstPendingCallback(pp_error);
+
+ // Always issue the callback.
+ RunAndRemoveFirstPendingCallback(pp_error_or_bytes);
}
int32_t PPB_FileIO_Shared::CommonCallValidation(bool should_be_open,
@@ -191,14 +215,15 @@ int32_t PPB_FileIO_Shared::CommonCallValidation(bool should_be_open,
void PPB_FileIO_Shared::RegisterCallback(
OperationType op,
scoped_refptr<TrackedCallback> callback,
- char* read_buffer,
+ const PP_ArrayOutput* read_buffer,
PP_FileInfo* info) {
DCHECK(pending_op_ == OPERATION_NONE ||
(pending_op_ != OPERATION_EXCLUSIVE && pending_op_ == op));
CallbackEntry entry;
entry.callback = callback;
- entry.read_buffer = read_buffer;
+ if (read_buffer)
+ entry.read_buffer = *read_buffer;
entry.info = info;
callbacks_.push_back(entry);
diff --git a/ppapi/shared_impl/ppb_file_io_shared.h b/ppapi/shared_impl/ppb_file_io_shared.h
index a062497..2c39c8d 100644
--- a/ppapi/shared_impl/ppb_file_io_shared.h
+++ b/ppapi/shared_impl/ppb_file_io_shared.h
@@ -42,6 +42,10 @@ class PPAPI_SHARED_EXPORT PPB_FileIO_Shared : public Resource,
char* buffer,
int32_t bytes_to_read,
scoped_refptr<TrackedCallback> callback) OVERRIDE;
+ virtual int32_t ReadToArray(int64_t offset,
+ int32_t max_read_length,
+ PP_ArrayOutput* output_array_buffer,
+ scoped_refptr<TrackedCallback> callback) OVERRIDE;
virtual int32_t Write(int64_t offset,
const char* buffer,
int32_t bytes_to_write,
@@ -54,7 +58,7 @@ class PPAPI_SHARED_EXPORT PPB_FileIO_Shared : public Resource,
void ExecuteGeneralCallback(int32_t pp_error);
void ExecuteOpenFileCallback(int32_t pp_error);
void ExecuteQueryCallback(int32_t pp_error, const PP_FileInfo& info);
- void ExecuteReadCallback(int32_t pp_error, const char* data);
+ void ExecuteReadCallback(int32_t pp_error_or_bytes, const char* data);
protected:
struct CallbackEntry {
@@ -64,9 +68,8 @@ class PPAPI_SHARED_EXPORT PPB_FileIO_Shared : public Resource,
scoped_refptr<TrackedCallback> callback;
- // Pointer back to the caller's read buffer; only used by |Read()|, NULL
- // for non-read operations. Not owned.
- char* read_buffer;
+ // Output buffer used only by |Read()|.
+ PP_ArrayOutput read_buffer;
// Pointer back to the caller's PP_FileInfo structure for Query operations.
// NULL for non-query operations. Not owned.
@@ -102,8 +105,8 @@ class PPAPI_SHARED_EXPORT PPB_FileIO_Shared : public Resource,
PP_Time last_modified_time,
scoped_refptr<TrackedCallback> callback) = 0;
virtual int32_t ReadValidated(int64_t offset,
- char* buffer,
- int32_t bytes_to_read,
+ const PP_ArrayOutput& buffer,
+ int32_t max_read_length,
scoped_refptr<TrackedCallback> callback) = 0;
virtual int32_t WriteValidated(int64_t offset,
const char* buffer,
@@ -131,7 +134,7 @@ class PPAPI_SHARED_EXPORT PPB_FileIO_Shared : public Resource,
// query operations.
void RegisterCallback(OperationType op,
scoped_refptr<TrackedCallback> callback,
- char* read_buffer,
+ const PP_ArrayOutput* read_buffer,
PP_FileInfo* info);
// Pops the oldest callback from the queue and runs it.
diff --git a/ppapi/tests/test_file_io.cc b/ppapi/tests/test_file_io.cc
index c61b31d..9f88f00 100644
--- a/ppapi/tests/test_file_io.cc
+++ b/ppapi/tests/test_file_io.cc
@@ -82,6 +82,29 @@ int32_t ReadEntireFile(PP_Instance instance,
return PP_OK;
}
+int32_t ReadToArrayEntireFile(PP_Instance instance,
+ pp::FileIO* file_io,
+ int32_t offset,
+ std::string* data,
+ bool force_async) {
+ TestCompletionCallbackWithOutput< std::vector<char> > callback(
+ instance, force_async);
+
+ for (;;) {
+ callback.WaitForResult(file_io->Read(offset, 256, callback));
+ int32_t rv = callback.result();
+ if (rv < 0)
+ return rv;
+ if (rv == 0)
+ break;
+ assert(rv == static_cast<int32_t>(callback.output().size()));
+ offset += rv;
+ data->append(callback.output().begin(), callback.output().end());
+ }
+
+ return PP_OK;
+}
+
int32_t WriteEntireBuffer(PP_Instance instance,
pp::FileIO* file_io,
int32_t offset,
@@ -115,6 +138,7 @@ bool TestFileIO::Init() {
void TestFileIO::RunTests(const std::string& filter) {
RUN_TEST_FORCEASYNC_AND_NOT(Open, filter);
RUN_TEST_FORCEASYNC_AND_NOT(ReadWriteSetLength, filter);
+ RUN_TEST_FORCEASYNC_AND_NOT(ReadToArrayWriteSetLength, filter);
RUN_TEST_FORCEASYNC_AND_NOT(TouchQuery, filter);
RUN_TEST_FORCEASYNC_AND_NOT(AbortCalls, filter);
RUN_TEST_FORCEASYNC_AND_NOT(ParallelReads, filter);
@@ -357,6 +381,150 @@ std::string TestFileIO::TestReadWriteSetLength() {
PASS();
}
+// This is basically a copy of TestReadWriteSetLength, but with the new Read
+// API. With this test case, we can make sure the two Read's have the same
+// behavior.
+std::string TestFileIO::TestReadToArrayWriteSetLength() {
+ TestCompletionCallback callback(instance_->pp_instance(), force_async_);
+
+ pp::FileSystem file_system(instance_, PP_FILESYSTEMTYPE_LOCALTEMPORARY);
+ pp::FileRef file_ref(file_system, "/file_read_write_setlength");
+ int32_t rv = file_system.Open(1024, callback);
+ if (force_async_ && rv != PP_OK_COMPLETIONPENDING)
+ return ReportError("FileSystem::Open force_async", rv);
+ if (rv == PP_OK_COMPLETIONPENDING)
+ rv = callback.WaitForResult();
+ if (rv != PP_OK)
+ return ReportError("FileSystem::Open", rv);
+
+ pp::FileIO file_io(instance_);
+ rv = file_io.Open(file_ref,
+ PP_FILEOPENFLAG_CREATE |
+ PP_FILEOPENFLAG_TRUNCATE |
+ PP_FILEOPENFLAG_READ |
+ PP_FILEOPENFLAG_WRITE,
+ callback);
+ if (force_async_ && rv != PP_OK_COMPLETIONPENDING)
+ return ReportError("FileIO::Open force_async", rv);
+ if (rv == PP_OK_COMPLETIONPENDING)
+ rv = callback.WaitForResult();
+ if (rv != PP_OK)
+ return ReportError("FileIO::Open", rv);
+
+ // Write something to the file.
+ rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 0, "test_test");
+ if (rv != PP_OK)
+ return ReportError("FileIO::Write", rv);
+
+ TestCompletionCallbackWithOutput< std::vector<char> > callback2(
+ instance_->pp_instance(), force_async_);
+ // Check for failing read operation.
+ callback2.WaitForResult(
+ file_io.Read(0, -1, // negative number of bytes to read
+ callback2));
+ CHECK_CALLBACK_BEHAVIOR(callback2);
+ if (callback2.result() != PP_ERROR_FAILED)
+ return ReportError("FileIO::Read", callback2.result());
+
+ // Read the entire file.
+ std::string read_buffer;
+ read_buffer.reserve(10);
+ rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
+ &read_buffer, force_async_);
+ if (rv != PP_OK)
+ return ReportError("FileIO::Read", rv);
+ if (read_buffer != "test_test")
+ return ReportMismatch("FileIO::Read", read_buffer, "test_test");
+
+ // Truncate the file.
+ rv = file_io.SetLength(4, callback);
+ if (force_async_ && rv != PP_OK_COMPLETIONPENDING)
+ return ReportError("FileIO::SetLength force_async", rv);
+ if (rv == PP_OK_COMPLETIONPENDING)
+ rv = callback.WaitForResult();
+ if (rv != PP_OK)
+ return ReportError("FileIO::SetLength", rv);
+
+ // Check the file contents.
+ read_buffer.clear();
+ rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
+ &read_buffer, force_async_);
+ if (rv != PP_OK)
+ return ReportError("FileIO::Read", rv);
+ if (read_buffer != "test")
+ return ReportMismatch("FileIO::Read", read_buffer, "test");
+
+ // Try to read past the end of the file.
+ read_buffer.clear();
+ rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 100,
+ &read_buffer, force_async_);
+ if (rv != PP_OK)
+ return ReportError("FileIO::Read", rv);
+ if (!read_buffer.empty())
+ return ReportMismatch("FileIO::Read", read_buffer, "<empty string>");
+
+ // Write past the end of the file. The file should be zero-padded.
+ rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 8, "test");
+ if (rv != PP_OK)
+ return ReportError("FileIO::Write", rv);
+
+ // Check the contents of the file.
+ read_buffer.clear();
+ rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
+ &read_buffer, force_async_);
+ if (rv != PP_OK)
+ return ReportError("FileIO::Read", rv);
+ if (read_buffer != std::string("test\0\0\0\0test", 12))
+ return ReportMismatch("FileIO::Read", read_buffer,
+ std::string("test\0\0\0\0test", 12));
+
+ // Extend the file.
+ rv = file_io.SetLength(16, callback);
+ if (force_async_ && rv != PP_OK_COMPLETIONPENDING)
+ return ReportError("FileIO::SetLength force_async", rv);
+ if (rv == PP_OK_COMPLETIONPENDING)
+ rv = callback.WaitForResult();
+ if (rv != PP_OK)
+ return ReportError("FileIO::SetLength", rv);
+
+ // Check the contents of the file.
+ read_buffer.clear();
+ rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
+ &read_buffer, force_async_);
+ if (rv != PP_OK)
+ return ReportError("FileIO::Read", rv);
+ if (read_buffer != std::string("test\0\0\0\0test\0\0\0\0", 16))
+ return ReportMismatch("FileIO::Read", read_buffer,
+ std::string("test\0\0\0\0test\0\0\0\0", 16));
+
+ // Write in the middle of the file.
+ rv = WriteEntireBuffer(instance_->pp_instance(), &file_io, 4, "test");
+ if (rv != PP_OK)
+ return ReportError("FileIO::Write", rv);
+
+ // Check the contents of the file.
+ read_buffer.clear();
+ rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 0,
+ &read_buffer, force_async_);
+ if (rv != PP_OK)
+ return ReportError("FileIO::Read", rv);
+ if (read_buffer != std::string("testtesttest\0\0\0\0", 16))
+ return ReportMismatch("FileIO::Read", read_buffer,
+ std::string("testtesttest\0\0\0\0", 16));
+
+ // Read from the middle of the file.
+ read_buffer.clear();
+ rv = ReadToArrayEntireFile(instance_->pp_instance(), &file_io, 4,
+ &read_buffer, force_async_);
+ if (rv != PP_OK)
+ return ReportError("FileIO::Read", rv);
+ if (read_buffer != std::string("testtest\0\0\0\0", 12))
+ return ReportMismatch("FileIO::Read", read_buffer,
+ std::string("testtest\0\0\0\0", 12));
+
+ PASS();
+}
+
std::string TestFileIO::TestTouchQuery() {
TestCompletionCallback callback(instance_->pp_instance(), force_async_);
diff --git a/ppapi/tests/test_file_io.h b/ppapi/tests/test_file_io.h
index b971105..bf1c798 100644
--- a/ppapi/tests/test_file_io.h
+++ b/ppapi/tests/test_file_io.h
@@ -10,6 +10,7 @@
#include "ppapi/tests/test_case.h"
namespace pp {
+class FileIO;
class FileSystem;
} // namespace pp
@@ -38,6 +39,7 @@ class TestFileIO : public TestCase {
std::string TestOpen();
std::string TestReadWriteSetLength();
+ std::string TestReadToArrayWriteSetLength();
std::string TestTouchQuery();
std::string TestAbortCalls();
std::string TestParallelReads();
diff --git a/ppapi/tests/test_utils.h b/ppapi/tests/test_utils.h
index 8ef2f4e..09e0b94 100644
--- a/ppapi/tests/test_utils.h
+++ b/ppapi/tests/test_utils.h
@@ -151,7 +151,7 @@ class TestCompletionCallback {
// Reset so that this callback can be used again.
void Reset();
- private:
+ protected:
static void Handler(void* user_data, int32_t result);
void RunMessageLoop();
void QuitMessageLoop();
@@ -172,6 +172,56 @@ class TestCompletionCallback {
pp::MessageLoop target_loop_;
};
+template <typename OutputT>
+class TestCompletionCallbackWithOutput : public TestCompletionCallback {
+ public:
+ explicit TestCompletionCallbackWithOutput(PP_Instance instance) :
+ TestCompletionCallback(instance) {
+ }
+
+ TestCompletionCallbackWithOutput(PP_Instance instance, bool force_async) :
+ TestCompletionCallback(instance, force_async) {
+ }
+
+ TestCompletionCallbackWithOutput(PP_Instance instance,
+ CallbackType callback_type) :
+ TestCompletionCallback(instance, callback_type) {
+ }
+
+ pp::CompletionCallbackWithOutput<OutputT> GetCallbackWithOutput();
+ operator pp::CompletionCallbackWithOutput<OutputT>() {
+ return GetCallbackWithOutput();
+ }
+
+ const OutputT& output() { return output_storage_.output(); }
+
+ typename pp::CompletionCallbackWithOutput<OutputT>::OutputStorageType
+ output_storage_;
+};
+
+template <typename OutputT>
+pp::CompletionCallbackWithOutput<OutputT>
+TestCompletionCallbackWithOutput<OutputT>::GetCallbackWithOutput() {
+ Reset();
+ if (callback_type_ == PP_BLOCKING) {
+ pp::CompletionCallbackWithOutput<OutputT> cc(
+ &TestCompletionCallback::Handler,
+ this,
+ &output_storage_);
+ return cc;
+ }
+
+ target_loop_ = pp::MessageLoop::GetCurrent();
+ pp::CompletionCallbackWithOutput<OutputT> cc(
+ &TestCompletionCallback::Handler,
+ this,
+ &output_storage_);
+ if (callback_type_ == PP_OPTIONAL)
+ cc.set_flags(PP_COMPLETIONCALLBACK_FLAG_OPTIONAL);
+ return cc;
+}
+
+
// Verifies that the callback didn't record any errors. If the callback is run
// in an unexpected way (e.g., if it's invoked asynchronously when the call
// should have blocked), this returns an appropriate error string.
diff --git a/ppapi/thunk/interfaces_ppb_public_stable.h b/ppapi/thunk/interfaces_ppb_public_stable.h
index 19b299c..d3a74a6 100644
--- a/ppapi/thunk/interfaces_ppb_public_stable.h
+++ b/ppapi/thunk/interfaces_ppb_public_stable.h
@@ -51,6 +51,7 @@ UNPROXIED_API(PPB_AudioConfig)
// Note: Core is special and is registered manually.
PROXIED_IFACE(PPB_Audio, PPB_AUDIO_INTERFACE_1_0, PPB_Audio_1_0)
PROXIED_IFACE(PPB_FileIO, PPB_FILEIO_INTERFACE_1_0, PPB_FileIO_1_0)
+PROXIED_IFACE(PPB_FileIO, PPB_FILEIO_INTERFACE_1_1, PPB_FileIO_1_1)
PROXIED_IFACE(PPB_FileRef, PPB_FILEREF_INTERFACE_1_0, PPB_FileRef_1_0)
PROXIED_IFACE(PPB_FileSystem, PPB_FILESYSTEM_INTERFACE_1_0, PPB_FileSystem_1_0)
PROXIED_IFACE(PPB_Graphics2D, PPB_GRAPHICS_2D_INTERFACE_1_0, PPB_Graphics2D_1_0)
diff --git a/ppapi/thunk/ppb_file_io_api.h b/ppapi/thunk/ppb_file_io_api.h
index 1e6e3ad..b7b3d90 100644
--- a/ppapi/thunk/ppb_file_io_api.h
+++ b/ppapi/thunk/ppb_file_io_api.h
@@ -31,6 +31,10 @@ class PPAPI_THUNK_EXPORT PPB_FileIO_API {
char* buffer,
int32_t bytes_to_read,
scoped_refptr<TrackedCallback> callback) = 0;
+ virtual int32_t ReadToArray(int64_t offset,
+ int32_t max_read_length,
+ PP_ArrayOutput* buffer,
+ scoped_refptr<TrackedCallback> callback) = 0;
virtual int32_t Write(int64_t offset,
const char* buffer,
int32_t bytes_to_write,
diff --git a/ppapi/thunk/ppb_file_io_thunk.cc b/ppapi/thunk/ppb_file_io_thunk.cc
index 8fcfa52..467958f 100644
--- a/ppapi/thunk/ppb_file_io_thunk.cc
+++ b/ppapi/thunk/ppb_file_io_thunk.cc
@@ -72,6 +72,18 @@ int32_t Read(PP_Resource file_io,
enter.callback()));
}
+int32_t ReadToArray(PP_Resource file_io,
+ int64_t offset,
+ int32_t max_read_length,
+ PP_ArrayOutput* buffer,
+ PP_CompletionCallback callback) {
+ EnterFileIO enter(file_io, callback, true);
+ if (enter.failed())
+ return enter.retval();
+ return enter.SetResult(enter.object()->ReadToArray(
+ offset, max_read_length, buffer, enter.callback()));
+}
+
int32_t Write(PP_Resource file_io,
int64_t offset,
const char* buffer,
@@ -107,7 +119,21 @@ void Close(PP_Resource file_io) {
enter.object()->Close();
}
-const PPB_FileIO g_ppb_file_io_thunk = {
+const PPB_FileIO_1_1 g_ppb_file_io_thunk = {
+ &Create,
+ &IsFileIO,
+ &Open,
+ &Query,
+ &Touch,
+ &Read,
+ &Write,
+ &SetLength,
+ &Flush,
+ &Close,
+ &ReadToArray
+};
+
+const PPB_FileIO_1_0 g_ppb_file_io_thunk_1_0 = {
&Create,
&IsFileIO,
&Open,
@@ -122,9 +148,13 @@ const PPB_FileIO g_ppb_file_io_thunk = {
} // namespace
-const PPB_FileIO_1_0* GetPPB_FileIO_1_0_Thunk() {
+const PPB_FileIO_1_1* GetPPB_FileIO_1_1_Thunk() {
return &g_ppb_file_io_thunk;
}
+const PPB_FileIO_1_0* GetPPB_FileIO_1_0_Thunk() {
+ return &g_ppb_file_io_thunk_1_0;
+}
+
} // namespace thunk
} // namespace ppapi
diff --git a/webkit/plugins/ppapi/ppb_file_io_impl.cc b/webkit/plugins/ppapi/ppb_file_io_impl.cc
index 8c59b7e..75e62a5 100644
--- a/webkit/plugins/ppapi/ppb_file_io_impl.cc
+++ b/webkit/plugins/ppapi/ppb_file_io_impl.cc
@@ -190,8 +190,8 @@ int32_t PPB_FileIO_Impl::TouchValidated(
int32_t PPB_FileIO_Impl::ReadValidated(
int64_t offset,
- char* buffer,
- int32_t bytes_to_read,
+ const PP_ArrayOutput& output_array_buffer,
+ int32_t max_read_length,
scoped_refptr<TrackedCallback> callback) {
PluginDelegate* plugin_delegate = GetPluginDelegate();
if (!plugin_delegate)
@@ -199,12 +199,12 @@ int32_t PPB_FileIO_Impl::ReadValidated(
if (!base::FileUtilProxy::Read(
plugin_delegate->GetFileThreadMessageLoopProxy(), file_, offset,
- bytes_to_read,
+ max_read_length,
base::Bind(&PPB_FileIO_Impl::ExecutePlatformReadCallback,
weak_factory_.GetWeakPtr())))
return PP_ERROR_FAILED;
- RegisterCallback(OPERATION_READ, callback, buffer, NULL);
+ RegisterCallback(OPERATION_READ, callback, &output_array_buffer, NULL);
return PP_OK_COMPLETIONPENDING;
}
diff --git a/webkit/plugins/ppapi/ppb_file_io_impl.h b/webkit/plugins/ppapi/ppb_file_io_impl.h
index 52d1105..a6f9e89 100644
--- a/webkit/plugins/ppapi/ppb_file_io_impl.h
+++ b/webkit/plugins/ppapi/ppb_file_io_impl.h
@@ -51,8 +51,8 @@ class PPB_FileIO_Impl : public ::ppapi::PPB_FileIO_Shared {
scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
virtual int32_t ReadValidated(
int64_t offset,
- char* buffer,
- int32_t bytes_to_read,
+ const PP_ArrayOutput& output_array_buffer,
+ int32_t max_read_length,
scoped_refptr< ::ppapi::TrackedCallback> callback) OVERRIDE;
virtual int32_t WriteValidated(
int64_t offset,