summaryrefslogtreecommitdiffstats
path: root/thirdparty/libktx/lib/miniz_wrapper.cpp
blob: cbd7da540af3be6dfc92ddd3a72f0c2d65fe887e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/* -*- tab-width: 4; -*- */
/* vi: set sw=2 ts=4 expandtab: */

/*
 * Copyright 2023-2023 The Khronos Group Inc.
 * Copyright 2023-2023 RasterGrid Kft.
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @internal
 * @file miniz_wrapper.c
 * @~English
 *
 * @brief Wrapper functions for ZLIB compression/decompression using miniz.
 *
 * @author Daniel Rakos, RasterGrid
 */

#include "ktx.h"
#include "ktxint.h"

#include <assert.h>

#if !KTX_FEATURE_WRITE
// The reader does not link with the basisu components that already include a
// definition of miniz so we include it here explicitly.
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wextra"
#pragma GCC diagnostic ignored "-Wmisleading-indentation"
#endif
#include "encoder/basisu_miniz.h"
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#else
// Otherwise we only declare the interfaces and link with the basisu version.
// This is needed because while miniz is defined as a header in basisu it's
// not declaring the functions as static or inline, hence causing multiple
// conflicting definitions at link-time.
namespace buminiz {
    typedef unsigned long mz_ulong;
    enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 };
    mz_ulong mz_compressBound(mz_ulong source_len);
    int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level);
    int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
}
#endif

using namespace buminiz;

extern "C" {

/**
 * @internal
 * @~English
 * @brief Returns upper bound for compresses data using miniz (ZLIB).
 *
 * @param srcLength source data length
 *
 * @author Daniel Rakos, RasterGrid
 */
ktx_size_t ktxCompressZLIBBounds(ktx_size_t srcLength) {
    return mz_compressBound((mz_ulong)srcLength);
}

/**
 * @internal
 * @~English
 * @brief Compresses data using miniz (ZLIB)
 *
 * @param pDest         destination data buffer
 * @param pDestLength   destination data buffer size
 *                      (filled with written byte count on success)
 * @param pSrc          source data buffer
 * @param srcLength     source data size
 * @param level         compression level (between 1 and 9)
 *
 * @author Daniel Rakos, RasterGrid
 */
KTX_error_code ktxCompressZLIBInt(unsigned char* pDest,
                                  ktx_size_t* pDestLength,
                                  const unsigned char* pSrc,
                                  ktx_size_t srcLength,
                                  ktx_uint32_t level) {
    if ((srcLength | *pDestLength) > 0xFFFFFFFFU) return KTX_INVALID_VALUE;
    mz_ulong mzCompressedSize = (mz_ulong)*pDestLength;
    int status = mz_compress2(pDest, &mzCompressedSize, pSrc, (mz_ulong)srcLength, level);
    switch (status) {
    case MZ_OK:
        *pDestLength = mzCompressedSize;
        return KTX_SUCCESS;
    case MZ_PARAM_ERROR:
        return KTX_INVALID_VALUE;
    case MZ_BUF_ERROR:
#ifdef DEBUG
        assert(false && "Deflate dstSize too small.");
#endif
        return KTX_OUT_OF_MEMORY;
    case MZ_MEM_ERROR:
#ifdef DEBUG
        assert(false && "Deflate workspace too small.");
#endif
        return KTX_OUT_OF_MEMORY;
    default:
        // The remaining errors look like they should only
        // occur during decompression but just in case.
#ifdef DEBUG
        assert(true);
#endif
        return KTX_INVALID_OPERATION;
    }
}

/**
 * @internal
 * @~English
 * @brief Uncompresses data using miniz (ZLIB)
 *
 * @param pDest         destination data buffer
 * @param pDestLength   destination data buffer size
 *                      (filled with written byte count on success)
 * @param pSrc          source data buffer
 * @param srcLength     source data size
 *
 * @author Daniel Rakos, RasterGrid
 */
KTX_error_code ktxUncompressZLIBInt(unsigned char* pDest,
                                    ktx_size_t* pDestLength,
                                    const unsigned char* pSrc,
                                    ktx_size_t srcLength) {
    if ((srcLength | *pDestLength) > 0xFFFFFFFFU) return KTX_INVALID_VALUE;
    mz_ulong mzUncompressedSize = (mz_ulong)*pDestLength;
    int status = mz_uncompress(pDest, &mzUncompressedSize, pSrc, (mz_ulong)srcLength);
    switch (status) {
    case MZ_OK:
        *pDestLength = mzUncompressedSize;
        return KTX_SUCCESS;
    case MZ_BUF_ERROR:
        return KTX_DECOMPRESS_LENGTH_ERROR; // buffer too small
    case MZ_MEM_ERROR:
        return KTX_OUT_OF_MEMORY;
    default:
        return KTX_FILE_DATA_ERROR;
    }
}

}