Index: gpu/command_buffer/client/gles2_implementation.cc |
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc |
index f0469a5cc5036d30307eecc86559df7b85e30687..7713d8fc2c3558b2661576b8bd13e1cb34ad93b1 100644 |
--- a/gpu/command_buffer/client/gles2_implementation.cc |
+++ b/gpu/command_buffer/client/gles2_implementation.cc |
@@ -4521,6 +4521,81 @@ bool GLES2Implementation::GetSamplerParameterivHelper( |
return false; |
} |
+bool GLES2Implementation::PackStringsToBucket(GLsizei count, |
+ const char* const* str, |
+ const GLint* length, |
+ const char* func_name) { |
+ DCHECK_LE(0, count); |
+ // Compute the total size. |
+ base::CheckedNumeric<size_t> total_size = count; |
+ total_size += 1; |
+ total_size *= sizeof(GLint); |
+ if (!total_size.IsValid()) { |
+ SetGLError(GL_INVALID_VALUE, func_name, "overflow"); |
+ return false; |
+ } |
+ size_t header_size = total_size.ValueOrDefault(0); |
+ std::vector<GLint> header(count + 1); |
+ header[0] = static_cast<GLint>(count); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ GLint len = 0; |
+ if (str[ii]) { |
+ len = (length && length[ii] >= 0) |
+ ? length[ii] |
+ : base::checked_cast<GLint>(strlen(str[ii])); |
+ } |
+ total_size += len; |
+ total_size += 1; // NULL at the end of each char array. |
+ if (!total_size.IsValid()) { |
+ SetGLError(GL_INVALID_VALUE, func_name, "overflow"); |
+ return false; |
+ } |
+ header[ii + 1] = len; |
+ } |
+ // Pack data into a bucket on the service. |
+ helper_->SetBucketSize(kResultBucketId, total_size.ValueOrDefault(0)); |
+ size_t offset = 0; |
+ for (GLsizei ii = 0; ii <= count; ++ii) { |
+ const char* src = |
+ (ii == 0) ? reinterpret_cast<const char*>(&header[0]) : str[ii - 1]; |
+ base::CheckedNumeric<size_t> checked_size = |
+ (ii == 0) ? header_size : static_cast<size_t>(header[ii]); |
+ if (ii > 0) { |
+ checked_size += 1; // NULL in the end. |
+ } |
+ if (!checked_size.IsValid()) { |
+ SetGLError(GL_INVALID_VALUE, func_name, "overflow"); |
+ return false; |
+ } |
+ size_t size = checked_size.ValueOrDefault(0); |
+ while (size) { |
+ ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); |
+ if (!buffer.valid() || buffer.size() == 0) { |
+ SetGLError(GL_OUT_OF_MEMORY, func_name, "too large"); |
+ return false; |
+ } |
+ size_t copy_size = buffer.size(); |
+ if (ii > 0 && buffer.size() == size) |
+ --copy_size; |
+ if (copy_size) |
+ memcpy(buffer.address(), src, copy_size); |
+ if (copy_size < buffer.size()) { |
+ // Append NULL in the end. |
+ DCHECK(copy_size + 1 == buffer.size()); |
+ char* str = reinterpret_cast<char*>(buffer.address()); |
+ str[copy_size] = 0; |
+ } |
+ helper_->SetBucketData(kResultBucketId, offset, buffer.size(), |
+ buffer.shm_id(), buffer.offset()); |
+ offset += buffer.size(); |
+ src += buffer.size(); |
+ size -= buffer.size(); |
+ } |
+ } |
+ DCHECK_EQ(total_size.ValueOrDefault(0), offset); |
+ return true; |
+} |
+ |
// Include the auto-generated part of this file. We split this because it means |
// we can easily edit the non-auto generated parts right here in this file |
// instead of having to edit some template or the code generator. |