CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!
Path: blob/master/Common/Data/Format/ZIMLoad.cpp
Views: 1401
#include <cstring>1#include <cstdio>2#include <cstdlib>3#include <zstd.h>45#include "zlib.h"67#include "Common/Log.h"8#include "Common/Data/Format/ZIMLoad.h"9#include "Common/Math/math_util.h"10#include "Common/File/VFS/VFS.h"1112int ezuncompress(unsigned char* pDest, long* pnDestLen, const unsigned char* pSrc, long nSrcLen) {13z_stream stream;14stream.next_in = (Bytef*)pSrc;15stream.avail_in = (uInt)nSrcLen;16/* Check for source > 64K on 16-bit machine: */17if ((uLong)stream.avail_in != (uLong)nSrcLen) return Z_BUF_ERROR;1819uInt destlen = (uInt)*pnDestLen;20if ((uLong)destlen != (uLong)*pnDestLen) return Z_BUF_ERROR;21stream.zalloc = (alloc_func)0;22stream.zfree = (free_func)0;2324int err = inflateInit(&stream);25if (err != Z_OK) return err;2627int nExtraChunks = 0;28do {29stream.next_out = pDest;30stream.avail_out = destlen;31err = inflate(&stream, Z_FINISH);32if (err == Z_STREAM_END )33break;34if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))35err = Z_DATA_ERROR;36if (err != Z_BUF_ERROR) {37inflateEnd(&stream);38return err;39}40nExtraChunks += 1;41} while (stream.avail_out == 0);4243*pnDestLen = stream.total_out;4445err = inflateEnd(&stream);46if (err != Z_OK) return err;4748return nExtraChunks ? Z_BUF_ERROR : Z_OK;49}5051int LoadZIMPtr(const uint8_t *zim, size_t datasize, int *width, int *height, int *flags, uint8_t **image) {52if (zim[0] != 'Z' || zim[1] != 'I' || zim[2] != 'M' || zim[3] != 'G') {53ERROR_LOG(Log::IO, "Not a ZIM file");54return 0;55}56memcpy(width, zim + 4, 4);57memcpy(height, zim + 8, 4);58memcpy(flags, zim + 12, 4);5960int num_levels = 1;61int image_data_size[ZIM_MAX_MIP_LEVELS];62if (*flags & ZIM_HAS_MIPS) {63num_levels = log2i(*width < *height ? *width : *height) + 1;64}65int total_data_size = 0;66for (int i = 0; i < num_levels; i++) {67if (i > 0) {68width[i] = width[i-1] / 2;69height[i] = height[i-1] / 2;70}71switch (*flags & ZIM_FORMAT_MASK) {72case ZIM_RGBA8888:73image_data_size[i] = width[i] * height[i] * 4;74break;75case ZIM_RGBA4444:76case ZIM_RGB565:77image_data_size[i] = width[i] * height[i] * 2;78break;79default:80ERROR_LOG(Log::IO, "Invalid ZIM format %i", *flags & ZIM_FORMAT_MASK);81return 0;82}83total_data_size += image_data_size[i];84}8586if (total_data_size == 0) {87ERROR_LOG(Log::IO, "Invalid ZIM data size 0");88return 0;89}9091image[0] = (uint8_t *)malloc(total_data_size);92for (int i = 1; i < num_levels; i++) {93image[i] = image[i-1] + image_data_size[i-1];94}9596if (*flags & ZIM_ZLIB_COMPRESSED) {97long outlen = (long)total_data_size;98int retcode = ezuncompress(*image, &outlen, (unsigned char *)(zim + 16), (long)datasize - 16);99if (Z_OK != retcode) {100ERROR_LOG(Log::IO, "ZIM zlib format decompression failed: %d", retcode);101free(*image);102*image = 0;103return 0;104}105if (outlen != total_data_size) {106// Shouldn't happen if return value was Z_OK.107ERROR_LOG(Log::IO, "Wrong size data in ZIM: %i vs %i", (int)outlen, (int)total_data_size);108}109} else if (*flags & ZIM_ZSTD_COMPRESSED) {110size_t outlen = ZSTD_decompress(*image, total_data_size, zim + 16, datasize - 16);111if (outlen != (size_t)total_data_size) {112ERROR_LOG(Log::IO, "ZIM zstd format decompression failed: %lld", (long long)outlen);113free(*image);114*image = 0;115return 0;116}117} else {118memcpy(*image, zim + 16, datasize - 16);119if (datasize - 16 != (size_t)total_data_size) {120ERROR_LOG(Log::IO, "Wrong size data in ZIM: %i vs %i", (int)(datasize-16), (int)total_data_size);121}122}123return num_levels;124}125126int LoadZIM(const char *filename, int *width, int *height, int *format, uint8_t **image) {127size_t size;128uint8_t *buffer = g_VFS.ReadFile(filename, &size);129if (!buffer) {130ERROR_LOG(Log::IO, "Couldn't read data for '%s'", filename);131return 0;132}133134int retval = LoadZIMPtr(buffer, size, width, height, format, image);135if (!retval) {136ERROR_LOG(Log::IO, "Not a valid ZIM file: %s (size: %lld bytes)", filename, (long long)size);137}138delete [] buffer;139return retval;140}141142143