Ziparchive: Enable -Wconversion

Enable -Wconversion (but not -Wsign-conversion). Fix up code. Handle
some actual error cases:

* too many files
* files too large

Bug: 130039052
Test: atest ziparchive-tests
Change-Id: I632af317b9e65dbc728851efefd0d11a2b5c29b9
diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc
index 0df0fa5..ae9d145 100644
--- a/libziparchive/zip_writer.cc
+++ b/libziparchive/zip_writer.cc
@@ -169,8 +169,8 @@
     year = 80;
   }
 
-  *out_date = (year - 80) << 9 | (ptm->tm_mon + 1) << 5 | ptm->tm_mday;
-  *out_time = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
+  *out_date = static_cast<uint16_t>((year - 80) << 9 | (ptm->tm_mon + 1) << 5 | ptm->tm_mday);
+  *out_time = static_cast<uint16_t>(ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1);
 }
 
 static void CopyFromFileEntry(const ZipWriter::FileEntry& src, bool use_data_descriptor,
@@ -193,7 +193,8 @@
   dst->compression_method = src.compression_method;
   dst->last_mod_time = src.last_mod_time;
   dst->last_mod_date = src.last_mod_date;
-  dst->file_name_length = src.path.size();
+  DCHECK_LE(src.path.size(), std::numeric_limits<uint16_t>::max());
+  dst->file_name_length = static_cast<uint16_t>(src.path.size());
   dst->extra_field_length = src.padding_length;
 }
 
@@ -203,6 +204,11 @@
     return kInvalidState;
   }
 
+  // Can only have 16535 entries because of zip records.
+  if (files_.size() == std::numeric_limits<uint16_t>::max()) {
+    return HandleError(kIoError);
+  }
+
   if (flags & kAlign32) {
     return kInvalidAlign32Flag;
   }
@@ -210,10 +216,17 @@
   if (powerof2(alignment) == 0) {
     return kInvalidAlignment;
   }
+  if (alignment > std::numeric_limits<uint16_t>::max()) {
+    return kInvalidAlignment;
+  }
 
   FileEntry file_entry = {};
   file_entry.local_file_header_offset = current_offset_;
   file_entry.path = path;
+  // No support for larger than 4GB files.
+  if (file_entry.local_file_header_offset > std::numeric_limits<uint32_t>::max()) {
+    return HandleError(kIoError);
+  }
 
   if (!IsValidEntryName(reinterpret_cast<const uint8_t*>(file_entry.path.data()),
                         file_entry.path.size())) {
@@ -237,7 +250,7 @@
   std::vector<char> zero_padding;
   if (alignment != 0 && (offset & (alignment - 1))) {
     // Pad the extra field so the data will be aligned.
-    uint16_t padding = alignment - (offset % alignment);
+    uint16_t padding = static_cast<uint16_t>(alignment - (offset % alignment));
     file_entry.padding_length = padding;
     offset += padding;
     zero_padding.resize(padding, 0);
@@ -314,7 +327,8 @@
   }
 
   z_stream_->next_out = buffer_.data();
-  z_stream_->avail_out = buffer_.size();
+  DCHECK_EQ(buffer_.size(), kBufSize);
+  z_stream_->avail_out = static_cast<uint32_t>(buffer_.size());
   return kNoError;
 }
 
@@ -322,25 +336,31 @@
   if (state_ != State::kWritingEntry) {
     return HandleError(kInvalidState);
   }
+  // Need to be able to mark down data correctly.
+  if (len + static_cast<uint64_t>(current_file_entry_.uncompressed_size) >
+      std::numeric_limits<uint32_t>::max()) {
+    return HandleError(kIoError);
+  }
+  uint32_t len32 = static_cast<uint32_t>(len);
 
   int32_t result = kNoError;
   if (current_file_entry_.compression_method & kCompressDeflated) {
-    result = CompressBytes(&current_file_entry_, data, len);
+    result = CompressBytes(&current_file_entry_, data, len32);
   } else {
-    result = StoreBytes(&current_file_entry_, data, len);
+    result = StoreBytes(&current_file_entry_, data, len32);
   }
 
   if (result != kNoError) {
     return result;
   }
 
