Coverage Report

Created: 2026-02-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ogre/OgreMain/src/OgreSerializer.cpp
Line
Count
Source
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
#include "OgreStableHeaders.h"
29
30
namespace Ogre {
31
32
    const uint16 HEADER_STREAM_ID = 0x1000;
33
    const uint16 OTHER_ENDIAN_HEADER_STREAM_ID = 0x0010;
34
    //---------------------------------------------------------------------
35
    Serializer::Serializer() :
36
0
        mVersion("[Serializer_v1.00]"), // Version number
37
0
        mFlipEndian(false)
38
#if OGRE_SERIALIZER_VALIDATE_CHUNKSIZE
39
        , mReportChunkErrors(true)
40
#endif
41
0
    {
42
0
    }
43
44
    //---------------------------------------------------------------------
45
    Serializer::~Serializer()
46
0
    {
47
0
    }
48
    //---------------------------------------------------------------------
49
    void Serializer::determineEndianness(const DataStreamPtr& stream)
50
0
    {
51
0
        if (stream->tell() != 0)
52
0
        {
53
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
54
0
                "Can only determine the endianness of the input stream if it "
55
0
                "is at the start", "Serializer::determineEndianness");
56
0
        }
57
                
58
0
        uint16 dest;
59
        // read header id manually (no conversion)
60
0
        size_t actually_read = stream->read(&dest, sizeof(uint16));
61
        // skip back
62
0
        stream->skip(0 - (long)actually_read);
63
0
        if (actually_read != sizeof(uint16))
64
0
        {
65
            // end of file?
66
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
67
0
                        "Couldn't read 16 bit header value from input stream.",
68
0
                        "Serializer::determineEndianness");
69
0
        }
70
0
        if (dest == HEADER_STREAM_ID)
71
0
        {
72
0
            mFlipEndian = false;
73
0
        }
74
0
        else if (dest == OTHER_ENDIAN_HEADER_STREAM_ID)
75
0
        {
76
0
            mFlipEndian = true;
77
0
        }
78
0
        else
79
0
        {
80
0
            OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
81
0
                "Header chunk didn't match either endian: Corrupted stream?",
82
0
                "Serializer::determineEndianness");
83
0
        }
84
0
    }
85
    //---------------------------------------------------------------------
86
    void Serializer::determineEndianness(Endian requestedEndian)
87
0
    {
88
0
        switch(requestedEndian)
89
0
        {
90
0
        case ENDIAN_NATIVE:
91
0
            mFlipEndian = false;
92
0
            break;
93
0
        case ENDIAN_BIG:
94
#if OGRE_ENDIAN == OGRE_ENDIAN_BIG
95
            mFlipEndian = false;
96
#else
97
0
            mFlipEndian = true;
98
0
#endif
99
0
            break;
100
0
        case ENDIAN_LITTLE:
101
#if OGRE_ENDIAN == OGRE_ENDIAN_BIG
102
            mFlipEndian = true;
103
#else
104
0
            mFlipEndian = false;
105
0
#endif
106
0
            break;
107
0
        }
108
0
    }
109
    //---------------------------------------------------------------------
110
    void Serializer::writeFileHeader(void)
111
0
    {
112
        
113
0
        uint16 val = HEADER_STREAM_ID;
114
0
        writeShorts(&val, 1);
115
116
0
        writeString(mVersion);
117
118
0
    }
119
    //---------------------------------------------------------------------
120
    void Serializer::writeChunkHeader(uint16 id, size_t size)
121
0
    {
122
#if OGRE_SERIALIZER_VALIDATE_CHUNKSIZE
123
        if (!mChunkSizeStack.empty()){
124
            size_t pos = mStream->tell();
125
            if (pos != static_cast<size_t>(mChunkSizeStack.back()) && mReportChunkErrors){
126
                LogManager::getSingleton().logMessage("Corrupted chunk detected! Stream name: '" + mStream->getName()
127
                    + "' Chunk id: " + StringConverter::toString(id));
128
            }
129
            mChunkSizeStack.back() = pos + size;
130
        }
131
#endif
132
0
        writeShorts(&id, 1);
133
0
        uint32 uint32size = static_cast<uint32>(size);
134
0
        writeInts(&uint32size, 1);
135
0
    }
