diff options
author | gman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-17 22:25:08 +0000 |
---|---|---|
committer | gman@google.com <gman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-17 22:25:08 +0000 |
commit | 523b2523c1f2cb22f56be9cc52fb734370992387 (patch) | |
tree | ede3f93c4e118e840778e39b5633d6bfc7058ab3 /o3d | |
parent | 9521c61f5588480d8cd6134144db7137630f2529 (diff) | |
download | chromium_src-523b2523c1f2cb22f56be9cc52fb734370992387.zip chromium_src-523b2523c1f2cb22f56be9cc52fb734370992387.tar.gz chromium_src-523b2523c1f2cb22f56be9cc52fb734370992387.tar.bz2 |
Add RawData request in preparation for manual loading of
Bitmaps and being able to flip them, scale them, etc...
Basically this just makes it possible to download a RawData
directly which you can then pass you'll be able to pass to
pack->CreateBitmapFromRawData.
Some design comments:
I used SetFromFile instead of making a different constructor
since it seemed wrong to do file IO in a constructor. Given
that SetFromFile is private I don't think this is a problem
since you can't call it directly.
Also, I thought about loading the file first and then calling
the original constructor but it seemed like a waste to load
the file into memory, then copy it to a new buffer when I could
just load it directly.
Finally I made it take a String instead of a FilePath because
it meant other places had to do less work.
Review URL: http://codereview.chromium.org/149784
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@21015 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r-- | o3d/core/cross/bitmap.cc | 53 | ||||
-rw-r--r-- | o3d/core/cross/file_request.h | 15 | ||||
-rw-r--r-- | o3d/import/cross/raw_data.cc | 81 | ||||
-rw-r--r-- | o3d/import/cross/raw_data.h | 9 | ||||
-rw-r--r-- | o3d/import/cross/raw_data_test.cc | 74 | ||||
-rw-r--r-- | o3d/plugin/cross/async_loading.cc | 68 | ||||
-rw-r--r-- | o3d/plugin/cross/async_loading.h | 6 | ||||
-rw-r--r-- | o3d/plugin/idl/file_request.idl | 7 | ||||
-rw-r--r-- | o3d/plugin/idl/pack.idl | 7 |
9 files changed, 281 insertions, 39 deletions
diff --git a/o3d/core/cross/bitmap.cc b/o3d/core/cross/bitmap.cc index 61ac355..320d3e1 100644 --- a/o3d/core/cross/bitmap.cc +++ b/o3d/core/cross/bitmap.cc @@ -219,40 +219,39 @@ bool Bitmap::LoadFromStream(MemoryReadStream *stream, bool Bitmap::LoadFromFile(const FilePath &filepath, ImageFileType file_type, bool generate_mipmaps) { - // Open the file + // Open the file. + bool result = false; String filename = FilePathToUTF8(filepath); FILE *file = OpenFile(filepath, "rb"); if (!file) { DLOG(ERROR) << "bitmap file not found \"" << filename << "\""; - return false; - } - - // Determine the file's length - int64 file_size64; - if (!GetFileSize(filepath, &file_size64)) { - DLOG(ERROR) << "error getting bitmap file size \"" << filename << "\""; + } else { + // Determine the file's length + int64 file_size64; + if (!GetFileSize(filepath, &file_size64)) { + DLOG(ERROR) << "error getting bitmap file size \"" << filename << "\""; + } else { + if (file_size64 > 0xffffffffLL) { + DLOG(ERROR) << "bitmap file is too large \"" << filename << "\""; + } else { + size_t file_length = static_cast<size_t>(file_size64); + + // Load the compressed image data into memory + MemoryBuffer<uint8> file_contents(file_length); + uint8 *p = file_contents; + if (fread(p, file_length, 1, file) != 1) { + DLOG(ERROR) << "error reading bitmap file \"" << filename << "\""; + } else { + // And create the bitmap from a memory stream + MemoryReadStream stream(file_contents, file_length); + result = LoadFromStream(&stream, filename, file_type, + generate_mipmaps); + } + } + } CloseFile(file); - return false; - } - if (file_size64 > 0xffffffffLL) { - DLOG(ERROR) << "bitmap file is too large \"" << filename << "\""; - return false; } - size_t file_length = static_cast<size_t>(file_size64); - - // Load the compressed image data into memory - MemoryBuffer<uint8> file_contents(file_length); - uint8 *p = file_contents; - if (fread(p, file_length, 1, file) != 1) { - DLOG(ERROR) << "error reading bitmap file \"" << filename << "\""; - return false; - } - - // And create the bitmap from a memory stream - MemoryReadStream stream(file_contents, file_length); - bool result = LoadFromStream(&stream, filename, file_type, generate_mipmaps); - CloseFile(file); return result; } diff --git a/o3d/core/cross/file_request.h b/o3d/core/cross/file_request.h index 1311ed1..11e695d9 100644 --- a/o3d/core/cross/file_request.h +++ b/o3d/core/cross/file_request.h @@ -42,6 +42,7 @@ #include "core/cross/callback.h" #include "core/cross/object_base.h" #include "core/cross/pack.h" +#include "import/cross/raw_data.h" namespace o3d { @@ -54,7 +55,8 @@ class FileRequest : public ObjectBase { enum Type { TYPE_INVALID, TYPE_TEXTURE, - TYPE_MAX = TYPE_TEXTURE, + TYPE_RAWDATA, + TYPE_MAX = TYPE_RAWDATA, }; enum ReadyState { // These are copied from XMLHttpRequest. @@ -82,6 +84,9 @@ class FileRequest : public ObjectBase { if (type == "texture") { return TYPE_TEXTURE; } + if (type == "rawdata") { + return TYPE_RAWDATA; + } return TYPE_INVALID; } @@ -109,6 +114,9 @@ class FileRequest : public ObjectBase { Texture *texture() const { return texture_.Get(); } + RawData *data() const { + return data_.Get(); + } bool generate_mipmaps() const { return generate_mipmaps_; } void set_generate_mipmaps(bool value) { generate_mipmaps_ = value; @@ -117,6 +125,10 @@ class FileRequest : public ObjectBase { CHECK(type_ == TYPE_TEXTURE); texture_ = Texture::Ref(texture); } + void set_data(RawData *data) { + CHECK(type_ == TYPE_RAWDATA); + data_ = RawData::Ref(data); + } bool done() const { return done_; } @@ -153,6 +165,7 @@ class FileRequest : public ObjectBase { String uri_; Type type_; Texture::Ref texture_; // Only used on a successful texture load. + RawData::Ref data_; // Only used on a successful RawData load. bool generate_mipmaps_; bool done_; // Set after completion/failure to indicate success_ is valid. bool success_; // Set after completion/failure to indicate which it is. diff --git a/o3d/import/cross/raw_data.cc b/o3d/import/cross/raw_data.cc index 53039c2..deabe37 100644 --- a/o3d/import/cross/raw_data.cc +++ b/o3d/import/cross/raw_data.cc @@ -35,6 +35,9 @@ #include "import/cross/raw_data.h" #include "base/file_util.h" +#include "utils/cross/file_path_utils.h" +#include "base/file_path.h" +#include "base/file_util.h" #ifdef OS_MACOSX #include <CoreFoundation/CoreFoundation.h> @@ -44,6 +47,10 @@ #include <rpc.h> #endif +using file_util::OpenFile; +using file_util::CloseFile; +using file_util::GetFileSize; + namespace o3d { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -59,7 +66,7 @@ RawData::RawData(ServiceLocator* service_locator, const String &uri, const void *data, size_t length) - : ParamObject(service_locator), uri_(uri) { + : ParamObject(service_locator), uri_(uri), allow_string_value_(true) { // make private copy of data data_.reset(new uint8[length]); length_ = length; @@ -74,6 +81,17 @@ RawData::Ref RawData::Create(ServiceLocator* service_locator, return RawData::Ref(new RawData(service_locator, uri, data, length)); } +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +RawData::Ref RawData::CreateFromFile(ServiceLocator* service_locator, + const String &uri, + const String& filename) { + RawData::Ref data(Create(service_locator, uri, NULL, 0)); + if (!data->SetFromFile(filename)) { + data.Reset(); + } + + return data; +} // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RawData::~RawData() { @@ -81,6 +99,46 @@ RawData::~RawData() { } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +bool RawData::SetFromFile(const String& filename) { + // We can't allow general string files to be downloaded from anywhere + // as that would override the security measures that have been added to + // XMLHttpRequest over the years. Images and other binary datas are okay. + // because RawData can only be passed to stuff that understands specific + // formats. + allow_string_value_ = false; + FilePath filepath = UTF8ToFilePath(filename); + FILE *file = OpenFile(filepath, "rb"); + bool result = false; + if (!file) { + DLOG(ERROR) << "file not found \"" << filename << "\""; + } else { + // Determine the file's length + int64 file_size64; + if (!GetFileSize(filepath, &file_size64)) { + DLOG(ERROR) << "error getting file size \"" << filename << "\""; + } else { + if (file_size64 > 0xffffffffLL) { + DLOG(ERROR) << "file is too large \"" << filename << "\""; + } else { + size_t file_length = static_cast<size_t>(file_size64); + + // Load the file data into memory + data_.reset(new uint8[file_length]); + length_ = file_length; + if (fread(data_.get(), file_length, 1, file) != 1) { + DLOG(ERROR) << "error reading file \"" << filename << "\""; + } else { + result = true; + } + } + } + CloseFile(file); + } + + return result; +} + +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ const uint8 *RawData::GetData() const { // Return data immediately if we have it if (data_.get()) { @@ -195,12 +253,23 @@ String RawData::StringValue() const { // .json, .xml, .ini, .csv, .php, .js, .html, .css .xsl, .dae, etc.) So, // instead we validate the string is valid UTF-8 AND that there are no NULLs // in the string. - size_t length; - const char* utf8 = GetValidUTF8(*this, &length); - if (!utf8) { - O3D_ERROR(service_locator()) << "RawData is not valid UTF-8 string"; + + // We can't allow general string files to be downloaded from anywhere + // as that would override the security measures that have been added to + // XMLHttpRequest over the years. Images and other binary datas are okay. + // because RawData can only be passed to stuff that understands specific + // formats. + if (!allow_string_value_) { + O3D_ERROR(service_locator()) + << "You can only get a stringValue from RawDatas inside archives."; } else { - return String (utf8, length); + size_t length; + const char* utf8 = GetValidUTF8(*this, &length); + if (!utf8) { + O3D_ERROR(service_locator()) << "RawData is not valid UTF-8 string"; + } else { + return String (utf8, length); + } } return String(); } diff --git a/o3d/import/cross/raw_data.h b/o3d/import/cross/raw_data.h index 8012efd..1929b1a 100644 --- a/o3d/import/cross/raw_data.h +++ b/o3d/import/cross/raw_data.h @@ -46,6 +46,8 @@ #include "core/cross/param.h" #include "core/cross/types.h" +class FilePath; + namespace o3d { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -58,6 +60,10 @@ class RawData : public ParamObject { const void *data, size_t length); + static RawData::Ref CreateFromFile(ServiceLocator* service_locator, + const String &uri, + const String& filename); + virtual ~RawData(); const uint8 *GetData() const; @@ -94,6 +100,7 @@ class RawData : public ParamObject { mutable scoped_array<uint8> data_; size_t length_; FilePath temp_filepath_; + bool allow_string_value_; // Deletes temp file if it exists void DeleteTempFile(); @@ -103,6 +110,8 @@ class RawData : public ParamObject { const void *data, size_t length); + bool SetFromFile(const String& filename); + friend class IClassManager; friend class Pack; diff --git a/o3d/import/cross/raw_data_test.cc b/o3d/import/cross/raw_data_test.cc index b1ccc5dd..4ab0955 100644 --- a/o3d/import/cross/raw_data_test.cc +++ b/o3d/import/cross/raw_data_test.cc @@ -34,14 +34,42 @@ #include "core/cross/client.h" #include "tests/common/win/testing_common.h" +#include "utils/cross/file_path_utils.h" +#include "base/file_path.h" +#include "base/file_util.h" #include "core/cross/error.h" +#include "core/cross/error_status.h" #include "import/cross/memory_buffer.h" #include "import/cross/raw_data.h" +using file_util::OpenFile; +using file_util::CloseFile; +using file_util::GetFileSize; + namespace o3d { +namespace { + +// Checks if an error has occured on the client then clears the error. +bool CheckErrorExists(IErrorStatus* error_status) { + bool have_error = !error_status->GetLastError().empty(); + error_status->ClearLastError(); + return have_error; +} + +} // anonymous namespace + // Test fixture for RawData testing. class RawDataTest : public testing::Test { + protected: + RawDataTest() + : error_status_(g_service_locator) { + } + + IErrorStatus* error_status() { return &error_status_; } + + private: + ErrorStatus error_status_; }; // Test RawData @@ -75,6 +103,52 @@ TEST_F(RawDataTest, Basic) { ASSERT_EQ(raw_data->uri(), uri); } +TEST_F(RawDataTest, CreateFromFile) { + String uri("test_filename"); + String filename = *g_program_path + "/bitmap_test/tga-256x256-24bit.tga"; + RawData::Ref ref = RawData::CreateFromFile(g_service_locator, + uri, + filename); + ASSERT_FALSE(ref.IsNull()); + FilePath filepath = UTF8ToFilePath(filename); + FILE *file = OpenFile(filepath, "rb"); + ASSERT_TRUE(file != NULL); + int64 file_size64; + ASSERT_TRUE(GetFileSize(filepath, &file_size64)); + size_t file_length = static_cast<size_t>(file_size64); + ASSERT_TRUE(file_length > 0); + scoped_array<uint8> data(new uint8[file_length]); + ASSERT_EQ(fread(data.get(), file_length, 1, file), 1); + CloseFile(file); + + ASSERT_EQ(file_length, ref->GetLength()); + ASSERT_EQ(0, memcmp(ref->GetData(), data.get(), file_length)); +} + +TEST_F(RawDataTest, CreateFromFileFail) { + String uri("test_filename"); + String filename = *g_program_path + "/bitmap_test/non-existent-file.foo"; + RawData::Ref ref = RawData::CreateFromFile(g_service_locator, + uri, + filename); + ASSERT_TRUE(ref.IsNull()); +} + +TEST_F(RawDataTest, CreateFromFileStringValue) { + String uri("test_filename"); + String filename = *g_program_path + "/unittest_data/fur.fx"; + RawData::Ref ref = RawData::CreateFromFile(g_service_locator, + uri, + filename); + ASSERT_FALSE(ref.IsNull()); + EXPECT_TRUE(ref->GetLength() > 0); + EXPECT_FALSE(CheckErrorExists(error_status())); + // We should NOT be able to get a string value from an individually + // loaded RawData. + EXPECT_TRUE(ref->StringValue().empty()); + EXPECT_TRUE(CheckErrorExists(error_status())); +} + namespace { struct TestData { diff --git a/o3d/plugin/cross/async_loading.cc b/o3d/plugin/cross/async_loading.cc index bcd8333..f38ef5d 100644 --- a/o3d/plugin/cross/async_loading.cc +++ b/o3d/plugin/cross/async_loading.cc @@ -41,6 +41,7 @@ #include "core/cross/file_request.h" #include "core/cross/pack.h" #include "core/cross/texture.h" +#include "import/cross/raw_data.h" namespace glue { namespace namespace_o3d { @@ -49,6 +50,7 @@ namespace class_FileRequest { using _o3d::PluginObject; using o3d::Bitmap; using o3d::Pack; +using o3d::RawData; using o3d::Texture; // StreamManager::FinishedCallback @@ -124,6 +126,69 @@ class LoadTextureURLCallback : public StreamManager::FinishedCallback { } }; +// StreamManager::FinishedCallback +// implementation that imports the file as a RawData once downloaded. When the +// download completes, LoadRawDataURLCallback::Run() will be called, which will +// parse and load the downloaded file. After that load is complete, +// onreadystatechange will be run to notify the user. +class LoadRawDataURLCallback : public StreamManager::FinishedCallback { + public: + // Creates a new LoadRawDataURLCallback. + static LoadRawDataURLCallback *Create(FileRequest *request) { + return new LoadRawDataURLCallback(request); + } + + virtual ~LoadRawDataURLCallback() { + // If the file request was interrupted (for example we moved to a new page + // before the file transfer was completed) then we tell the FileRequest + // object that the request failed. It's important to call this here since + // set_success() will release the pack reference that the FileRequest holds + // which will allow the pack to be garbage collected. + if (!request_->done()) { + request_->set_success(false); + } + } + + // Loads the RawData file, calls the JS callback to pass back the RawData + // object. + virtual void Run(DownloadStream*, + bool success, + const std::string &filename, + const std::string &mime_type) { + RawData::Ref data; + if (success) { + o3d::ErrorCollector error_collector(request_->service_locator()); + request_->set_ready_state(FileRequest::STATE_LOADED); + data = RawData::Ref(RawData::CreateFromFile(request_->service_locator(), + request_->uri(), + filename)); + if (data) { + request_->set_data(data); + } else { + success = false; + } + request_->set_error(error_collector.errors()); + } else { + // No error is passed in from the stream but we MUST have an error + // for the request to work on the javascript side. + request_->set_error("Could not download: " + request_->uri()); + } + request_->set_success(success); + // Since the standard codes only go far enough to tell us that the download + // succeeded, we set the success [and implicitly the done] flags to give the + // rest of the story. + if (request_->onreadystatechange()) + request_->onreadystatechange()->Run(); + } + + private: + FileRequest::Ref request_; + + explicit LoadRawDataURLCallback(FileRequest *request) + : request_(request) { + } +}; + // Sets up the parameters required for all FileRequests. void userglue_method_open(void *plugin_data, FileRequest *request, @@ -183,6 +248,9 @@ void userglue_method_send(void *plugin_data, case FileRequest::TYPE_TEXTURE: callback = LoadTextureURLCallback::Create(request); break; + case FileRequest::TYPE_RAWDATA: + callback = LoadRawDataURLCallback::Create(request); + break; default: CHECK(false); } diff --git a/o3d/plugin/cross/async_loading.h b/o3d/plugin/cross/async_loading.h index d0df9df..b64175e 100644 --- a/o3d/plugin/cross/async_loading.h +++ b/o3d/plugin/cross/async_loading.h @@ -32,8 +32,8 @@ // This file declares the glue for FileRequest actions. -#ifndef EXPERIMENTAL_O3D_O3DPLUGIN_AUTOGEN_O3D_GLUE_ASYNC_LOADING_H_ -#define EXPERIMENTAL_O3D_O3DPLUGIN_AUTOGEN_O3D_GLUE_ASYNC_LOADING_H_ +#ifndef O3D_PLUGIN_CROSS_ASYNC_LOADING_H_ +#define O3D_PLUGIN_CROSS_ASYNC_LOADING_H_ #include "core/cross/callback.h" #include "core/cross/types.h" @@ -64,4 +64,4 @@ void userglue_method_send(void *plugin_data, } // namespace namespace_o3d } // namespace glue -#endif // EXPERIMENTAL_O3D_O3DPLUGIN_AUTOGEN_O3D_GLUE_ASYNC_LOADING_H_ +#endif // O3D_PLUGIN_CROSS_ASYNC_LOADING_H_ diff --git a/o3d/plugin/idl/file_request.idl b/o3d/plugin/idl/file_request.idl index 5e931ce..5b1c9a3 100644 --- a/o3d/plugin/idl/file_request.idl +++ b/o3d/plugin/idl/file_request.idl @@ -76,6 +76,13 @@ namespace o3d { texture. %] [getter=texture] Texture? texture; + + %[ + On completion of successful RawData file loads, this holds the loaded + RawData. + %] + [getter=data] RawData? data; + %[ Whether or not to generate mip-maps on textures that are loaded (default: true). Mip-maps are not generated for DXTC textures. DDS files can contain diff --git a/o3d/plugin/idl/pack.idl b/o3d/plugin/idl/pack.idl index 0c9cba7..94f8e0e 100644 --- a/o3d/plugin/idl/pack.idl +++ b/o3d/plugin/idl/pack.idl @@ -270,8 +270,11 @@ typedef ObjectBase[] ObjectArray; [userglue_getter, getter] ObjectBaseArray objects_; %[ - Creates a FileRequest to be used to asynchronously load a Texture. - \param type Must be "TEXTURE" + Creates a FileRequest to be used to asynchronously load a Texture or + RawData. Note: Loading a "TEXTURE" is deprecated. The recommended way to + load a texture is to load a RawData, use that to create Bitmap, Massage + the Bitmap to your liking the use that to create a Texture. + \param type Must be "TEXTURE" or "RAWDATA" \return a FileRequest %] [noccp, userglue] FileRequest? CreateFileRequest(String type); |