summaryrefslogtreecommitdiffstats
path: root/o3d
diff options
context:
space:
mode:
authormstrydom@google.com <mstrydom@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-02 22:21:31 +0000
committermstrydom@google.com <mstrydom@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-02 22:21:31 +0000
commit8607f6dae7f80f494d55cb6701234ca7be18738b (patch)
tree2121ef79ee8402d5ada98b5c634c76c30263af1a /o3d
parent74d7f63a55085f2d7badff916b08ebe459184b9b (diff)
downloadchromium_src-8607f6dae7f80f494d55cb6701234ca7be18738b.zip
chromium_src-8607f6dae7f80f494d55cb6701234ca7be18738b.tar.gz
chromium_src-8607f6dae7f80f494d55cb6701234ca7be18738b.tar.bz2
This CL adds the createRawDataFromDataURL function to o3d.Pack. The function
takes as input a data URL, decodes the data, and returns the raw data in a RawData object. If the data URL has an invalid format, an error message is displayed. Currently only data URL's encoded in base64 are supported. The mime type is ignored. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25252 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d')
-rw-r--r--o3d/core/cross/pack.cc11
-rw-r--r--o3d/core/cross/pack.h7
-rw-r--r--o3d/core/cross/pack_test.cc16
-rw-r--r--o3d/import/cross/raw_data.cc26
-rw-r--r--o3d/import/cross/raw_data.h9
-rw-r--r--o3d/import/cross/raw_data_test.cc18
-rw-r--r--o3d/plugin/idl/pack.idl7
-rw-r--r--o3d/utils/cross/base64.cc128
-rw-r--r--o3d/utils/cross/base64.h34
-rw-r--r--o3d/utils/cross/base64_test.cc105
-rw-r--r--o3d/utils/cross/dataurl.cc60
-rw-r--r--o3d/utils/cross/dataurl.h18
-rw-r--r--o3d/utils/cross/dataurl_test.cc69
13 files changed, 506 insertions, 2 deletions
diff --git a/o3d/core/cross/pack.cc b/o3d/core/cross/pack.cc
index bcc5c06..fb3af89 100644
--- a/o3d/core/cross/pack.cc
+++ b/o3d/core/cross/pack.cc
@@ -309,6 +309,17 @@ std::vector<Bitmap*> Pack::CreateBitmapsFromRawData(RawData* raw_data) {
return bitmaps;
}
+// Creates a new RawData from a data URL.
+RawData* Pack::CreateRawDataFromDataURL(const String& data_url) {
+ RawData::Ref raw_data = RawData::CreateFromDataURL(service_locator(),
+ data_url);
+
+ if (!raw_data.IsNull()) {
+ RegisterObject(raw_data);
+ }
+ return raw_data.Get();
+}
+
// Creates a Texture2D object and allocates the necessary resources for it.
Texture2D* Pack::CreateTexture2D(int width,
int height,
diff --git a/o3d/core/cross/pack.h b/o3d/core/cross/pack.h
index ce7be0f..1d17c83 100644
--- a/o3d/core/cross/pack.h
+++ b/o3d/core/cross/pack.h
@@ -235,6 +235,13 @@ class Pack : public NamedObject {
// bitmaps: A vector of pointers to bitmaps. If empty there was an error.
std::vector<Bitmap*> CreateBitmapsFromRawData(RawData* raw_data);
+ // Creates a new RawData from a String containing a data URL.
+ // Parameters:
+ // data_url: Contains the data URL that is to be decoded.
+ // Returns:
+ // A pointer to the RawData that contains the data URL's data.
+ RawData* CreateRawDataFromDataURL(const String& data_url);
+
// Creates a new Texture2D object of the specified size and format and
// reserves the necessary resources for it.
// Parameters:
diff --git a/o3d/core/cross/pack_test.cc b/o3d/core/cross/pack_test.cc
index 5aca47f..0b637ec 100644
--- a/o3d/core/cross/pack_test.cc
+++ b/o3d/core/cross/pack_test.cc
@@ -162,4 +162,20 @@ TEST_F(PackTest, RemoveObject) {
EXPECT_TRUE(pack->Destroy());
}
+TEST_F(PackTest, CreateRawDataFromDataURL) {
+ Pack* pack = object_manager()->CreatePack();
+ RawData* raw_data = pack->CreateRawDataFromDataURL("data:;base64,YWJj");
+
+ EXPECT_FALSE(raw_data == NULL);
+ EXPECT_FALSE(CheckErrorExists());
+}
+
+TEST_F(PackTest, CreateRawDataFromDataURLFail) {
+ Pack* pack = object_manager()->CreatePack();
+ RawData* raw_data = pack->CreateRawDataFromDataURL("data:;base64,Y");
+
+ EXPECT_TRUE(raw_data == NULL);
+ EXPECT_TRUE(CheckErrorExists());
+}
+
} // namespace o3d
diff --git a/o3d/import/cross/raw_data.cc b/o3d/import/cross/raw_data.cc
index 66e0109..91e2bc6 100644
--- a/o3d/import/cross/raw_data.cc
+++ b/o3d/import/cross/raw_data.cc
@@ -38,6 +38,7 @@
#include "utils/cross/file_path_utils.h"
#include "base/file_path.h"
#include "base/file_util.h"
+#include "utils/cross/dataurl.h"
#ifdef OS_MACOSX
#include <CoreFoundation/CoreFoundation.h>
@@ -92,7 +93,16 @@ RawData::Ref RawData::CreateFromFile(ServiceLocator* service_locator,
return data;
}
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+RawData::Ref RawData::CreateFromDataURL(ServiceLocator* service_locator,
+ const String& data_url) {
+ RawData::Ref raw_data(Create(service_locator, "", NULL, 0));
+ if (!raw_data->SetFromDataURL(data_url)) {
+ raw_data.Reset();
+ }
+ return raw_data;
+}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
RawData::~RawData() {
Discard();
@@ -137,7 +147,21 @@ bool RawData::SetFromFile(const String& filename) {
return result;
}
-
+// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+bool RawData::SetFromDataURL(const String& data_url) {
+ String error_string;
+ size_t data_length = 0;
+ bool no_errors = dataurl::FromDataURL(data_url,
+ &data_,
+ &data_length,
+ &error_string);
+ length_ = data_length;
+ if (!no_errors) {
+ O3D_ERROR(service_locator()) << error_string;
+ return false;
+ }
+ return true;
+}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const uint8 *RawData::GetData() const {
// Return data immediately if we have it
diff --git a/o3d/import/cross/raw_data.h b/o3d/import/cross/raw_data.h
index 092c800..96ea3f4 100644
--- a/o3d/import/cross/raw_data.h
+++ b/o3d/import/cross/raw_data.h
@@ -62,6 +62,11 @@ class RawData : public ParamObject {
const String &uri,
const String& filename);
+ // Creates a RawData object, taking as input a string containing a
+ // data URL.
+ static RawData::Ref CreateFromDataURL(ServiceLocator* service_locator,
+ const String& data_url);
+
virtual ~RawData();
const uint8 *GetData() const;
@@ -110,6 +115,10 @@ class RawData : public ParamObject {
bool SetFromFile(const String& filename);
+ // Decodes data from a data URL and stores that data in this
+ // RawData object. Returns false on error, true otherwise
+ bool SetFromDataURL(const String& data_url);
+
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 b4c5f86..fe0f212 100644
--- a/o3d/import/cross/raw_data_test.cc
+++ b/o3d/import/cross/raw_data_test.cc
@@ -157,7 +157,7 @@ struct TestData {
size_t offset;
};
-} // anonymous namespace
+} // anonymous namespace
TEST_F(RawDataTest, StringValue) {
// A BOM in the front (valid)
@@ -266,4 +266,20 @@ TEST_F(RawDataTest, StringValue) {
}
}
+TEST_F(RawDataTest, CreateFromDataURL) {
+ RawData::Ref ref = RawData::CreateFromDataURL(g_service_locator,
+ "data:;base64,YWJj");
+ ASSERT_FALSE(ref.IsNull());
+ EXPECT_EQ(3u, ref->GetLength());
+ EXPECT_FALSE(CheckErrorExists(error_status()));
+ EXPECT_EQ(0, memcmp(ref->GetData(), "abc", 3));
+}
+
+TEST_F(RawDataTest, CreateFromDataURLFail) {
+ RawData::Ref ref = RawData::CreateFromDataURL(g_service_locator,
+ "data:;base64,Y");
+ EXPECT_TRUE(ref.IsNull());
+ EXPECT_TRUE(CheckErrorExists(error_status()));
+}
+
} // namespace o3d
diff --git a/o3d/plugin/idl/pack.idl b/o3d/plugin/idl/pack.idl
index 3d63f6b..3fd5b6d 100644
--- a/o3d/plugin/idl/pack.idl
+++ b/o3d/plugin/idl/pack.idl
@@ -325,6 +325,13 @@ typedef Bitmap[] BitmapArray;
\return An Array of Bitmaps object.
%]
BitmapArray CreateBitmapsFromRawData(RawData raw_data);
+
+ %[
+ Create RawData given a data URL.
+ \param data_url The data URL from which to create the RawData.
+ \return The RawData.
+ %]
+ RawData CreateRawDataFromDataURL(String data_url);
}; // Pack
} // namespace o3d
diff --git a/o3d/utils/cross/base64.cc b/o3d/utils/cross/base64.cc
index 3662258..7e688b0 100644
--- a/o3d/utils/cross/base64.cc
+++ b/o3d/utils/cross/base64.cc
@@ -85,6 +85,134 @@ void Encode(const void* src_ptr, size_t length, void* dst_ptr) {
}
}
+// This function actually does the decoding.
+// Parameters:
+// src_ptr: pointer to the source data
+// input_length: The length in bytes of the source data.
+// dst_ptr: pointer to where the output data should be stored.
+// dst_buffer_length: the size in bytes of the dst_ptr buffer. This
+// is used to check for overflow. Not used if write_destination is
+// false.
+// output_length: The output length (in bytes) will be stored here if
+// it is not null.
+// write_destination: If true, actually write to the output. Otherwise,
+// the length of the output will be determined only.
+DecodeStatus PerformDecode(const void* src_ptr,
+ size_t input_length,
+ void* dst_ptr,
+ size_t dst_buffer_length,
+ size_t* output_length,
+ bool write_destination) {
+ const int kDecodePad = -2;
+
+ static const int8 kDecodeData[] = {
+ 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, kDecodePad, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+ };
+
+ uint8* dst = reinterpret_cast<uint8*>(dst_ptr);
+ const uint8* dst_start = reinterpret_cast<const uint8*>(dst_ptr);
+ const uint8* dst_end = dst_start + dst_buffer_length;
+ const uint8* src = reinterpret_cast<const uint8*>(src_ptr);
+ bool pad_two = false;
+ bool pad_three = false;
+ const uint8* end = src + input_length;
+ while (src < end) {
+ uint8 bytes[4];
+ int byte = 0;
+ do {
+ uint8 src_byte = *src++;
+ if (src_byte == 0)
+ goto goHome;
+ if (src_byte <= ' ')
+ continue; // treat as white space
+ if (src_byte < '+' || src_byte > 'z')
+ return kBadCharError;
+ int8 decoded = kDecodeData[src_byte - '+'];
+ bytes[byte] = decoded;
+ if (decoded < 0) {
+ if (decoded == kDecodePad)
+ goto handlePad;
+ return kBadCharError;
+ } else {
+ byte++;
+ }
+ if (*src)
+ continue;
+ if (byte == 0)
+ goto goHome;
+ if (byte == 4)
+ break;
+ handlePad:
+ if (byte < 2)
+ return kPadError;
+ pad_three = true;
+ if (byte == 2)
+ pad_two = true;
+ break;
+ } while (byte < 4);
+ int two, three;
+ if (write_destination) {
+ int one = (bytes[0] << 2) & 0xFF;
+ two = bytes[1];
+ one |= two >> 4;
+ two = (two << 4) & 0xFF;
+ three = bytes[2];
+ two |= three >> 2;
+ three = (three << 6) & 0xFF;
+ three |= bytes[3];
+ O3D_ASSERT(one < 256 && two < 256 && three < 256);
+ if (dst >= dst_end) {
+ return kOutputOverflowError;
+ }
+ *dst = one;
+ }
+ dst++;
+ if (pad_two)
+ break;
+ if (write_destination) {
+ if (dst >= dst_end) {
+ return kOutputOverflowError;
+ }
+ *dst = two;
+ }
+ dst++;
+ if (pad_three)
+ break;
+ if (write_destination) {
+ if (dst >= dst_end) {
+ return kOutputOverflowError;
+ }
+ *dst = three;
+ }
+ dst++;
+ }
+ goHome:
+ if (output_length) {
+ *output_length = dst - dst_start;
+ }
+ return kSuccess;
+}
+
+// Returns the number of bytes of output data after decoding from base64.
+DecodeStatus GetDecodeLength(const void* src,
+ size_t input_length,
+ size_t* decode_length) {
+ return PerformDecode(src, input_length, NULL, 0, decode_length, false);
+}
+
+// Decodes the src data from base64 and stores the result in dst.
+DecodeStatus Decode(const void* src,
+ size_t input_length,
+ void* dst,
+ size_t dst_buffer_length) {
+ return PerformDecode(src, input_length, dst, dst_buffer_length, NULL, true);
+}
+
} // namespace base64
} // namespace o3d
diff --git a/o3d/utils/cross/base64.h b/o3d/utils/cross/base64.h
index d56ad4f..6cc7762 100644
--- a/o3d/utils/cross/base64.h
+++ b/o3d/utils/cross/base64.h
@@ -40,6 +40,14 @@
namespace o3d {
namespace base64 {
+// The possible error codes that can occur during a decoding.
+enum DecodeStatus {
+ kSuccess,
+ kPadError,
+ kBadCharError,
+ kOutputOverflowError
+};
+
// Returns the number of bytes needed to encode length bytes in base64.
size_t GetEncodeLength(size_t length);
@@ -51,6 +59,32 @@ size_t GetEncodeLength(size_t length);
// dst: pointer to place to store result.
void Encode(const void* src, size_t length, void* dst);
+// Used to obtain the number of bytes needed to decode the src data
+// from base64.
+// Parameters:
+// src: pointer to the source data.
+// input_length: the length of the source data
+// decode_length: the length in bytes of the decoded data will be
+// placed here.
+DecodeStatus GetDecodeLength(const void* src,
+ size_t input_length,
+ size_t* decode_length);
+
+// Decodes the src, which should be encoded in base64, into the dst.
+// dst must have enough space to hold the result. The number of bytes
+// necessary can be obtained by calling GetDecodeLength()
+// Parameters:
+// src: pointer to the source data
+// input_length: the length of the source data
+// dst: pointer to where the result should be stored.
+// dst_buffer_length: the size in bytes of the dst buffer. This is
+// used to check for buffer overflow.
+// Returns an error code (of type DecodeStatus)
+DecodeStatus Decode(const void* src,
+ size_t input_length,
+ void* dst,
+ size_t dst_buffer_length);
+
} // namespace base64
} // namespace o3d
diff --git a/o3d/utils/cross/base64_test.cc b/o3d/utils/cross/base64_test.cc
index b6d3aea..9eacd69 100644
--- a/o3d/utils/cross/base64_test.cc
+++ b/o3d/utils/cross/base64_test.cc
@@ -60,6 +60,111 @@ TEST_F(Base64Test, Encode) {
EXPECT_EQ(0xFF, buffer[8]);
}
+TEST_F(Base64Test, GetDecodeLength) {
+ size_t length = 256u;
+ base64::GetDecodeLength("", 0, &length);
+ EXPECT_EQ(0u, length);
+
+ length = 256u;
+ base64::GetDecodeLength("YQ==", 4, &length);
+ EXPECT_EQ(1u, length);
+
+ length = 256u;
+ base64::GetDecodeLength("YWI=", 4, &length);
+ EXPECT_EQ(2u, length);
+
+ length = 256u;
+ base64::GetDecodeLength("YWJj", 4, &length);
+ EXPECT_EQ(3u, length);
+
+ length = 256u;
+ base64::GetDecodeLength("YWJjZA==", 8, &length);
+ EXPECT_EQ(4u, length);
+
+ length = 256u;
+ base64::GetDecodeLength("YWJjZGU=", 8, &length);
+ EXPECT_EQ(5u, length);
+}
+
+TEST_F(Base64Test, GetDecodeLengthInputError) {
+ base64::DecodeStatus status = base64::kSuccess;
+ size_t length = 256u;
+ status = base64::GetDecodeLength("Y@==", 4, &length);
+ EXPECT_EQ(base64::kBadCharError, status);
+
+ status = base64::GetDecodeLength("Y Q==", 4, &length);
+ EXPECT_EQ(base64::kSuccess, status);
+
+ status = base64::GetDecodeLength("Y", 1, &length);
+ EXPECT_EQ(base64::kPadError, status);
+}
+
+TEST_F(Base64Test, Decode) {
+ unsigned char buffer[10];
+ memset(buffer, 0xFF, sizeof(buffer));
+ unsigned char result_buffer[10];
+ memset(result_buffer, 0xFF, sizeof(result_buffer));
+ base64::DecodeStatus status = base64::kSuccess;
+
+ status = base64::Decode("", 0, buffer, 10);
+ EXPECT_EQ(base64::kSuccess, status);
+ EXPECT_EQ(0, memcmp(buffer, result_buffer, 10));
+
+ result_buffer[0] = 'a';
+ status = base64::Decode("YQ==", 4, buffer, 10);
+ EXPECT_EQ(base64::kSuccess, status);
+ EXPECT_EQ(0, memcmp(buffer, result_buffer, 10));
+
+ result_buffer[1] = 'b';
+ status = base64::Decode("YWI=", 4, buffer, 10);
+ EXPECT_EQ(base64::kSuccess, status);
+ EXPECT_EQ(0, memcmp(buffer, result_buffer, 10));
+
+ result_buffer[2] = 'c';
+ status = base64::Decode("YWJj", 4, buffer, 10);
+ EXPECT_EQ(base64::kSuccess, status);
+ EXPECT_EQ(0, memcmp(buffer, result_buffer, 10));
+
+ result_buffer[3] = 'd';
+ status = base64::Decode("YWJjZA==", 8, buffer, 10);
+ EXPECT_EQ(base64::kSuccess, status);
+ EXPECT_EQ(0, memcmp(buffer, result_buffer, 10));
+
+ result_buffer[4] = 'e';
+ status = base64::Decode("YWJjZGU=", 8, buffer, 10);
+ EXPECT_EQ(base64::kSuccess, status);
+ EXPECT_EQ(0, memcmp(buffer, result_buffer, 10));
+}
+
+TEST_F(Base64Test, DecodeInputError) {
+ unsigned char buffer[10];
+ base64::DecodeStatus status = base64::kSuccess;
+ status = base64::Decode("Y@==", 4, buffer, 10);
+ EXPECT_EQ(base64::kBadCharError, status);
+
+ status = base64::Decode("Y Q==", 4, buffer, 10);
+ EXPECT_EQ(base64::kSuccess, status);
+
+ status = base64::Decode("Y", 1, buffer, 10);
+ EXPECT_EQ(base64::kPadError, status);
+}
+
+TEST_F(Base64Test, DecodeOverflowError) {
+ unsigned char buffer[10];
+ base64::DecodeStatus status = base64::kSuccess;
+ status = base64::Decode("YWJjZA==", 8, buffer, 3);
+ EXPECT_EQ(base64::kOutputOverflowError, status);
+
+ status = base64::Decode("YWJjZA==", 8, buffer, 4);
+ EXPECT_EQ(base64::kSuccess, status);
+
+ status = base64::Decode("YQ==", 8, buffer, 0);
+ EXPECT_EQ(base64::kOutputOverflowError, status);
+
+ status = base64::Decode("YQ==", 8, buffer, 1);
+ EXPECT_EQ(base64::kSuccess, status);
+}
+
} // namespace o3d
diff --git a/o3d/utils/cross/dataurl.cc b/o3d/utils/cross/dataurl.cc
index 8334b8d..f796719 100644
--- a/o3d/utils/cross/dataurl.cc
+++ b/o3d/utils/cross/dataurl.cc
@@ -48,6 +48,66 @@ String ToDataURL(const String& mime_type, const void* data, size_t length) {
return result;
}
+// Decodes the data URL and stores a pointer to the data in dst_buffer
+bool FromDataURL(const String& data_url,
+ scoped_array<uint8>* dst_buffer,
+ size_t* output_length,
+ String* error_string) {
+ // First parse the data_url
+ const String kDataHeader("data:");
+ const String kBase64Header(";base64,");
+ // The string has to be long enough.
+ if (data_url.size() <= kDataHeader.size() + kBase64Header.size()) {
+ *error_string = "Invalid formatting: The data URL is not long enough.";
+ return false;
+ }
+ // it must start with "data:"
+ if (data_url.compare(0, kDataHeader.size(), kDataHeader) != 0) {
+ *error_string
+ = "Invalid formatting: The data URL must start with 'data:'";
+ return false;
+ }
+ // we only support base64 data URL's
+ String::size_type data_index = data_url.find(kBase64Header);
+ if (data_index == String::npos) {
+ *error_string
+ = "Invalid formatting: The data URL have ';base64,' in the header.";
+ return false;
+ }
+ // The start of the data.
+ data_index += kBase64Header.size();
+ if (data_index >= data_url.size()) {
+ *error_string
+ = "Invalid formatting: There must be data in the body of the data URL.";
+ return false;
+ }
+
+ // Get the length of the decoded data
+ size_t input_length = data_url.size() - data_index;
+ base64::DecodeStatus return_code = base64::GetDecodeLength(
+ &data_url[data_index],
+ input_length,
+ output_length);
+ if (return_code != base64::kSuccess) {
+ if (return_code == base64::kPadError) {
+ *error_string
+ = "Invalid formatting: Padding error in the data URL data.";
+ } else {
+ *error_string
+ = "Invalid formatting: Bad character error in the data URL data.";
+ }
+ return false;
+ }
+
+ dst_buffer->reset(new uint8[*output_length]);
+ base64::Decode(&data_url[data_index],
+ input_length,
+ dst_buffer->get(),
+ (*output_length));
+
+ return true;
+}
+
} // namespace dataurl
} // namespace o3d
diff --git a/o3d/utils/cross/dataurl.h b/o3d/utils/cross/dataurl.h
index cc46e01..7cb979a 100644
--- a/o3d/utils/cross/dataurl.h
+++ b/o3d/utils/cross/dataurl.h
@@ -35,6 +35,7 @@
#define O3D_UTILS_CROSS_DATAURL_H_
#include "core/cross/types.h"
+#include "base/scoped_ptr.h"
namespace o3d {
namespace dataurl {
@@ -45,6 +46,23 @@ extern const char* const kEmptyDataURL;
// Creates a data URL for the given data.
String ToDataURL(const String& mime_type, const void* data, size_t length);
+// Decodes the data from a data URL and stores a pointer to the data in
+// dst_buffer. If an error occurs in decoding, it returns false and
+// error_string will contain an error message. Otherwise, returns true.
+// Parameters:
+// data_url: The data URL from which to extract the data.
+// dst_buffer: A pointer to the output data will be stored in this
+// scoped_array.
+// output_length: The length of the output data will be stored at this
+// address.
+// error_string: This will contain the error message, if an error occurs.
+// Returns:
+// False if an error occurs in decoding, true otherwise.
+bool FromDataURL(const String& data_url,
+ scoped_array<uint8>* dst_buffer,
+ size_t* output_length,
+ String* error_string);
+
} // namespace dataurl
} // namespace o3d
diff --git a/o3d/utils/cross/dataurl_test.cc b/o3d/utils/cross/dataurl_test.cc
index 8404650..4095859 100644
--- a/o3d/utils/cross/dataurl_test.cc
+++ b/o3d/utils/cross/dataurl_test.cc
@@ -51,6 +51,75 @@ TEST_F(DataURLTest, ToDataURL) {
dataurl::ToDataURL("de/ej", "ab\0c", 4).c_str());
}
+TEST_F(DataURLTest, FromDataURL) {
+ String data_url("data:a/b;base64,YWJj");
+ scoped_array<uint8> output;
+ size_t output_length;
+ String error_string;
+
+ EXPECT_TRUE(dataurl::FromDataURL(data_url,
+ &output,
+ &output_length,
+ &error_string));
+ EXPECT_EQ(3, output_length);
+ EXPECT_EQ(0, memcmp("abc", output.get(), 3));
+}
+
+TEST_F(DataURLTest, FromDataURLFormatErrors) {
+ scoped_array<uint8> output;
+ size_t output_length;
+ String error_string("");
+ // Not long enough
+ EXPECT_FALSE(dataurl::FromDataURL("",
+ &output,
+ &output_length,
+ &error_string));
+ EXPECT_LT(0u, error_string.size());
+ // Does not start with "data:"
+ error_string = "";
+ EXPECT_FALSE(dataurl::FromDataURL("aaaaaaaaaaaaaaaa",
+ &output,
+ &output_length,
+ &error_string));
+ EXPECT_LT(0u, error_string.size());
+ // Must contain base64
+ error_string = "";
+ EXPECT_FALSE(dataurl::FromDataURL("data:aaaaaaaaaaa",
+ &output,
+ &output_length,
+ &error_string));
+ EXPECT_LT(0u, error_string.size());
+ // Must contain data.
+ error_string = "";
+ EXPECT_FALSE(dataurl::FromDataURL("data:aa;base64,",
+ &output,
+ &output_length,
+ &error_string));
+ EXPECT_LT(0u, error_string.size());
+
+ // Bad character in data.
+ error_string = "";
+ EXPECT_FALSE(dataurl::FromDataURL("data:;base64,@",
+ &output,
+ &output_length,
+ &error_string));
+ EXPECT_LT(0u, error_string.size());
+ // Padding error in data.
+ error_string = "";
+ EXPECT_FALSE(dataurl::FromDataURL("data:;base64,Y",
+ &output,
+ &output_length,
+ &error_string));
+ EXPECT_LT(0u, error_string.size());
+ // Correct.
+ error_string = "";
+ EXPECT_TRUE(dataurl::FromDataURL("data:;base64,YWJj",
+ &output,
+ &output_length,
+ &error_string));
+ EXPECT_EQ(0u, error_string.size());
+}
+
} // namespace o3d