136
    //---------------------------------------------------------------------
137
    void Serializer::writeFloats(const float* const pFloat, size_t count)
138
0
    {
139
0
        if (mFlipEndian)
140
0
        {
141
0
            float * pFloatToWrite = (float *)malloc(sizeof(float) * count);
142
0
            memcpy(pFloatToWrite, pFloat, sizeof(float) * count);
143
            
144
0
            flipToLittleEndian(pFloatToWrite, sizeof(float), count);
145
0
            writeData(pFloatToWrite, sizeof(float), count);
146
            
147
0
            free(pFloatToWrite);
148
0
        }
149
0
        else
150
0
        {
151
0
            writeData(pFloat, sizeof(float), count);
152
0
        }
153
0
    }
154
    //---------------------------------------------------------------------
155
    void Serializer::writeFloats(const double* const pDouble, size_t count)
156
0
    {
157
        // Convert to float, then write
158
0
        float* tmp = OGRE_ALLOC_T(float, count, MEMCATEGORY_GENERAL);
159
0
        for (unsigned int i = 0; i < count; ++i)
160
0
        {
161
0
            tmp[i] = static_cast<float>(pDouble[i]);
162
0
        }
163
0
        if(mFlipEndian)
164
0
        {
165
0
            flipToLittleEndian(tmp, sizeof(float), count);
166
0
            writeData(tmp, sizeof(float), count);
167
0
        }
168
0
        else
169
0
        {
170
0
            writeData(tmp, sizeof(float), count);
171
0
        }
172
0
        OGRE_FREE(tmp, MEMCATEGORY_GENERAL);
173
0
    }
174
    //---------------------------------------------------------------------
175
    void Serializer::writeShorts(const uint16* const pShort, size_t count = 1)
176
0
    {
177
0
        if(mFlipEndian)
178
0
        {
179
0
            unsigned short * pShortToWrite = (unsigned short *)malloc(sizeof(unsigned short) * count);
180
0
            memcpy(pShortToWrite, pShort, sizeof(unsigned short) * count);
181
            
182
0
            flipToLittleEndian(pShortToWrite, sizeof(unsigned short), count);
183
0
            writeData(pShortToWrite, sizeof(unsigned short), count);
184
            
185
0
            free(pShortToWrite);
186
0
        }
187
0
        else
188
0
        {
189
0
            writeData(pShort, sizeof(unsigned short), count);
190
0
        }
191
0
    }
192
    //---------------------------------------------------------------------
193
    void Serializer::writeInts(const uint32* const pInt, size_t count = 1)
194
0
    {
195
0
        if(mFlipEndian)
196
0
        {
197
0
            uint32 * pIntToWrite = (uint32 *)malloc(sizeof(uint32) * count);
198
0
            memcpy(pIntToWrite, pInt, sizeof(uint32) * count);
199
            
200
0
            flipToLittleEndian(pIntToWrite, sizeof(uint32), count);
201
0
            writeData(pIntToWrite, sizeof(uint32), count);
202
            
203
0
            free(pIntToWrite);
204
0
        }
205
0
        else
206
0
        {
207
0
            writeData(pInt, sizeof(uint32), count);
208
0
        }
209
0
    }
210
    //---------------------------------------------------------------------
211
    //---------------------------------------------------------------------
212
    void Serializer::writeBools(const bool* const pBool, size_t count = 1)
213
0
    {
214
        //no endian flipping for 1-byte bools
215
0
        static_assert(sizeof(bool) == 1, "add conversion to char for your platform");
216
0
        writeData(pBool, sizeof(bool), count);
217
0
    }
218
    
219
    //---------------------------------------------------------------------
