Coverage Report

Created: 2025-07-18 07:04

/src/ogre/OgreMain/include/OgreDeflate.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 -----------------------------------------------------------------------------
3
 This source file is part of OGRE
4
 (Object-oriented Graphics Rendering Engine)
5
 For the latest info, see http://www.ogre3d.org/
6
 
7
 Copyright (c) 2000-2014 Torus Knot Software Ltd
8
 
9
 Permission is hereby granted, free of charge, to any person obtaining a copy
10
 of this software and associated documentation files (the "Software"), to deal
11
 in the Software without restriction, including without limitation the rights
12
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
 copies of the Software, and to permit persons to whom the Software is
14
 furnished to do so, subject to the following conditions:
15
 
16
 The above copyright notice and this permission notice shall be included in
17
 all copies or substantial portions of the Software.
18
 
19
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
 THE SOFTWARE.
26
 -----------------------------------------------------------------------------
27
 */
28
#ifndef __OGRE_DEFLATE_H__
29
#define __OGRE_DEFLATE_H__
30
31
#if OGRE_NO_ZIP_ARCHIVE == 0
32
33
#include "OgrePrerequisites.h"
34
#include "OgreDataStream.h"
35
#include "OgreHeaderPrefix.h"
36
37
/// forward decls
38
struct mz_stream_s;
39
typedef struct mz_stream_s z_stream;
40
41
namespace Ogre
42
{
43
    /** Template version of cache based on static array.
44
     'cacheSize' defines size of cache in bytes. */
45
    template <size_t cacheSize>
46
    class StaticCache
47
    {
48
    private:
49
        /// Static buffer
50
        char mBuffer[cacheSize];
51
52
        /// Number of bytes valid in cache (written from the beginning of static buffer)
53
        size_t mValidBytes;
54
        /// Current read position
55
        size_t mPos;
56
    public:
57
        /// Constructor
58
        StaticCache()
59
0
        {
60
0
            mValidBytes = 0;
61
0
            mPos = 0;
62
0
            memset(mBuffer, 0, cacheSize);
63
0
        }
64
65
        /** Cache data pointed by 'buf'. If 'count' is greater than cache size, we cache only last bytes.
66
         Returns number of bytes written to cache. */
67
        size_t cacheData(const void* buf, size_t count)
68
0
        {
69
0
            assert(avail() == 0 && "It is assumed that you cache data only after you have read everything.");
70
71
0
            if (count < cacheSize)
72
0
            {
73
                // number of bytes written is less than total size of cache
74
0
                if (count + mValidBytes <= cacheSize)
75
0
                {
76
                    // just append
77
0
                    memcpy(mBuffer + mValidBytes, buf, count);
78
0
                    mValidBytes += count;
79
0
                }
80
0
                else
81
0
                {
82
0
                    size_t begOff = count - (cacheSize - mValidBytes);
83
                    // override old cache content in the beginning
84
0
                    memmove(mBuffer, mBuffer + begOff, mValidBytes - begOff);
85
                    // append new data
86
0
                    memcpy(mBuffer + cacheSize - count, buf, count);
87
0
                    mValidBytes = cacheSize;
88
0
                }
89
0
                mPos = mValidBytes;
90
0
                return count;
91
0
            }
92
0
            else
93
0
            {
94
                // discard all
95
0
                memcpy(mBuffer, (const char*)buf + count - cacheSize, cacheSize);
96
0
                mValidBytes = mPos = cacheSize;
97
0
                return cacheSize;
98
0
            }
99
0
        }
100
        /** Read data from cache to 'buf' (maximum 'count' bytes). Returns number of bytes read from cache. */
101
        size_t read(void* buf, size_t count)
102
0
        {
103
0
            size_t rb = avail();
104
0
            rb = (rb < count) ? rb : count;
105
0
            memcpy(buf, mBuffer + mPos, rb);
106
0
            mPos += rb;
107
0
            return rb;
108
0
        }
109
110
        /** Step back in cached stream by 'count' bytes. Returns 'true' if cache contains resulting position. */
111
        bool rewind(size_t count)
112
0
        {
113
0
            if (mPos < count)
114
0
            {
115
0
                clear();
116
0
                return false;
117
0
            }
118
0
            else
119
0
            {
120
0
                mPos -= count;
121
0
                return true;
122
0
            }
123
0
        }
124
        /** Step forward in cached stream by 'count' bytes. Returns 'true' if cache contains resulting position. */
125
        bool ff(size_t count)
126
0
        {
127
0
            if (avail() < count)
128
0
            {
129
0
                clear();
130
0
                return false;
131
0
            }
132
0
            else
133
0
            {
134
0
                mPos += count;
135
0
                return true;
136
0
            }
137
0
        }
138
139
        /** Returns number of bytes available for reading in cache after rewinding. */
140
        size_t avail() const
141
0
        {
142
0
            return mValidBytes - mPos;
143
0
        }
144
145
        /** Clear the cache */
146
        void clear()
147
0
        {
148
0
            mValidBytes = 0;
149
0
            mPos = 0;
150
0
        }
151
    };
152
153
    /** Stream which compresses / uncompresses data using the 'deflate' compression
154
        algorithm.
155
156
        This stream is designed to wrap another stream for the actual source / destination
157
        of the compressed data, it has no concrete source / data itself. The idea is
158
        that you pass uncompressed data through this stream, and the underlying
159
        stream reads/writes compressed data to the final source.
160
    @note
161
        This is an alternative to using a compressed archive since it is able to 
162
        compress & decompress regardless of the actual source of the stream.
163
        You should avoid using this with already compressed archives.
164
        Also note that this cannot be used as a read / write stream, only a read-only
165
        or write-only stream.
166
    */
167
    class _OgreExport DeflateStream : public DataStream
168
    {
169
    public:
170
        /** Requested stream type. All are essentially the same deflate stream with varying wrapping.
171
            ZLib is used by default.
172
        */
173
        enum StreamType
174
        {
175
            Invalid = -1, /// Unexpected stream type or uncompressed data
176
            Deflate = 0,  /// no header, no checksum, rfc1951
177
            ZLib = 1,     /// 2 byte header, 4 byte footer with adler32 checksum, rfc1950
178
            GZip = 2,     /// 10 byte header, 8 byte footer with crc32 checksum and unpacked size, rfc1952
179
        };
180
    private:
181
        DataStreamPtr mCompressedStream;
182
        DataStreamPtr mTmpWriteStream;
183
        String mTempFileName;
184
        z_stream* mZStream;
185
        int mStatus;
186
        size_t mCurrentPos;
187
        size_t mAvailIn;
188
        
189
        /// Cache for read data in case skipping around
190
        StaticCache<16 * OGRE_STREAM_TEMP_SIZE> mReadCache;
191
        
192
        /// Intermediate buffer for read / write
193
        unsigned char *mTmp;
194
        
195
        /// Whether the underlying stream is valid compressed data
196
        StreamType mStreamType;
197
        
198
        void init();
199
        void destroy();
200
        void compressFinal();
201
202
        size_t getAvailInForSinglePass();
203
    public:
204
        /** Constructor for creating unnamed stream wrapping another stream.
205
         @param compressedStream The stream that this stream will use when reading / 
206
            writing compressed data. The access mode from this stream will be matched.
207
         @param tmpFileName Path/Filename to be used for temporary storage of incoming data
208
         @param avail_in Available data length to be uncompressed. With it we can uncompress
209
            DataStream partly.
210
        */
211
        DeflateStream(const DataStreamPtr& compressedStream, const String& tmpFileName = "",
212
            size_t avail_in = 0);
213
        /** Constructor for creating named stream wrapping another stream.
214
         @param name The name to give this stream
215
         @param compressedStream The stream that this stream will use when reading / 
216
            writing compressed data. The access mode from this stream will be matched.
217
         @param tmpFileName Path/Filename to be used for temporary storage of incoming data
218
         @param avail_in Available data length to be uncompressed. With it we can uncompress
219
            DataStream partly.
220
         */
221
        DeflateStream(const String& name, const DataStreamPtr& compressedStream, const String& tmpFileName="",
222
            size_t avail_in = 0);
223
        /** Constructor for creating named stream wrapping another stream.
224
         @param name The name to give this stream
225
         @param compressedStream The stream that this stream will use when reading / 
226
            writing compressed data. The access mode from this stream will be matched.
227
         @param streamType The type of compressed stream
228
         @param tmpFileName Path/Filename to be used for temporary storage of incoming data
229
         @param avail_in Available data length to be uncompressed. With it we can uncompress
230
            DataStream partly.
231
         */
232
        DeflateStream(const String& name, const DataStreamPtr& compressedStream, StreamType streamType, const String& tmpFileName="",
233
            size_t avail_in = 0);
234
        
235
        ~DeflateStream();
236
        
237
        /** Returns whether the compressed stream is valid deflated data.
238
239
            If you pass this class a READ stream which is not compressed with the 
240
            deflate algorithm, this method returns false and all read commands
241
            will actually be executed as passthroughs as a fallback. 
242
        */
243
0
        bool isCompressedStreamValid() const { return mStreamType != Invalid; }
244
        
245
        /** @copydoc DataStream::read
246
         */
247
        size_t read(void* buf, size_t count) override;
248
        
249
        /** @copydoc DataStream::write
250
         */
251
        size_t write(const void* buf, size_t count) override;
252
                
253
        /** @copydoc DataStream::skip
254
         */
255
        void skip(long count) override;
256
        
257
        /** @copydoc DataStream::seek
258
         */
259
        void seek( size_t pos ) override;
260
        
261
        /** @copydoc DataStream::tell
262
         */
263
        size_t tell(void) const override;
264
        
265
        /** @copydoc DataStream::eof
266
         */
267
        bool eof(void) const override;
268
        
269
        /** @copydoc DataStream::close
270
         */
271
        void close(void) override;
272
        
273
    };
274
}
275
276
#include "OgreHeaderSuffix.h"
277
278
#endif
279
280
#endif