1 /* test_libFLAC - Unit tester for libFLAC
2  * Copyright (C) 2014-2018  Xiph.Org Foundation
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22 
23 #include <stdio.h>
24 
25 #include "FLAC/assert.h"
26 #include "share/compat.h"
27 #include "private/crc.h"
28 #include "crc.h"
29 
30 static FLAC__uint8 crc8_update_ref(FLAC__byte byte, FLAC__uint8 crc);
31 static FLAC__uint16 crc16_update_ref(FLAC__byte byte, FLAC__uint16 crc);
32 
33 static FLAC__bool test_crc8(const FLAC__byte *data, size_t size);
34 static FLAC__bool test_crc16(const FLAC__byte *data, size_t size);
35 static FLAC__bool test_crc16_update(const FLAC__byte *data, size_t size);
36 static FLAC__bool test_crc16_32bit_words(const FLAC__uint32 *words, size_t size);
37 static FLAC__bool test_crc16_64bit_words(const FLAC__uint64 *words, size_t size);
38 
39 #define DATA_SIZE 32768
40 
test_crc(void)41 FLAC__bool test_crc(void)
42 {
43 	uint32_t i;
44 	FLAC__byte data[DATA_SIZE] = { 0 };
45 
46 	/* Initialize data reproducibly with pseudo-random values. */
47 	for (i = 1; i < DATA_SIZE; i++)
48 		data[i] = crc8_update_ref(i % 256, data[i - 1]);
49 
50 	printf("\n+++ libFLAC unit test: crc\n\n");
51 
52 	if (! test_crc8(data, DATA_SIZE))
53 		return false;
54 
55 	if (! test_crc16(data, DATA_SIZE))
56 		return false;
57 
58 	if (! test_crc16_update(data, DATA_SIZE))
59 		return false;
60 
61 	if (! test_crc16_32bit_words((FLAC__uint32 *)data, DATA_SIZE / 4))
62 		return false;
63 
64 	if (! test_crc16_64bit_words((FLAC__uint64 *)data, DATA_SIZE / 8))
65 		return false;
66 
67 	printf("\nPASSED!\n");
68 	return true;
69 }
70 
71 /*----------------------------------------------------------------------------*/
72 
73 /* Reference implementations of CRC-8 and CRC-16 to check against. */
74 
75 #define CRC8_POLYNOMIAL 0x07
76 
crc8_update_ref(FLAC__byte byte,FLAC__uint8 crc)77 static FLAC__uint8 crc8_update_ref(FLAC__byte byte, FLAC__uint8 crc)
78 {
79     uint32_t i;
80 
81     crc ^= byte;
82 
83     for (i = 0; i < 8; i++) {
84         crc = (crc << 1) ^ ((crc >> 7) ? CRC8_POLYNOMIAL : 0);
85     }
86 
87     return crc;
88 }
89 
90 #define CRC16_POLYNOMIAL 0x8005
91 
crc16_update_ref(FLAC__byte byte,FLAC__uint16 crc)92 static FLAC__uint16 crc16_update_ref(FLAC__byte byte, FLAC__uint16 crc)
93 {
94     uint32_t i;
95 
96     crc ^= byte << 8;
97 
98     for (i = 0; i < 8; i++) {
99         crc = (crc << 1) ^ ((crc >> 15) ? CRC16_POLYNOMIAL : 0);
100     }
101 
102     return crc;
103 }
104 
105 /*----------------------------------------------------------------------------*/
106 
test_crc8(const FLAC__byte * data,size_t size)107 static FLAC__bool test_crc8(const FLAC__byte *data, size_t size)
108 {
109 	uint32_t i;
110 	FLAC__uint8 crc0,crc1;
111 
112 	printf("testing FLAC__crc8 ... ");
113 
114 	crc0 = 0;
115 	crc1 = FLAC__crc8(data, 0);
116 
117 	if (crc1 != crc0) {
118 		printf("FAILED, FLAC__crc8 returned non-zero CRC for zero bytes of data\n");
119 		return false;
120 	}
121 
122 	for (i = 0; i < size; i++) {
123 		crc0 = crc8_update_ref(data[i], crc0);
124 		crc1 = FLAC__crc8(data, i + 1);
125 
126 		if (crc1 != crc0) {
127 			printf("FAILED, FLAC__crc8 result did not match reference CRC for %u bytes of test data\n", i + 1);
128 			return false;
129 		}
130 	}
131 
132 	printf("OK\n");
133 
134 	return true;
135 }
136 
test_crc16(const FLAC__byte * data,size_t size)137 static FLAC__bool test_crc16(const FLAC__byte *data, size_t size)
138 {
139 	uint32_t i;
140 	FLAC__uint16 crc0,crc1;
141 
142 	printf("testing FLAC__crc16 ... ");
143 
144 	crc0 = 0;
145 	crc1 = FLAC__crc16(data, 0);
146 
147 	if (crc1 != crc0) {
148 		printf("FAILED, FLAC__crc16 returned non-zero CRC for zero bytes of data\n");
149 		return false;
150 	}
151 
152 	for (i = 0; i < size; i++) {
153 		crc0 = crc16_update_ref(data[i], crc0);
154 		crc1 = FLAC__crc16(data, i + 1);
155 
156 		if (crc1 != crc0) {
157 			printf("FAILED, FLAC__crc16 result did not match reference CRC for %u bytes of test data\n", i + 1);
158 			return false;
159 		}
160 	}
161 
162 	printf("OK\n");
163 
164 	return true;
165 }
166 
test_crc16_update(const FLAC__byte * data,size_t size)167 static FLAC__bool test_crc16_update(const FLAC__byte *data, size_t size)
168 {
169 	uint32_t i;
170 	FLAC__uint16 crc0,crc1;
171 
172 	printf("testing FLAC__CRC16_UPDATE macro ... ");
173 
174 	crc0 = 0;
175 	crc1 = 0;
176 
177 	for (i = 0; i < size; i++) {
178 		crc0 = crc16_update_ref(data[i], crc0);
179 		crc1 = FLAC__CRC16_UPDATE(data[i], crc1);
180 
181 		if (crc1 != crc0) {
182 			printf("FAILED, FLAC__CRC16_UPDATE result did not match reference CRC after %u bytes of test data\n", i + 1);
183 			return false;
184 		}
185 	}
186 
187 	printf("OK\n");
188 
189 	return true;
190 }
191 
test_crc16_32bit_words(const FLAC__uint32 * words,size_t size)192 static FLAC__bool test_crc16_32bit_words(const FLAC__uint32 *words, size_t size)
193 {
194 	uint32_t n,i,k;
195 	FLAC__uint16 crc0,crc1;
196 
197 	for (n = 1; n <= 16; n++) {
198 		printf("testing FLAC__crc16_update_words32 (length=%i) ... ", n);
199 
200 		crc0 = 0;
201 		crc1 = 0;
202 
203 		for (i = 0; i <= size - n; i += n) {
204 			for (k = 0; k < n; k++) {
205 				crc0 = crc16_update_ref( words[i + k] >> 24,         crc0);
206 				crc0 = crc16_update_ref((words[i + k] >> 16) & 0xFF, crc0);
207 				crc0 = crc16_update_ref((words[i + k] >>  8) & 0xFF, crc0);
208 				crc0 = crc16_update_ref( words[i + k]        & 0xFF, crc0);
209 			}
210 
211 			crc1 = FLAC__crc16_update_words32(words + i, n, crc1);
212 
213 			if (crc1 != crc0) {
214 				printf("FAILED, FLAC__crc16_update_words32 result did not match reference CRC after %u words of test data\n", i + n);
215 				return false;
216 			}
217 		}
218 
219 		crc1 = FLAC__crc16_update_words32(words, 0, crc1);
220 
221 		if (crc1 != crc0) {
222 			printf("FAILED, FLAC__crc16_update_words32 called with zero bytes changed CRC value\n");
223 			return false;
224 		}
225 
226 		printf("OK\n");
227 	}
228 
229 	return true;
230 }
231 
test_crc16_64bit_words(const FLAC__uint64 * words,size_t size)232 static FLAC__bool test_crc16_64bit_words(const FLAC__uint64 *words, size_t size)
233 {
234 	uint32_t n,i,k;
235 	FLAC__uint16 crc0,crc1;
236 
237 	for (n = 1; n <= 16; n++) {
238 		printf("testing FLAC__crc16_update_words64 (length=%i) ... ", n);
239 
240 		crc0 = 0;
241 		crc1 = 0;
242 
243 		for (i = 0; i <= size - n; i += n) {
244 			for (k = 0; k < n; k++) {
245 				crc0 = crc16_update_ref( words[i + k] >> 56,         crc0);
246 				crc0 = crc16_update_ref((words[i + k] >> 48) & 0xFF, crc0);
247 				crc0 = crc16_update_ref((words[i + k] >> 40) & 0xFF, crc0);
248 				crc0 = crc16_update_ref((words[i + k] >> 32) & 0xFF, crc0);
249 				crc0 = crc16_update_ref((words[i + k] >> 24) & 0xFF, crc0);
250 				crc0 = crc16_update_ref((words[i + k] >> 16) & 0xFF, crc0);
251 				crc0 = crc16_update_ref((words[i + k] >>  8) & 0xFF, crc0);
252 				crc0 = crc16_update_ref( words[i + k]        & 0xFF, crc0);
253 			}
254 
255 			crc1 = FLAC__crc16_update_words64(words + i, n, crc1);
256 
257 			if (crc1 != crc0) {
258 				printf("FAILED, FLAC__crc16_update_words64 result did not match reference CRC after %u words of test data\n", i + n);
259 				return false;
260 			}
261 		}
262 
263 		crc1 = FLAC__crc16_update_words64(words, 0, crc1);
264 
265 		if (crc1 != crc0) {
266 			printf("FAILED, FLAC__crc16_update_words64 called with zero bytes changed CRC value\n");
267 			return false;
268 		}
269 
270 		printf("OK\n");
271 	}
272 
273 	return true;
274 }
275