Coverage Report

Created: 2026-07-25 07:30

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libregf/libregf/libregf_checksum.c
Line
Count
Source
1
/*
2
 * Checksum functions
3
 *
4
 * Copyright (C) 2009-2026, Joachim Metz <joachim.metz@gmail.com>
5
 *
6
 * Refer to AUTHORS for acknowledgements.
7
 *
8
 * This program is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation, either version 3 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 * GNU General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
 */
21
22
#include <common.h>
23
#include <byte_stream.h>
24
#include <types.h>
25
26
#include "libregf_checksum.h"
27
#include "libregf_libcerror.h"
28
29
/* The largest primary (or scalar) available
30
 * supported by a single load and store instruction
31
 */
32
typedef unsigned long int libregf_aligned_t;
33
34
/* Calculates the little-endian XOR-32 of a buffer
35
 * It uses the initial value to calculate a new XOR-32
36
 * Returns 1 if successful or -1 on error
37
 */
38
int libregf_checksum_calculate_little_endian_xor32(
39
     uint32_t *checksum_value,
40
     const uint8_t *buffer,
41
     size_t size,
42
     uint32_t initial_value,
43
     libcerror_error_t **error )
44
3.79k
{
45
3.79k
  libregf_aligned_t *aligned_buffer_iterator = NULL;
46
3.79k
  uint8_t *buffer_iterator                   = NULL;
47
3.79k
  static char *function                      = "libregf_checksum_calculate_little_endian_xor32";
48
3.79k
  libregf_aligned_t value_aligned            = 0;
49
3.79k
  uint32_t big_endian_value_32bit            = 0;
50
3.79k
  uint32_t safe_checksum_value               = 0;
51
3.79k
  uint32_t value_32bit                       = 0;
52
3.79k
  uint8_t alignment_count                    = 0;
53
3.79k
  uint8_t alignment_size                     = 0;
54
3.79k
  uint8_t byte_count                         = 0;
55
3.79k
  uint8_t byte_order                         = 0;
56
3.79k
  uint8_t byte_size                          = 0;
57
58
3.79k
  if( checksum_value == NULL )
59
0
  {
60
0
    libcerror_error_set(
61
0
     error,
62
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
63
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
64
0
     "%s: invalid checksum value.",
65
0
     function );
66
67
0
    return( -1 );
68
0
  }
69
3.79k
  if( buffer == NULL )
70
0
  {
71
0
    libcerror_error_set(
72
0
     error,
73
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
74
0
     LIBCERROR_ARGUMENT_ERROR_INVALID_VALUE,
75
0
     "%s: invalid buffer.",
76
0
     function );
77
78
0
    return( -1 );
79
0
  }
80
3.79k
  if( size > (size_t) SSIZE_MAX )
81
0
  {
82
0
    libcerror_error_set(
83
0
     error,
84
0
     LIBCERROR_ERROR_DOMAIN_ARGUMENTS,
85
0
     LIBCERROR_ARGUMENT_ERROR_VALUE_EXCEEDS_MAXIMUM,
86
0
     "%s: invalid size value exceeds maximum.",
87
0
     function );
88
89
0
    return( -1 );
90
0
  }
91
3.79k
  safe_checksum_value = initial_value;
92
93
3.79k
  buffer_iterator = (uint8_t *) buffer;
94
95
  /* Only optimize when there is the alignment is a multitude of 32-bit
96
   * and for buffers larger than the alignment
97
   */
98
3.79k
  if( ( ( sizeof( libregf_aligned_t ) % 4 ) == 0 )
99
3.79k
   && ( size > ( 2 * sizeof( libregf_aligned_t ) ) ) )
100
3.79k
  {
101
    /* Align the buffer iterator
102
     */
103
3.79k
    alignment_size = (uint8_t) ( (intptr_t) buffer_iterator % sizeof( libregf_aligned_t ) );
104
105
3.79k
    if( alignment_size > 0 )
106
0
    {
107
0
      byte_size = sizeof( libregf_aligned_t ) - alignment_size;
108
109
      /* Align the buffer iterator in 4-byte steps
110
       */
111
0
      while( byte_size != 0 )
112
0
      {
113
0
        value_32bit = 0;
114
0
        byte_count  = 1;
115
116
0
        if( byte_size >= 4 )
117
0
        {
118
0
          value_32bit |= buffer_iterator[ 3 ];
119
0
          value_32bit <<= 8;
120
121
0
          byte_count++;
122
0
        }
123
0
        if( byte_size >= 3 )
124
0
        {
125
0
          value_32bit |= buffer_iterator[ 2 ];
126
0
          value_32bit <<= 8;
127
128
0
          byte_count++;
129
0
        }
130
0
        if( byte_size >= 2 )
131
0
        {
132
0
          value_32bit |= buffer_iterator[ 1 ];
133
0
          value_32bit <<= 8;
134
135
0
          byte_count++;
136
0
        }
137
0
        value_32bit |= buffer_iterator[ 0 ];
138
139
0
        buffer_iterator += byte_count;
140
0
        byte_size       -= byte_count;
141
142
0
        safe_checksum_value ^= value_32bit;
143
0
      }
144
0
      size -= byte_count;
145
0
    }
146
3.79k
    aligned_buffer_iterator = (libregf_aligned_t *) buffer_iterator;
147
148
3.79k
    if( *buffer_iterator != (uint8_t) ( *aligned_buffer_iterator & 0xff ) )
149
0
    {
150
0
      byte_order = _BYTE_STREAM_ENDIAN_BIG;
151
0
    }
152
3.79k
    else
153
3.79k
    {
154
3.79k
      byte_order = _BYTE_STREAM_ENDIAN_LITTLE;
155
3.79k
    }
156
    /* Calculate the XOR value using the aligned buffer iterator
157
     */
158
243k
    while( size > sizeof( libregf_aligned_t ) )
159
239k
    {
160
239k
      value_aligned ^= *aligned_buffer_iterator;
161
162
239k
      aligned_buffer_iterator++;
163
164
239k
      size -= sizeof( libregf_aligned_t );
165
239k
    }
166
    /* Align the aligned XOR value with the 32-bit XOR value
167
     */
168
3.79k
    if( alignment_size > 0 )
169
0
    {
170
0
      byte_count      = ( alignment_size % 4 ) * 8;
171
0
      alignment_count = ( sizeof( libregf_aligned_t ) - alignment_size ) * 8;
172
173
0
      if( byte_order == _BYTE_STREAM_ENDIAN_BIG )
174
0
      {
175
0
        if( alignment_count > sizeof( libregf_aligned_t ) )
176
0
        {
177
0
          libcerror_error_set(
178
0
           error,
179
0
           LIBCERROR_ERROR_DOMAIN_RUNTIME,
180
0
           LIBCERROR_RUNTIME_ERROR_VALUE_OUT_OF_BOUNDS,
181
0
           "%s: invalid alignment count value out of bounds.",
182
0
           function );
183
184
0
          return( -1 );
185
0
        }
186
        /* Shift twice to set unused bytes to 0
187
         */
188
0
        big_endian_value_32bit = (uint32_t) ( ( value_aligned >> alignment_count ) << byte_count );
189
190
        /* Change big-endian into little-endian
191
         */
192
0
        value_32bit = ( ( big_endian_value_32bit & 0x000000ffUL ) << 24 )
193
0
                    | ( ( big_endian_value_32bit & 0x0000ff00UL ) << 8 )
194
0
                    | ( ( big_endian_value_32bit >> 8 ) & 0x0000ff00UL )
195
0
                    | ( ( big_endian_value_32bit >> 24 ) & 0x000000ffUL );
196
197
        /* Strip-off the used part of the aligned value
198
         */
199
0
        value_aligned <<= alignment_count;
200
0
      }
201
0
      else if( byte_order == _BYTE_STREAM_ENDIAN_LITTLE )
202
0
      {
203
0
        value_32bit = (uint32_t) ( value_aligned << byte_count );
204
205
        /* Strip-off the used part of the aligned value
206
         */
207
0
        value_aligned >>= alignment_count;
208
0
      }
209
0
      safe_checksum_value ^= value_32bit;
210
0
    }
211
    /* Update the 32-bit XOR value with the aligned XOR value
212
     */
213
3.79k
    byte_size = (uint8_t) sizeof( libregf_aligned_t );
214
215
11.3k
    while( byte_size != 0 )
216
7.59k
    {
217
7.59k
      byte_count = ( ( byte_size / 4 ) - 1 ) * 32;
218
219
7.59k
      if( byte_order == _BYTE_STREAM_ENDIAN_BIG )
220
0
      {
221
0
        big_endian_value_32bit = (uint32_t) ( ( value_aligned >> byte_count ) & 0xffffffffUL );
222
223
        /* Change big-endian into little-endian
224
         */
225
0
        value_32bit = ( ( big_endian_value_32bit & 0x000000ffUL ) << 24 )
226
0
                    | ( ( big_endian_value_32bit & 0x0000ff00UL ) << 8 )
227
0
                    | ( ( big_endian_value_32bit >> 8 ) & 0x0000ff00UL )
228
0
                    | ( ( big_endian_value_32bit >> 24 ) & 0x000000ffUL );
229
0
      }
230
7.59k
      else if( byte_order == _BYTE_STREAM_ENDIAN_LITTLE )
231
7.59k
      {
232
7.59k
        value_32bit = (uint32_t) value_aligned;
233
234
7.59k
        value_aligned >>= byte_count;
235
7.59k
      }
236
7.59k
      byte_size -= 4;
237
238
7.59k
      safe_checksum_value ^= value_32bit;
239
7.59k
    }
240
    /* Re-align the buffer iterator
241
     */
242
3.79k
    buffer_iterator = (uint8_t *) aligned_buffer_iterator;
243
244
3.79k
    byte_size = 4 - ( alignment_size % 4 );
245
246
3.79k
    if( byte_size != 4 )
247
0
    {
248
0
      value_32bit   = buffer_iterator[ 0 ];
249
0
      value_32bit <<= 8;
250
251
0
      if( byte_size >= 2 )
252
0
      {
253
0
        value_32bit |= buffer_iterator[ 1 ];
254
0
      }
255
0
      value_32bit <<= 8;
256
257
0
      if( byte_size >= 3 )
258
0
      {
259
0
        value_32bit |= buffer_iterator[ 2 ];
260
0
      }
261
0
      value_32bit <<= 8;
262
263
0
      buffer_iterator += byte_size;
264
0
      size            -= byte_size;
265
266
0
      safe_checksum_value ^= value_32bit;
267
0
    }
268
3.79k
  }
269
7.59k
  while( size > 0 )
270
3.79k
  {
271
3.79k
    value_32bit = 0;
272
3.79k
    byte_count  = 1;
273
274
3.79k
    if( size >= 4 )
275
3.79k
    {
276
3.79k
      value_32bit |= buffer_iterator[ 3 ];
277
3.79k
      value_32bit <<= 8;
278
279
3.79k
      byte_count++;
280
3.79k
    }
281
3.79k
    if( size >= 3 )
282
3.79k
    {
283
3.79k
      value_32bit |= buffer_iterator[ 2 ];
284
3.79k
      value_32bit <<= 8;
285
286
3.79k
      byte_count++;
287
3.79k
    }
288
3.79k
    if( size >= 2 )
289
3.79k
    {
290
3.79k
      value_32bit |= buffer_iterator[ 1 ];
291
3.79k
      value_32bit <<= 8;
292
293
3.79k
      byte_count++;
294
3.79k
    }
295
3.79k
    value_32bit |= buffer_iterator[ 0 ];
296
297
3.79k
    buffer_iterator += byte_count;
298
3.79k
    size            -= byte_count;
299
300
3.79k
    safe_checksum_value ^= value_32bit;
301
3.79k
  }
302
3.79k
  *checksum_value = safe_checksum_value;
303
304
3.79k
  return( 1 );
305
3.79k
}
306