15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "third_party/zlib/google/zip_internal.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <algorithm>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
91320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/files/file_util.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
12010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "base/time/time.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(USE_SYSTEM_MINIZIP)
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <minizip/ioapi.h>
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <minizip/unzip.h>
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <minizip/zip.h>
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/zlib/contrib/minizip/unzip.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/zlib/contrib/minizip/zip.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/zlib/contrib/minizip/iowin32.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#elif defined(OS_POSIX)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/zlib/contrib/minizip/ioapi.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(OS_POSIX)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(USE_SYSTEM_MINIZIP)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)typedef struct {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE hf;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int error;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} WIN32FILE_IOWIN;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This function is derived from third_party/minizip/iowin32.c.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Its only difference is that it treats the char* as UTF8 and
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// uses the Unicode version of CreateFile.
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* ZipOpenFunc(void *opaque, const char* filename, int mode) {
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DWORD desired_access = 0, creation_disposition = 0;
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DWORD share_mode = 0, flags_and_attributes = 0;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HANDLE file = 0;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void* ret = NULL;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    desired_access = GENERIC_READ;
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    creation_disposition = OPEN_EXISTING;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    share_mode = FILE_SHARE_READ;
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (mode & ZLIB_FILEFUNC_MODE_EXISTING) {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    desired_access = GENERIC_WRITE | GENERIC_READ;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    creation_disposition = OPEN_EXISTING;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    desired_access = GENERIC_WRITE | GENERIC_READ;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    creation_disposition = CREATE_ALWAYS;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::string16 filename16 = base::UTF8ToUTF16(filename);
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((filename != NULL) && (desired_access != 0)) {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file = CreateFile(filename16.c_str(), desired_access, share_mode,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        NULL, creation_disposition, flags_and_attributes, NULL);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file == INVALID_HANDLE_VALUE)
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file = NULL;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (file != NULL) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    WIN32FILE_IOWIN file_ret;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_ret.hf = file;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file_ret.error = 0;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ret = malloc(sizeof(WIN32FILE_IOWIN));
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ret == NULL)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      CloseHandle(file);
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    else
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return ret;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Callback function for zlib that opens a file stream from a file descriptor.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* FdOpenFileFunc(void* opaque, const char* filename, int mode) {
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FILE* file = NULL;
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* mode_fopen = NULL;
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mode_fopen = "rb";
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mode_fopen = "r+b";
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    mode_fopen = "wb";
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((filename != NULL) && (mode_fopen != NULL))
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    file = fdopen(*static_cast<int*>(opaque), mode_fopen);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return file;
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We don't actually close the file stream since that would close
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// the underlying file descriptor, and we don't own it. However we do need to
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// flush buffers and free |opaque| since we malloc'ed it in FillFdOpenFileFunc.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CloseFileFunc(void* opaque, void* stream) {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fflush(static_cast<FILE*>(stream));
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  free(opaque);
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Fills |pzlib_filecunc_def| appropriately to handle the zip file
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// referred to by |fd|.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void FillFdOpenFileFunc(zlib_filefunc_def* pzlib_filefunc_def, int fd) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fill_fopen_filefunc(pzlib_filefunc_def);
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pzlib_filefunc_def->zopen_file = FdOpenFileFunc;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pzlib_filefunc_def->zclose_file = CloseFileFunc;
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int* ptr_fd = static_cast<int*>(malloc(sizeof(fd)));
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  *ptr_fd = fd;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  pzlib_filefunc_def->opaque = ptr_fd;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(OS_POSIX)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Callback function for zlib that opens a file stream from a Windows handle.
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void* HandleOpenFileFunc(void* opaque, const char* filename, int mode) {
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  WIN32FILE_IOWIN file_ret;
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  file_ret.hf = static_cast<HANDLE>(opaque);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  file_ret.error = 0;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (file_ret.hf == INVALID_HANDLE_VALUE)
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void* ret = malloc(sizeof(WIN32FILE_IOWIN));
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (ret != NULL)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *(static_cast<WIN32FILE_IOWIN*>(ret)) = file_ret;
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ret;
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A struct that contains data required for zlib functions to extract files from
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// a zip archive stored in memory directly. The following I/O API functions
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// expect their opaque parameters refer to this struct.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ZipBuffer {
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const char* data;  // weak
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t length;
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t offset;
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Opens the specified file. When this function returns a non-NULL pointer, zlib
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// uses this pointer as a stream parameter while compressing or uncompressing
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// data. (Returning NULL represents an error.) This function initializes the
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// given opaque parameter and returns it because this parameter stores all
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// information needed for uncompressing data. (This function does not support
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// writing compressed data and it returns NULL for this case.)
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void* OpenZipBuffer(void* opaque, const char* /*filename*/, int mode) {
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) != ZLIB_FILEFUNC_MODE_READ) {
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!buffer || !buffer->data || !buffer->length)
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffer->offset = 0;
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return opaque;
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Reads compressed data from the specified stream. This function copies data
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// refered by the opaque parameter and returns the size actually copied.
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uLong ReadZipBuffer(void* opaque, void* /*stream*/, void* buf, uLong size) {
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK_LE(buffer->offset, buffer->length);
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size_t remaining_bytes = buffer->length - buffer->offset;
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!buffer || !buffer->data || !remaining_bytes)
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  size = std::min(size, static_cast<uLong>(remaining_bytes));
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  memcpy(buf, &buffer->data[buffer->offset], size);
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffer->offset += size;
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return size;
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Writes compressed data to the stream. This function always returns zero
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// because this implementation is only for reading compressed data.
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)uLong WriteZipBuffer(void* /*opaque*/,
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     void* /*stream*/,
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     const void* /*buf*/,
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     uLong /*size*/) {
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the offset from the beginning of the data.
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)long GetOffsetOfZipBuffer(void* opaque, void* /*stream*/) {
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!buffer)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<long>(buffer->offset);
1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Moves the current offset to the specified position.
1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)long SeekZipBuffer(void* opaque, void* /*stream*/, uLong offset, int origin) {
1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ZipBuffer* buffer = static_cast<ZipBuffer*>(opaque);
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!buffer)
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return -1;
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (origin == ZLIB_FILEFUNC_SEEK_CUR) {
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buffer->offset = std::min(buffer->offset + static_cast<size_t>(offset),
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              buffer->length);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (origin == ZLIB_FILEFUNC_SEEK_END) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buffer->offset = (buffer->length > offset) ? buffer->length - offset : 0;
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (origin == ZLIB_FILEFUNC_SEEK_SET) {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    buffer->offset = std::min(buffer->length, static_cast<size_t>(offset));
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NOTREACHED();
2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return -1;
2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Closes the input offset and deletes all resources used for compressing or
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// uncompressing data. This function deletes the ZipBuffer object referred by
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// the opaque parameter since zlib deletes the unzFile object and it does not
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// use this object any longer.
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int CloseZipBuffer(void* opaque, void* /*stream*/) {
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (opaque)
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    free(opaque);
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns the last error happened when reading or writing data. This function
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// always returns zero, which means there are not any errors.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int GetErrorOfZipBuffer(void* /*opaque*/, void* /*stream*/) {
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return 0;
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
233010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Returns a zip_fileinfo struct with the time represented by |file_time|.
234010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)zip_fileinfo TimeToZipFileInfo(const base::Time& file_time) {
235010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::Time::Exploded file_time_parts;
236010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  file_time.LocalExplode(&file_time_parts);
237010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
238010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  zip_fileinfo zip_info = {};
239010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (file_time_parts.year >= 1980) {
240010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // This if check works around the handling of the year value in
241010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // contrib/minizip/zip.c in function zip64local_TmzDateToDosDate
242010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // It assumes that dates below 1980 are in the double digit format.
243010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // Hence the fail safe option is to leave the date unset. Some programs
244010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    // might show the unset date as 1980-0-0 which is invalid.
245010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    zip_info.tmz_date.tm_year = file_time_parts.year;
246010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    zip_info.tmz_date.tm_mon = file_time_parts.month - 1;
247010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    zip_info.tmz_date.tm_mday = file_time_parts.day_of_month;
248010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    zip_info.tmz_date.tm_hour = file_time_parts.hour;
249010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    zip_info.tmz_date.tm_min = file_time_parts.minute;
250010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    zip_info.tmz_date.tm_sec = file_time_parts.second;
251010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
252010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
253010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return zip_info;
254010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace zip {
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unzFile OpenForUnzipping(const std::string& file_name_utf8) {
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zlib_filefunc_def* zip_func_ptrs = NULL;
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zlib_filefunc_def zip_funcs;
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fill_win32_filefunc(&zip_funcs);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zip_funcs.zopen_file = ZipOpenFunc;
2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zip_func_ptrs = &zip_funcs;
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return unzOpen2(file_name_utf8.c_str(), zip_func_ptrs);
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX)
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)unzFile OpenFdForUnzipping(int zip_fd) {
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zlib_filefunc_def zip_funcs;
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FillFdOpenFileFunc(&zip_funcs, zip_fd);
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Passing dummy "fd" filename to zlib.
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return unzOpen2("fd", &zip_funcs);
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_WIN)
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)unzFile OpenHandleForUnzipping(HANDLE zip_handle) {
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  zlib_filefunc_def zip_funcs;
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  fill_win32_filefunc(&zip_funcs);
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  zip_funcs.zopen_file = HandleOpenFileFunc;
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  zip_funcs.opaque = zip_handle;
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return unzOpen2("fd", &zip_funcs);
2872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
2892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
291010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)unzFile PrepareMemoryForUnzipping(const std::string& data) {
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (data.empty())
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ZipBuffer* buffer = static_cast<ZipBuffer*>(malloc(sizeof(ZipBuffer)));
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!buffer)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffer->data = data.data();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffer->length = data.length();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  buffer->offset = 0;
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zlib_filefunc_def zip_functions;
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zip_functions.zopen_file = OpenZipBuffer;
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zip_functions.zread_file = ReadZipBuffer;
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zip_functions.zwrite_file = WriteZipBuffer;
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zip_functions.ztell_file = GetOffsetOfZipBuffer;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zip_functions.zseek_file = SeekZipBuffer;
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zip_functions.zclose_file = CloseZipBuffer;
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zip_functions.zerror_file = GetErrorOfZipBuffer;
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zip_functions.opaque = static_cast<void*>(buffer);
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return unzOpen2(NULL, &zip_functions);
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)zipFile OpenForZipping(const std::string& file_name_utf8, int append_flag) {
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zlib_filefunc_def* zip_func_ptrs = NULL;
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zlib_filefunc_def zip_funcs;
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  fill_win32_filefunc(&zip_funcs);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zip_funcs.zopen_file = ZipOpenFunc;
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  zip_func_ptrs = &zip_funcs;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return zipOpen2(file_name_utf8.c_str(),
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  append_flag,
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  NULL,  // global comment
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                  zip_func_ptrs);
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_POSIX)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)zipFile OpenFdForZipping(int zip_fd, int append_flag) {
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  zlib_filefunc_def zip_funcs;
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FillFdOpenFileFunc(&zip_funcs, zip_fd);
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Passing dummy "fd" filename to zlib.
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return zipOpen2("fd", append_flag, NULL, &zip_funcs);
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
337010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)zip_fileinfo GetFileInfoForZipping(const base::FilePath& path) {
338010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::Time file_time;
339010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  base::File::Info file_info;
340010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (base::GetFileInfo(path, &file_info))
341010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    file_time = file_info.last_modified;
342010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return TimeToZipFileInfo(file_time);
343010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
344010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
345010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)bool ZipOpenNewFileInZip(zipFile zip_file,
346010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                         const std::string& str_path,
347010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                         const zip_fileinfo* file_info) {
348010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Section 4.4.4 http://www.pkware.com/documents/casestudies/APPNOTE.TXT
349010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  // Setting the Language encoding flag so the file is told to be in utf-8.
350010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  const uLong LANGUAGE_ENCODING_FLAG = 0x1 << 11;
351010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
352010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  if (ZIP_OK != zipOpenNewFileInZip4(
353010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    zip_file,  // file
354010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    str_path.c_str(),  // filename
355010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    file_info,  // zipfi
356010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    NULL,  // extrafield_local,
357010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    0u,  // size_extrafield_local
358010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    NULL,  // extrafield_global
359010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    0u,  // size_extrafield_global
360010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    NULL,  // comment
361010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    Z_DEFLATED,  // method
362010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    Z_DEFAULT_COMPRESSION,  // level
363010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    0,  // raw
364010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    -MAX_WBITS,  // windowBits
365010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    DEF_MEM_LEVEL,  // memLevel
366010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    Z_DEFAULT_STRATEGY,  // strategy
367010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    NULL,  // password
368010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    0,  // crcForCrypting
369010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    0,  // versionMadeBy
370010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                    LANGUAGE_ENCODING_FLAG)) {  // flagBase
371010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    DLOG(ERROR) << "Could not open zip file entry " << str_path;
372010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    return false;
373010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  }
374010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  return true;
375010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)}
376010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace internal
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace zip
379