220
    void Serializer::writeData(const void* const buf, size_t size, size_t count)
221
0
    {
222
0
        mStream->write(buf, size * count);
223
0
    }
224
    //---------------------------------------------------------------------
225
    void Serializer::writeString(const String& string)
226
0
    {
227
        // Old, backwards compatible way - \n terminated
228
0
        mStream->write(string.c_str(), string.length());
229
        // Write terminating newline char
230
0
        char terminator = '\n';
231
0
        mStream->write(&terminator, 1);
232
0
    }
233
    //---------------------------------------------------------------------
234
    void Serializer::readFileHeader(const DataStreamPtr& stream)
235
0
    {
236
0
        unsigned short headerID;
237
        
238
        // Read header ID
239
0
        readShorts(stream, &headerID, 1);
240
        
241
0
        if (headerID == HEADER_STREAM_ID)
242
0
        {
243
            // Read version
244
0
            String ver = readString(stream);
245
0
            if (ver != mVersion)
246
0
            {
247
0
                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 
248
0
                    "Invalid file: version incompatible, file reports " + String(ver) +
249
0
                    " Serializer is version " + mVersion,
250
0
                    "Serializer::readFileHeader");
251
0
            }
252
0
        }
253
0
        else
254
0
        {
255
0
            OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Invalid file: no header", 
256
0
                "Serializer::readFileHeader");
257
0
        }
258
259
0
    }
260
    //---------------------------------------------------------------------
261
    unsigned short Serializer::readChunk(const DataStreamPtr& stream)
262
0
    {
263
#if OGRE_SERIALIZER_VALIDATE_CHUNKSIZE
264
        size_t pos = stream->tell();
265
#endif
266
0
        unsigned short id;
267
0
        readShorts(stream, &id, 1);
268
        
269
0
        readInts(stream, &mCurrentstreamLen, 1);
270
#if OGRE_SERIALIZER_VALIDATE_CHUNKSIZE
271
        if (!mChunkSizeStack.empty() && !stream->eof()){
272
            if (pos != static_cast<size_t>(mChunkSizeStack.back()) && mReportChunkErrors){
273
                LogManager::getSingleton().logMessage("Corrupted chunk detected! Stream name: '" + stream->getName() + "' Chunk id: " + StringConverter::toString(id));
274
            }
275
            mChunkSizeStack.back() = pos + mCurrentstreamLen;
276
        }
277
#endif
278
0
        return id;
279
0
    }
280
    //---------------------------------------------------------------------
281
    void Serializer::readBools(const DataStreamPtr& stream, bool* pDest, size_t count)
282
0
    {
283
0
        static_assert(sizeof(bool) == 1, "add conversion to char for your platform");
284
0
        stream->read(pDest, sizeof(bool) * count);
285
0
    }
286
    //---------------------------------------------------------------------
287
    void Serializer::readFloats(const DataStreamPtr& stream, float* pDest, size_t count)
288
0
    {
289
0
        stream->read(pDest, sizeof(float) * count);
290
0
        flipFromLittleEndian(pDest, sizeof(float), count);
291
0
    }
292
    //---------------------------------------------------------------------
293
    void Serializer::readFloats(const DataStreamPtr& stream, double* pDest, size_t count)
294
0
    {
295
        // Read from float, convert to double
296
0
        float* tmp = OGRE_ALLOC_T(float, count, MEMCATEGORY_GENERAL);
297
0
        float* ptmp = tmp;
298
0
        stream->read(tmp, sizeof(float) * count);
299
0
        flipFromLittleEndian(tmp, sizeof(float), count);
300
        // Convert to doubles (no cast required)
301
0
        while(count--)
302
0
        {
303
0
            *pDest++ = *ptmp++;
304
0
        }
305
0
        OGRE_FREE(tmp, MEMCATEGORY_GENERAL);
306
0
    }
307
    //---------------------------------------------------------------------
308
    void Serializer::readShorts(const DataStreamPtr& stream, unsigned short* pDest, size_t count)
