| Index: ui/file_manager/zip_archiver/cpp/compressor_io_javascript_stream.cc | 
| diff --git a/ui/file_manager/zip_archiver/cpp/compressor_io_javascript_stream.cc b/ui/file_manager/zip_archiver/cpp/compressor_io_javascript_stream.cc | 
| index 5fdb081f15e4df94925111e85d987a8302f11d7c..92bba21f9eb16a4feadb4a7b75bfe06a2e517029 100644 | 
| --- a/ui/file_manager/zip_archiver/cpp/compressor_io_javascript_stream.cc | 
| +++ b/ui/file_manager/zip_archiver/cpp/compressor_io_javascript_stream.cc | 
| @@ -7,45 +7,129 @@ | 
| #include <limits> | 
| #include <thread> | 
|  | 
| -#include "archive.h" | 
| #include "ppapi/cpp/logging.h" | 
|  | 
| CompressorIOJavaScriptStream::CompressorIOJavaScriptStream( | 
| JavaScriptCompressorRequestorInterface* requestor) | 
| -    : requestor_(requestor) { | 
| -  pthread_mutex_init(&shared_state_lock_, NULL); | 
| -  pthread_cond_init(&available_data_cond_, NULL); | 
| -  pthread_cond_init(&data_written_cond_, NULL); | 
| +    : requestor_(requestor), buffer_offset_(-1), buffer_data_length_(0) { | 
| +  pthread_mutex_init(&shared_state_lock_, nullptr); | 
| +  pthread_cond_init(&available_data_cond_, nullptr); | 
| +  pthread_cond_init(&data_written_cond_, nullptr); | 
|  | 
| pthread_mutex_lock(&shared_state_lock_); | 
| available_data_ = false; | 
| +  buffer_ = new char[compressor_stream_constants::kMaximumDataChunkSize]; | 
| pthread_mutex_unlock(&shared_state_lock_); | 
| } | 
|  | 
| CompressorIOJavaScriptStream::~CompressorIOJavaScriptStream() { | 
| +  pthread_mutex_lock(&shared_state_lock_); | 
| +  delete buffer_; | 
| +  pthread_mutex_unlock(&shared_state_lock_); | 
| pthread_cond_destroy(&data_written_cond_); | 
| pthread_cond_destroy(&available_data_cond_); | 
| pthread_mutex_destroy(&shared_state_lock_); | 
| }; | 
|  | 
| -int64_t CompressorIOJavaScriptStream::Write(int64_t byte_to_write, | 
| -    const pp::VarArrayBuffer& buffer) { | 
| +int64_t CompressorIOJavaScriptStream::Flush() { | 
| pthread_mutex_lock(&shared_state_lock_); | 
| -  requestor_->WriteChunkRequest(byte_to_write, buffer); | 
| + | 
| +  if (buffer_data_length_ == 0) { | 
| +    pthread_mutex_unlock(&shared_state_lock_); | 
| +    return 0; | 
| +  } | 
| + | 
| +  // Copy the data in buffer_ to array_buffer. | 
| +  pp::VarArrayBuffer array_buffer(buffer_data_length_); | 
| +  char* array_buffer_data = static_cast<char*>(array_buffer.Map()); | 
| +  memcpy(array_buffer_data, buffer_, buffer_data_length_); | 
| +  array_buffer.Unmap(); | 
| + | 
| +  requestor_->WriteChunkRequest(buffer_offset_, | 
| +                                buffer_data_length_, | 
| +                                array_buffer); | 
|  | 
| pthread_cond_wait(&data_written_cond_, &shared_state_lock_); | 
|  | 
| int64_t written_bytes = written_bytes_; | 
| -  pthread_mutex_unlock(&shared_state_lock_); | 
| +  if (written_bytes < buffer_data_length_) { | 
| +    pthread_mutex_unlock(&shared_state_lock_); | 
| +    return -1 /* Error */; | 
| +  } | 
| + | 
| +  // Reset the offset and length to the default values. | 
| +  buffer_offset_ = -1; | 
| +  buffer_data_length_ = 0; | 
|  | 
| +  pthread_mutex_unlock(&shared_state_lock_); | 
| return written_bytes; | 
| } | 
|  | 
| -void CompressorIOJavaScriptStream::WriteChunkDone(int64_t written_bytes) { | 
| +int64_t CompressorIOJavaScriptStream::Write(int64_t zip_offset, | 
| +                                            int64_t zip_length, | 
| +                                            const char* zip_buffer) { | 
| +  pthread_mutex_lock(&shared_state_lock_); | 
| + | 
| +  // The offset from which the data should be written onto the archive. | 
| +  int64_t current_offset = zip_offset; | 
| +  int64_t left_length = zip_length; | 
| +  const char* buffer_pointer = zip_buffer; | 
| + | 
| +  do { | 
| +    // Flush the buffer if the data in the buffer cannot be reused. | 
| +    // The following is the brief explanation about the conditions of the | 
| +    // following if statement. | 
| +    // 1: The buffer is not in the initial state (empty). | 
| +    //    The buffer should have some data to flush. | 
| +    // 2: This write operation is not to append the data to the buffer. | 
| +    // 3: The buffer overflows if we append the data to the buffer. | 
| +    //    If we can append the new data to the current data in the buffer, | 
| +    //    we should not flush the buffer. | 
| +    // 4: The index to write is outside the buffer. | 
| +    //    If we want to write data outside the range, we first need to flush | 
| +    //    the buffer, and then cache the data in the buffer. | 
| +    if (buffer_offset_ >= 0 && /* 1 */ | 
| +        (current_offset != buffer_offset_ + buffer_data_length_ || /* 2 */ | 
| +         buffer_data_length_ + left_length > | 
| +             compressor_stream_constants::kMaximumDataChunkSize) && /* 3 */ | 
| +        (current_offset < buffer_offset_ || | 
| +         buffer_offset_ + buffer_data_length_ < | 
| +         current_offset + left_length) /* 4 */ ) { | 
| +      pthread_mutex_unlock(&shared_state_lock_); | 
| +      int64_t bytes_to_write = buffer_data_length_; | 
| +      if (Flush() != bytes_to_write) | 
| +        return -1; | 
| +      pthread_mutex_lock(&shared_state_lock_); | 
| +    } | 
| + | 
| +    // How many bytes we should copy to buffer_ in this iteration. | 
| +    int64_t copy_length = std::min( | 
| +        left_length, compressor_stream_constants::kMaximumDataChunkSize); | 
| +    // Set up the buffer_offset_ if the buffer_ has no data. | 
| +    if (buffer_offset_ == -1 /* initial state */) | 
| +      buffer_offset_ = current_offset; | 
| +    // Calculate the relative offset from left_length. | 
| +    int64_t offset_in_buffer = current_offset - buffer_offset_; | 
| +    // Copy data from zip_buffer, which is pointed by buffer_pointer, to buffer_. | 
| +    memcpy(buffer_ + offset_in_buffer, buffer_pointer, copy_length); | 
| + | 
| +    buffer_pointer += copy_length; | 
| +    buffer_data_length_ = std::max( | 
| +        buffer_data_length_, offset_in_buffer + copy_length); | 
| +    current_offset += copy_length; | 
| +    left_length -= copy_length; | 
| +  } while (left_length > 0); | 
| + | 
| +  pthread_mutex_unlock(&shared_state_lock_); | 
| +  return zip_length; | 
| +} | 
| + | 
| +int64_t CompressorIOJavaScriptStream::WriteChunkDone(int64_t written_bytes) { | 
| pthread_mutex_lock(&shared_state_lock_); | 
| written_bytes_ = written_bytes; | 
| pthread_cond_signal(&data_written_cond_); | 
| pthread_mutex_unlock(&shared_state_lock_); | 
| +  return written_bytes; | 
| } | 
|  | 
| int64_t CompressorIOJavaScriptStream::Read(int64_t bytes_to_read, | 
| @@ -65,7 +149,7 @@ int64_t CompressorIOJavaScriptStream::Read(int64_t bytes_to_read, | 
| return read_bytes; | 
| } | 
|  | 
| -void CompressorIOJavaScriptStream::ReadFileChunkDone(int64_t read_bytes, | 
| +int64_t CompressorIOJavaScriptStream::ReadFileChunkDone(int64_t read_bytes, | 
| pp::VarArrayBuffer* array_buffer) { | 
| pthread_mutex_lock(&shared_state_lock_); | 
|  | 
| @@ -81,4 +165,5 @@ void CompressorIOJavaScriptStream::ReadFileChunkDone(int64_t read_bytes, | 
| available_data_ = true; | 
| pthread_cond_signal(&available_data_cond_); | 
| pthread_mutex_unlock(&shared_state_lock_); | 
| +  return read_bytes; | 
| } | 
|  |