示例#1
0
bool FileUtils::mzCopyFileRaw(unzFile uf,
                              zipFile zf,
                              const std::string &name,
                              void (*cb)(uint64_t bytes, void *), void *userData)
{
    unz_file_info64 ufi;

    if (!mzGetInfo(uf, &ufi, nullptr)) {
        return false;
    }

    bool zip64 = ufi.uncompressed_size >= ((1ull << 32) - 1);

    zip_fileinfo zfi;
    memset(&zfi, 0, sizeof(zfi));

    zfi.dosDate = ufi.dosDate;
    zfi.tmz_date.tm_sec = ufi.tmu_date.tm_sec;
    zfi.tmz_date.tm_min = ufi.tmu_date.tm_min;
    zfi.tmz_date.tm_hour = ufi.tmu_date.tm_hour;
    zfi.tmz_date.tm_mday = ufi.tmu_date.tm_mday;
    zfi.tmz_date.tm_mon = ufi.tmu_date.tm_mon;
    zfi.tmz_date.tm_year = ufi.tmu_date.tm_year;
    zfi.internal_fa = ufi.internal_fa;
    zfi.external_fa = ufi.external_fa;

    int method;
    int level;

    // Open raw file in input zip
    int ret = unzOpenCurrentFile2(
        uf,                     // file
        &method,                // method
        &level,                 // level
        1                       // raw
    );
    if (ret != UNZ_OK) {
        return false;
    }

    // Open raw file in output zip
    ret = zipOpenNewFileInZip2_64(
        zf,             // file
        name.c_str(),   // filename
        &zfi,           // zip_fileinfo
        nullptr,        // extrafield_local
        0,              // size_extrafield_local
        nullptr,        // extrafield_global
        0,              // size_extrafield_global
        nullptr,        // comment
        method,         // method
        level,          // level
        1,              // raw
        zip64           // zip64
    );
    if (ret != ZIP_OK) {
        unzCloseCurrentFile(uf);
        return false;
    }

    uint64_t bytes = 0;

    // Exceeds Android's default stack size, unfortunately, so allocate
    // on the heap
    std::vector<unsigned char> buf(1024 * 1024); // 1MiB
    int bytes_read;
    double ratio;

    while ((bytes_read = unzReadCurrentFile(uf, buf.data(), buf.size())) > 0) {
        bytes += bytes_read;
        if (cb) {
            // Scale this to the uncompressed size for the purposes of a
            // progress bar
            ratio = (double) bytes / ufi.compressed_size;
            cb(ratio * ufi.uncompressed_size, userData);
        }

        ret = zipWriteInFileInZip(zf, buf.data(), bytes_read);
        if (ret != ZIP_OK) {
            unzCloseCurrentFile(uf);
            zipCloseFileInZip(zf);
            return false;
        }
    }

    unzCloseCurrentFile(uf);
    zipCloseFileInZipRaw64(zf, ufi.uncompressed_size, ufi.crc);

    return bytes_read == 0;
}
示例#2
0
bool MinizipUtils::copy_file_raw(unzFile uf,
                                 zipFile zf,
                                 const std::string &name,
                                 void (*cb)(uint64_t bytes, void *),
                                 void *userData)
{
    unz_file_info64 ufi;

    if (!get_info(uf, &ufi, nullptr)) {
        return false;
    }

    bool zip64 = ufi.uncompressed_size >= ((1ull << 32) - 1);

    zip_fileinfo zfi;
    memset(&zfi, 0, sizeof(zfi));

    zfi.dos_date = ufi.dos_date;
    zfi.internal_fa = ufi.internal_fa;
    zfi.external_fa = ufi.external_fa;

    int method;
    int level;

    // Open raw file in input zip
    int ret = unzOpenCurrentFile2(
        uf,                     // file
        &method,                // method
        &level,                 // level
        1                       // raw
    );
    if (ret != UNZ_OK) {
        LOGE("miniunz: Failed to open inner file: %s",
             unz_error_string(ret).c_str());
        return false;
    }

    // Open raw file in output zip
    ret = zipOpenNewFileInZip2_64(
        zf,                             // file
        name.c_str(),                   // filename
        &zfi,                           // zip_fileinfo
        nullptr,                        // extrafield_local
        0,                              // size_extrafield_local
        nullptr,                        // extrafield_global
        0,                              // size_extrafield_global
        nullptr,                        // comment
        static_cast<uint16_t>(method),  // method
        level,                          // level
        1,                              // raw
        zip64                           // zip64
    );
    if (ret != ZIP_OK) {
        LOGE("minizip: Failed to open inner file: %s",
             zip_error_string(ret).c_str());
        unzCloseCurrentFile(uf);
        return false;
    }

    uint64_t bytes = 0;

    // minizip no longer supports buffers larger than UINT16_MAX
    char buf[UINT16_MAX];
    int bytes_read;
    double ratio;

    while ((bytes_read = unzReadCurrentFile(uf, buf, sizeof(buf))) > 0) {
        bytes += static_cast<uint64_t>(bytes_read);
        if (cb) {
            // Scale this to the uncompressed size for the purposes of a
            // progress bar
            ratio = static_cast<double>(bytes)
                    / static_cast<double>(ufi.compressed_size);
            cb(static_cast<uint64_t>(
                    ratio * static_cast<double>(ufi.uncompressed_size)),
               userData);
        }

        ret = zipWriteInFileInZip(zf, buf, static_cast<uint32_t>(bytes_read));
        if (ret != ZIP_OK) {
            LOGE("minizip: Failed to write data to inner file: %s",
                 zip_error_string(ret).c_str());
            unzCloseCurrentFile(uf);
            zipCloseFileInZip(zf);
            return false;
        }
    }
    if (bytes_read != 0) {
        LOGE("miniunz: Finished before reaching inner file's EOF: %s",
             unz_error_string(bytes_read).c_str());
    }

    bool close_success = true;

    ret = unzCloseCurrentFile(uf);
    if (ret != UNZ_OK) {
        LOGE("miniunz: Failed to close inner file: %s",
             unz_error_string(ret).c_str());
        close_success = false;
    }
    ret = zipCloseFileInZipRaw64(zf, ufi.uncompressed_size, ufi.crc);
    if (ret != ZIP_OK) {
        LOGE("minizip: Failed to close inner file: %s",
             zip_error_string(ret).c_str());
        close_success = false;
    }

    return bytes_read == 0 && close_success;
}