309
0
    {
310
0
        stream->read(pDest, sizeof(unsigned short) * count);
311
0
        flipFromLittleEndian(pDest, sizeof(unsigned short), count);
312
0
    }
313
    //---------------------------------------------------------------------
314
    void Serializer::readInts(const DataStreamPtr& stream, uint32* pDest, size_t count)
315
0
    {
316
0
        stream->read(pDest, sizeof(uint32) * count);
317
0
        flipFromLittleEndian(pDest, sizeof(uint32), count);
318
0
    }
319
    //---------------------------------------------------------------------
320
    String Serializer::readString(const DataStreamPtr& stream)
321
0
    {
322
0
        return stream->getLine(false);
323
0
    }
324
    //---------------------------------------------------------------------
325
    void Serializer::writeObject(const Vector3& vec)
326
0
    {
327
0
        writeFloats(vec.ptr(), 3);
328
0
    }
329
    //---------------------------------------------------------------------
330
    void Serializer::writeObject(const Quaternion& q)
331
0
    {
332
0
        float tmp[4] = {
333
0
            static_cast<float>(q.x),
334
0
            static_cast<float>(q.y),
335
0
            static_cast<float>(q.z),
336
0
            static_cast<float>(q.w)
337
0
        };
338
0
        writeFloats(tmp, 4);
339
0
    }
340
    //---------------------------------------------------------------------
341
    void Serializer::readObject(const DataStreamPtr& stream, Vector3& pDest)
342
0
    {
343
0
        readFloats(stream, pDest.ptr(), 3);
344
0
    }
345
    //---------------------------------------------------------------------
346
    void Serializer::readObject(const DataStreamPtr& stream, Quaternion& pDest)
347
0
    {
348
0
        float tmp[4];
349
0
        readFloats(stream, tmp, 4);
350
0
        pDest.x = tmp[0];
351
0
        pDest.y = tmp[1];
352
0
        pDest.z = tmp[2];
353
0
        pDest.w = tmp[3];
354
0
    }
355
    //---------------------------------------------------------------------
356
357
358
    void Serializer::flipToLittleEndian(void* pData, size_t size, size_t count)
359
0
    {
360
0
        if(mFlipEndian)
361
0
        {
362
0
      Bitwise::bswapChunks(pData, size, count);
363
0
        }
364
0
    }
365
    
366
    void Serializer::flipFromLittleEndian(void* pData, size_t size, size_t count)
367
0
    {
368
0
        if(mFlipEndian)
369
0
        {
370
0
          Bitwise::bswapChunks(pData, size, count);
371
0
        }
372
0
    }
373
374
    void Serializer::pushInnerChunk(const DataStreamPtr& stream)
375
0
    {
376
#if OGRE_SERIALIZER_VALIDATE_CHUNKSIZE
377
        mChunkSizeStack.push_back(stream->tell());
378
#endif
379
0
    }
380
    void Serializer::backpedalChunkHeader(const DataStreamPtr& stream)
381
0
    {
382
0
        if (!stream->eof()){
383
0
            stream->skip(-(int)calcChunkHeaderSize());
384
0
        }
385
#if OGRE_SERIALIZER_VALIDATE_CHUNKSIZE
386
        mChunkSizeStack.back() = stream->tell();
387
#endif
388
0
    }
389
    void Serializer::popInnerChunk(const DataStreamPtr& stream)
390
0
    {
391
#if OGRE_SERIALIZER_VALIDATE_CHUNKSIZE
392
        if (!mChunkSizeStack.empty()){
393
            size_t pos = stream->tell();
394
            if (pos != static_cast<size_t>(mChunkSizeStack.back()) && !stream->eof() && mReportChunkErrors){
395
                LogManager::getSingleton().logMessage("Corrupted chunk detected! Stream name: " + stream->getName());
396
            }
397
398
            mChunkSizeStack.pop_back();
399
        }
400
#endif
401
0
    }
402
403
}
404