-  current_file_entry_.crc32 =
-      crc32(current_file_entry_.crc32, reinterpret_cast<const Bytef*>(data), len);
-  current_file_entry_.uncompressed_size += len;
+  current_file_entry_.crc32 = static_cast<uint32_t>(
+      crc32(current_file_entry_.crc32, reinterpret_cast<const Bytef*>(data), len32));
+  current_file_entry_.uncompressed_size += len32;
   return kNoError;
 }
 
-int32_t ZipWriter::StoreBytes(FileEntry* file, const void* data, size_t len) {
+int32_t ZipWriter::StoreBytes(FileEntry* file, const void* data, uint32_t len) {
   CHECK(state_ == State::kWritingEntry);
 
   if (fwrite(data, 1, len, file_) != len) {
@@ -351,7 +371,7 @@
   return kNoError;
 }
 
-int32_t ZipWriter::CompressBytes(FileEntry* file, const void* data, size_t len) {
+int32_t ZipWriter::CompressBytes(FileEntry* file, const void* data, uint32_t len) {
   CHECK(state_ == State::kWritingEntry);
   CHECK(z_stream_);
   CHECK(z_stream_->next_out != nullptr);
@@ -379,7 +399,8 @@
 
       // Reset the output buffer for the next input.
       z_stream_->next_out = buffer_.data();
-      z_stream_->avail_out = buffer_.size();
+      DCHECK_EQ(buffer_.size(), kBufSize);
+      z_stream_->avail_out = static_cast<uint32_t>(buffer_.size());
     }
   }
   return kNoError;
@@ -404,7 +425,8 @@
     current_offset_ += write_bytes;
 
     z_stream_->next_out = buffer_.data();
-    z_stream_->avail_out = buffer_.size();
+    DCHECK_EQ(buffer_.size(), kBufSize);
+    z_stream_->avail_out = static_cast<uint32_t>(buffer_.size());
   }
   if (zerr != Z_STREAM_END) {
     return HandleError(kZlibError);
@@ -491,7 +513,11 @@
     cdr.crc32 = file.crc32;
     cdr.compressed_size = file.compressed_size;
     cdr.uncompressed_size = file.uncompressed_size;
-    cdr.file_name_length = file.path.size();
+    // Checked in IsValidEntryName.
+    DCHECK_LE(file.path.size(), std::numeric_limits<uint16_t>::max());
+    cdr.file_name_length = static_cast<uint16_t>(file.path.size());
+    // Checked in StartAlignedEntryWithTime.
+    DCHECK_LE(file.local_file_header_offset, std::numeric_limits<uint32_t>::max());
     cdr.local_file_header_offset = static_cast<uint32_t>(file.local_file_header_offset);
     if (fwrite(&cdr, sizeof(cdr), 1, file_) != 1) {
       return HandleError(kIoError);
@@ -508,10 +534,15 @@
   er.eocd_signature = EocdRecord::kSignature;
   er.disk_num = 0;
   er.cd_start_disk = 0;
-  er.num_records_on_disk = files_.size();
-  er.num_records = files_.size();
-  er.cd_size = current_offset_ - startOfCdr;
-  er.cd_start_offset = startOfCdr;
+  // Checked when adding entries.
+  DCHECK_LE(files_.size(), std::numeric_limits<uint16_t>::max());
+  er.num_records_on_disk = static_cast<uint16_t>(files_.size());
+  er.num_records = static_cast<uint16_t>(files_.size());
+  if (current_offset_ > std::numeric_limits<uint32_t>::max()) {
+    return HandleError(kIoError);
+  }
+  er.cd_size = static_cast<uint32_t>(current_offset_ - startOfCdr);
+  er.cd_start_offset = static_cast<uint32_t>(startOfCdr);
 
   if (fwrite(&er, sizeof(er), 1, file_) != 1) {
     return HandleError(kIoError);