| OLD | NEW |
| 1 // Copyright 2017 The Chromium OS Authors. All rights reserved. | 1 // Copyright 2017 The Chromium OS Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "compressor_io_javascript_stream.h" | 5 #include "compressor_io_javascript_stream.h" |
| 6 | 6 |
| 7 #include <limits> | 7 #include <limits> |
| 8 #include <thread> | 8 #include <thread> |
| 9 | 9 |
| 10 #include "archive.h" | |
| 11 #include "ppapi/cpp/logging.h" | 10 #include "ppapi/cpp/logging.h" |
| 12 | 11 |
| 13 CompressorIOJavaScriptStream::CompressorIOJavaScriptStream( | 12 CompressorIOJavaScriptStream::CompressorIOJavaScriptStream( |
| 14 JavaScriptCompressorRequestorInterface* requestor) | 13 JavaScriptCompressorRequestorInterface* requestor) |
| 15 : requestor_(requestor) { | 14 : requestor_(requestor), buffer_offset_(-1), buffer_data_length_(0) { |
| 16 pthread_mutex_init(&shared_state_lock_, NULL); | 15 pthread_mutex_init(&shared_state_lock_, nullptr); |
| 17 pthread_cond_init(&available_data_cond_, NULL); | 16 pthread_cond_init(&available_data_cond_, nullptr); |
| 18 pthread_cond_init(&data_written_cond_, NULL); | 17 pthread_cond_init(&data_written_cond_, nullptr); |
| 19 | 18 |
| 20 pthread_mutex_lock(&shared_state_lock_); | 19 pthread_mutex_lock(&shared_state_lock_); |
| 21 available_data_ = false; | 20 available_data_ = false; |
| 21 buffer_ = new char[compressor_stream_constants::kMaximumDataChunkSize]; |
| 22 pthread_mutex_unlock(&shared_state_lock_); | 22 pthread_mutex_unlock(&shared_state_lock_); |
| 23 } | 23 } |
| 24 | 24 |
| 25 CompressorIOJavaScriptStream::~CompressorIOJavaScriptStream() { | 25 CompressorIOJavaScriptStream::~CompressorIOJavaScriptStream() { |
| 26 pthread_mutex_lock(&shared_state_lock_); |
| 27 delete buffer_; |
| 28 pthread_mutex_unlock(&shared_state_lock_); |
| 26 pthread_cond_destroy(&data_written_cond_); | 29 pthread_cond_destroy(&data_written_cond_); |
| 27 pthread_cond_destroy(&available_data_cond_); | 30 pthread_cond_destroy(&available_data_cond_); |
| 28 pthread_mutex_destroy(&shared_state_lock_); | 31 pthread_mutex_destroy(&shared_state_lock_); |
| 29 }; | 32 }; |
| 30 | 33 |
| 31 int64_t CompressorIOJavaScriptStream::Write(int64_t byte_to_write, | 34 int64_t CompressorIOJavaScriptStream::Flush() { |
| 32 const pp::VarArrayBuffer& buffer) { | |
| 33 pthread_mutex_lock(&shared_state_lock_); | 35 pthread_mutex_lock(&shared_state_lock_); |
| 34 requestor_->WriteChunkRequest(byte_to_write, buffer); | 36 |
| 37 if (buffer_data_length_ == 0) { |
| 38 pthread_mutex_unlock(&shared_state_lock_); |
| 39 return 0; |
| 40 } |
| 41 |
| 42 // Copy the data in buffer_ to array_buffer. |
| 43 pp::VarArrayBuffer array_buffer(buffer_data_length_); |
| 44 char* array_buffer_data = static_cast<char*>(array_buffer.Map()); |
| 45 memcpy(array_buffer_data, buffer_, buffer_data_length_); |
| 46 array_buffer.Unmap(); |
| 47 |
| 48 requestor_->WriteChunkRequest(buffer_offset_, |
| 49 buffer_data_length_, |
| 50 array_buffer); |
| 35 | 51 |
| 36 pthread_cond_wait(&data_written_cond_, &shared_state_lock_); | 52 pthread_cond_wait(&data_written_cond_, &shared_state_lock_); |
| 37 | 53 |
| 38 int64_t written_bytes = written_bytes_; | 54 int64_t written_bytes = written_bytes_; |
| 55 if (written_bytes < buffer_data_length_) { |
| 56 pthread_mutex_unlock(&shared_state_lock_); |
| 57 return -1 /* Error */; |
| 58 } |
| 59 |
| 60 // Reset the offset and length to the default values. |
| 61 buffer_offset_ = -1; |
| 62 buffer_data_length_ = 0; |
| 63 |
| 39 pthread_mutex_unlock(&shared_state_lock_); | 64 pthread_mutex_unlock(&shared_state_lock_); |
| 40 | |
| 41 return written_bytes; | 65 return written_bytes; |
| 42 } | 66 } |
| 43 | 67 |
| 44 void CompressorIOJavaScriptStream::WriteChunkDone(int64_t written_bytes) { | 68 int64_t CompressorIOJavaScriptStream::Write(int64_t zip_offset, |
| 69 int64_t zip_length, |
| 70 const char* zip_buffer) { |
| 71 pthread_mutex_lock(&shared_state_lock_); |
| 72 |
| 73 // The offset from which the data should be written onto the archive. |
| 74 int64_t current_offset = zip_offset; |
| 75 int64_t left_length = zip_length; |
| 76 const char* buffer_pointer = zip_buffer; |
| 77 |
| 78 do { |
| 79 // Flush the buffer if the data in the buffer cannot be reused. |
| 80 // The following is the brief explanation about the conditions of the |
| 81 // following if statement. |
| 82 // 1: The buffer is not in the initial state (empty). |
| 83 // The buffer should have some data to flush. |
| 84 // 2: This write operation is not to append the data to the buffer. |
| 85 // 3: The buffer overflows if we append the data to the buffer. |
| 86 // If we can append the new data to the current data in the buffer, |
| 87 // we should not flush the buffer. |
| 88 // 4: The index to write is outside the buffer. |
| 89 // If we want to write data outside the range, we first need to flush |
| 90 // the buffer, and then cache the data in the buffer. |
| 91 if (buffer_offset_ >= 0 && /* 1 */ |
| 92 (current_offset != buffer_offset_ + buffer_data_length_ || /* 2 */ |
| 93 buffer_data_length_ + left_length > |
| 94 compressor_stream_constants::kMaximumDataChunkSize) && /* 3 */ |
| 95 (current_offset < buffer_offset_ || |
| 96 buffer_offset_ + buffer_data_length_ < |
| 97 current_offset + left_length) /* 4 */ ) { |
| 98 pthread_mutex_unlock(&shared_state_lock_); |
| 99 int64_t bytes_to_write = buffer_data_length_; |
| 100 if (Flush() != bytes_to_write) |
| 101 return -1; |
| 102 pthread_mutex_lock(&shared_state_lock_); |
| 103 } |
| 104 |
| 105 // How many bytes we should copy to buffer_ in this iteration. |
| 106 int64_t copy_length = std::min( |
| 107 left_length, compressor_stream_constants::kMaximumDataChunkSize); |
| 108 // Set up the buffer_offset_ if the buffer_ has no data. |
| 109 if (buffer_offset_ == -1 /* initial state */) |
| 110 buffer_offset_ = current_offset; |
| 111 // Calculate the relative offset from left_length. |
| 112 int64_t offset_in_buffer = current_offset - buffer_offset_; |
| 113 // Copy data from zip_buffer, which is pointed by buffer_pointer, to buffer_
. |
| 114 memcpy(buffer_ + offset_in_buffer, buffer_pointer, copy_length); |
| 115 |
| 116 buffer_pointer += copy_length; |
| 117 buffer_data_length_ = std::max( |
| 118 buffer_data_length_, offset_in_buffer + copy_length); |
| 119 current_offset += copy_length; |
| 120 left_length -= copy_length; |
| 121 } while (left_length > 0); |
| 122 |
| 123 pthread_mutex_unlock(&shared_state_lock_); |
| 124 return zip_length; |
| 125 } |
| 126 |
| 127 int64_t CompressorIOJavaScriptStream::WriteChunkDone(int64_t written_bytes) { |
| 45 pthread_mutex_lock(&shared_state_lock_); | 128 pthread_mutex_lock(&shared_state_lock_); |
| 46 written_bytes_ = written_bytes; | 129 written_bytes_ = written_bytes; |
| 47 pthread_cond_signal(&data_written_cond_); | 130 pthread_cond_signal(&data_written_cond_); |
| 48 pthread_mutex_unlock(&shared_state_lock_); | 131 pthread_mutex_unlock(&shared_state_lock_); |
| 132 return written_bytes; |
| 49 } | 133 } |
| 50 | 134 |
| 51 int64_t CompressorIOJavaScriptStream::Read(int64_t bytes_to_read, | 135 int64_t CompressorIOJavaScriptStream::Read(int64_t bytes_to_read, |
| 52 char* destination_buffer) { | 136 char* destination_buffer) { |
| 53 pthread_mutex_lock(&shared_state_lock_); | 137 pthread_mutex_lock(&shared_state_lock_); |
| 54 | 138 |
| 55 destination_buffer_ = destination_buffer; | 139 destination_buffer_ = destination_buffer; |
| 56 requestor_->ReadFileChunkRequest(bytes_to_read); | 140 requestor_->ReadFileChunkRequest(bytes_to_read); |
| 57 | 141 |
| 58 while (!available_data_) { | 142 while (!available_data_) { |
| 59 pthread_cond_wait(&available_data_cond_, &shared_state_lock_); | 143 pthread_cond_wait(&available_data_cond_, &shared_state_lock_); |
| 60 } | 144 } |
| 61 | 145 |
| 62 int64_t read_bytes = read_bytes_; | 146 int64_t read_bytes = read_bytes_; |
| 63 available_data_ = false; | 147 available_data_ = false; |
| 64 pthread_mutex_unlock(&shared_state_lock_); | 148 pthread_mutex_unlock(&shared_state_lock_); |
| 65 return read_bytes; | 149 return read_bytes; |
| 66 } | 150 } |
| 67 | 151 |
| 68 void CompressorIOJavaScriptStream::ReadFileChunkDone(int64_t read_bytes, | 152 int64_t CompressorIOJavaScriptStream::ReadFileChunkDone(int64_t read_bytes, |
| 69 pp::VarArrayBuffer* array_buffer) { | 153 pp::VarArrayBuffer* array_buffer) { |
| 70 pthread_mutex_lock(&shared_state_lock_); | 154 pthread_mutex_lock(&shared_state_lock_); |
| 71 | 155 |
| 72 // JavaScript sets a negative value in read_bytes if an error occurred while | 156 // JavaScript sets a negative value in read_bytes if an error occurred while |
| 73 // reading a chunk. | 157 // reading a chunk. |
| 74 if (read_bytes >= 0) { | 158 if (read_bytes >= 0) { |
| 75 char* array_buffer_data = static_cast<char*>(array_buffer->Map()); | 159 char* array_buffer_data = static_cast<char*>(array_buffer->Map()); |
| 76 memcpy(destination_buffer_, array_buffer_data, read_bytes); | 160 memcpy(destination_buffer_, array_buffer_data, read_bytes); |
| 77 array_buffer->Unmap(); | 161 array_buffer->Unmap(); |
| 78 } | 162 } |
| 79 | 163 |
| 80 read_bytes_ = read_bytes; | 164 read_bytes_ = read_bytes; |
| 81 available_data_ = true; | 165 available_data_ = true; |
| 82 pthread_cond_signal(&available_data_cond_); | 166 pthread_cond_signal(&available_data_cond_); |
| 83 pthread_mutex_unlock(&shared_state_lock_); | 167 pthread_mutex_unlock(&shared_state_lock_); |
| 168 return read_bytes; |
| 84 } | 169 } |
| OLD | NEW |