Chromium Code Reviews| Index: chrome/browser/android/vr_shell/gltf_parser.cc |
| diff --git a/chrome/browser/android/vr_shell/gltf_parser.cc b/chrome/browser/android/vr_shell/gltf_parser.cc |
| index 6dbde77ac9e81adbab0a662e92cc178073a9c0f0..febcc2b4526680b12285573e4361584d5c03bc4d 100644 |
| --- a/chrome/browser/android/vr_shell/gltf_parser.cc |
| +++ b/chrome/browser/android/vr_shell/gltf_parser.cc |
| @@ -9,14 +9,39 @@ |
| #include "base/callback_helpers.h" |
| #include "base/files/file_util.h" |
| #include "base/json/json_file_value_serializer.h" |
| +#include "base/json/json_string_value_serializer.h" |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| +#include "base/strings/string_util.h" |
| +#include "base/sys_byteorder.h" |
| #include "net/base/data_url.h" |
| #include "net/base/filename_util.h" |
| #include "url/gurl.h" |
| namespace vr_shell { |
| +namespace { |
| +constexpr const char kFailedtoReadBinaryGltfMsg[] = |
|
mthiesse
2017/04/28 15:51:34
Wrap this in #if defined(DCHECK_IS_ON)
mthiesse
2017/04/28 16:11:45
I know this makes the code cleaner, but to avoid e
|
| + "Failed to read binary glTF: "; |
| +constexpr const char kGltfMagic[] = "glTF"; |
| +constexpr const char kBinaryGltfBufferName[] = "binary_glTF"; |
| +constexpr uint32_t kJsonGltfFormat = 0; |
| + |
| +enum { |
|
mthiesse
2017/04/28 15:51:34
Why is this an enum? Looks like just making consta
acondor_
2017/04/28 16:07:01
Done.
|
| + kVersionStart = 4, |
| + kLengthStart = 8, |
| + kContentLengthStart = 12, |
| + kContentFormatStart = 16, |
| + kContentStart = 20 |
| +}; |
| + |
| +uint32_t GetLE32(const char* data) { |
| + const uint32_t* int_data = reinterpret_cast<const uint32_t*>(data); |
| + return base::ByteSwapToLE32(*int_data); |
| +} |
| + |
| +} // namespace |
| + |
| GltfParser::GltfParser() {} |
| GltfParser::~GltfParser() = default; |
| @@ -25,6 +50,7 @@ std::unique_ptr<gltf::Asset> GltfParser::Parse( |
| const base::DictionaryValue& dict, |
| std::vector<std::unique_ptr<gltf::Buffer>>* buffers, |
| const base::FilePath& path) { |
| + DCHECK(buffers && buffers->size() <= 1); |
| path_ = path; |
| asset_ = base::MakeUnique<gltf::Asset>(); |
| @@ -40,6 +66,7 @@ std::unique_ptr<gltf::Asset> GltfParser::Parse( |
| std::unique_ptr<gltf::Asset> GltfParser::Parse( |
| const base::FilePath& gltf_path, |
| std::vector<std::unique_ptr<gltf::Buffer>>* buffers) { |
| + DCHECK(buffers && buffers->size() <= 1); |
| JSONFileValueDeserializer json_deserializer(gltf_path); |
| int error_code; |
| std::string error_msg; |
| @@ -89,12 +116,19 @@ bool GltfParser::ParseInternal( |
| bool GltfParser::SetBuffers( |
| const base::DictionaryValue& dict, |
| std::vector<std::unique_ptr<gltf::Buffer>>* buffers) { |
| - buffers->clear(); |
| + size_t buffer_cnt = 0; |
|
mthiesse
2017/04/28 15:51:34
nit: avoid using abbreviations in variable names l
acondor_
2017/04/28 16:07:01
Done.
|
| for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) { |
| const base::DictionaryValue* buffer_dict; |
| if (!it.value().GetAsDictionary(&buffer_dict)) |
| return false; |
| + if (it.key() == kBinaryGltfBufferName) { |
| + if (buffers->size() == buffer_cnt) |
| + return false; |
| + buffer_ids_[it.key()] = 0; |
| + continue; |
| + } |
| + |
| std::string uri_str; |
| if (!buffer_dict->GetString("uri", &uri_str)) |
| return false; |
| @@ -109,6 +143,7 @@ bool GltfParser::SetBuffers( |
| buffer_ids_[it.key()] = buffers->size(); |
| buffers->push_back(std::move(buffer)); |
| + ++buffer_cnt; |
| } |
| return true; |
| } |
| @@ -333,4 +368,64 @@ void GltfParser::Clear() { |
| scene_ids_.clear(); |
| } |
| +std::unique_ptr<gltf::Asset> BinaryGltfParser::Parse( |
| + const base::StringPiece& glb_content, |
| + std::vector<std::unique_ptr<gltf::Buffer>>* buffers, |
| + const base::FilePath& path) { |
| + DCHECK(buffers && buffers->empty()); |
| + if (glb_content.length() < kContentStart) { |
| + LOG(ERROR) << kFailedtoReadBinaryGltfMsg << "Incomplete data"; |
|
mthiesse
2017/04/28 15:51:34
Make these DLOGs? Best to avoid adding strings to
|
| + return nullptr; |
| + } |
| + if (!glb_content.starts_with(kGltfMagic)) { |
| + LOG(ERROR) << kFailedtoReadBinaryGltfMsg << "Unknown magic number"; |
| + return nullptr; |
| + } |
| + if (GetLE32(glb_content.data() + kVersionStart) != 1) { |
| + LOG(ERROR) << kFailedtoReadBinaryGltfMsg << "Unknown version"; |
|
mthiesse
2017/04/28 15:51:34
nit: s/Unknown/Unsupported
|
| + return nullptr; |
| + } |
| + if (GetLE32(glb_content.data() + kLengthStart) != glb_content.length()) { |
| + LOG(ERROR) << kFailedtoReadBinaryGltfMsg << "Incorrect file size"; |
| + return nullptr; |
| + } |
| + uint32_t content_length = GetLE32(glb_content.data() + kContentLengthStart); |
| + if (kContentStart + content_length > glb_content.length()) { |
| + LOG(ERROR) << kFailedtoReadBinaryGltfMsg << "Invalid content length"; |
| + return nullptr; |
| + } |
| + if (GetLE32(glb_content.data() + kContentFormatStart) != kJsonGltfFormat) { |
| + LOG(ERROR) << kFailedtoReadBinaryGltfMsg << "Unknown glTF format"; |
|
mthiesse
2017/04/28 15:51:34
nit: s/Unknown/Unsupported
|
| + return nullptr; |
| + } |
| + |
| + base::StringPiece gltf_content(glb_content.data() + kContentStart, |
| + content_length); |
| + int error_code; |
| + std::string error_msg; |
| + JSONStringValueDeserializer json_deserializer(gltf_content); |
| + auto gltf_value = json_deserializer.Deserialize(&error_code, &error_msg); |
| + if (!gltf_value) { |
| + LOG(ERROR) << kFailedtoReadBinaryGltfMsg << "Content not a valid JSON"; |
| + return nullptr; |
| + } |
| + base::DictionaryValue* gltf_dict; |
| + if (!gltf_value->GetAsDictionary(&gltf_dict)) { |
| + LOG(ERROR) << kFailedtoReadBinaryGltfMsg << "Content is not a valid glTF"; |
| + return nullptr; |
| + } |
| + |
| + auto glb_buffer = base::MakeUnique<gltf::Buffer>( |
| + glb_content.substr(kContentStart + content_length)); |
| + buffers->push_back(std::move(glb_buffer)); |
| + GltfParser gltf_parser; |
| + auto gltf_asset = gltf_parser.Parse(*gltf_dict, buffers); |
| + if (!gltf_asset) { |
| + LOG(ERROR) << kFailedtoReadBinaryGltfMsg << "Content is not a valid glTF"; |
| + buffers->clear(); |
| + return nullptr; |
| + } |
| + return gltf_asset; |
| +} |
| + |
| } // namespace vr_shell |