2 * Copyright (C) 2004 Benjamin Otte <otte@gnome.org>
4 * includes code based on glibc 2.2.3's crypt/md5.c,
5 * Copyright (C) 1995, 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
43 length_get_spec (const GstTestInfo * info, gboolean compare_value)
46 return g_param_spec_int64 ("expected-length", "expected length",
47 "expected length of stream", -1, G_MAXINT64, -1,
48 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
50 return g_param_spec_int64 ("length", "length", "length of stream",
51 -1, G_MAXINT64, -1, G_PARAM_READABLE);
56 length_new (const GstTestInfo * info)
58 return g_new0 (LengthTest, 1);
62 length_add (gpointer test, GstBuffer * buffer)
66 t->value += GST_BUFFER_SIZE (buffer);
70 length_finish (gpointer test, GValue * value)
74 if (g_value_get_int64 (value) == -1)
77 return t->value == g_value_get_int64 (value);
81 length_get_value (gpointer test, GValue * value)
85 g_value_set_int64 (value, t ? t->value : -1);
93 buffer_count_get_spec (const GstTestInfo * info, gboolean compare_value)
96 return g_param_spec_int64 ("expected-buffer-count", "expected buffer count",
97 "expected number of buffers in stream",
98 -1, G_MAXINT64, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
100 return g_param_spec_int64 ("buffer-count", "buffer count",
101 "number of buffers in stream", -1, G_MAXINT64, -1, G_PARAM_READABLE);
106 buffer_count_add (gpointer test, GstBuffer * buffer)
108 LengthTest *t = test;
114 *** TIMESTAMP / DURATION MATCHING ***
121 GstClockTime expected;
126 timedur_get_spec (const GstTestInfo * info, gboolean compare_value)
129 return g_param_spec_int64 ("allowed-timestamp-deviation",
130 "allowed timestamp deviation",
131 "allowed average difference in usec between timestamp of next buffer "
132 "and expected timestamp from analyzing last buffer",
133 -1, G_MAXINT64, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
135 return g_param_spec_int64 ("timestamp-deviation",
136 "timestamp deviation",
137 "average difference in usec between timestamp of next buffer "
138 "and expected timestamp from analyzing last buffer",
139 -1, G_MAXINT64, -1, G_PARAM_READABLE);
144 timedur_new (const GstTestInfo * info)
146 TimeDurTest *ret = g_new0 (TimeDurTest, 1);
148 ret->expected = GST_CLOCK_TIME_NONE;
154 timedur_add (gpointer test, GstBuffer * buffer)
156 TimeDurTest *t = test;
158 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
159 GST_CLOCK_TIME_IS_VALID (t->expected)) {
160 t->diff += labs (GST_BUFFER_TIMESTAMP (buffer) - t->expected);
163 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
164 GST_BUFFER_DURATION_IS_VALID (buffer)) {
165 t->expected = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
167 t->expected = GST_CLOCK_TIME_NONE;
172 timedur_finish (gpointer test, GValue * value)
174 TimeDurTest *t = test;
176 if (g_value_get_int64 (value) == -1)
179 return (t->diff / MAX (1, t->count)) <= g_value_get_int64 (value);
183 timedur_get_value (gpointer test, GValue * value)
185 TimeDurTest *t = test;
187 g_value_set_int64 (value, t ? (t->diff / MAX (1, t->count)) : -1);
196 /* md5 information */
210 static void md5_process_block (const void *buffer, size_t len, MD5Test * ctx);
211 static void md5_read_ctx (MD5Test * ctx, gchar * result);
214 md5_get_spec (const GstTestInfo * info, gboolean compare_value)
217 return g_param_spec_string ("expected-md5", "expected md5",
218 "expected md5 of processing the whole data",
219 "---", G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
221 return g_param_spec_string ("md5", "md5",
222 "md5 of processing the whole data", "---", G_PARAM_READABLE);
226 /* This array contains the bytes used to pad the buffer to the next
227 64-byte boundary. (RFC 1321, 3.1: Step 1) */
228 static const guchar fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
231 /* Initialize structure containing state of computation.
232 (RFC 1321, 3.3: Step 3) */
234 md5_new (const GstTestInfo * info)
236 MD5Test *ctx = g_new (MD5Test, 1);
243 ctx->total[0] = ctx->total[1] = 0;
246 memset (ctx->result, 0, 33);
251 /* Process the remaining bytes in the internal buffer and the usual
252 prolog according to the standard and write the result to RESBUF.
254 IMPORTANT: On some systems it is required that RESBUF is correctly
255 aligned for a 32 bits value. */
257 md5_finish (gpointer test, GValue * value)
260 const gchar *str_val = g_value_get_string (value);
262 /* Take yet unprocessed bytes into account. */
263 guint32 bytes = ctx->buflen;
266 /* Now count remaining bytes. */
267 ctx->total[0] += bytes;
268 if (ctx->total[0] < bytes)
271 pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
272 memcpy (&ctx->buffer[bytes], fillbuf, pad);
274 /* Put the 64-bit file length in *bits* at the end of the buffer. */
275 *(guint32 *) & ctx->buffer[bytes + pad] = GUINT32_TO_LE (ctx->total[0] << 3);
276 *(guint32 *) & ctx->buffer[bytes + pad + 4] =
277 GUINT32_TO_LE ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
279 /* Process last bytes. */
280 md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
282 md5_read_ctx (ctx, ctx->result);
283 if (g_str_equal (str_val, "---"))
285 if (g_str_equal (str_val, ctx->result))
290 /* Put result from CTX in first 16 bytes following RESBUF. The result
291 must be in little endian byte order.
293 IMPORTANT: On some systems it is required that RESBUF is correctly
294 aligned for a 32 bits value. */
296 md5_read_ctx (MD5Test * ctx, gchar * result)
301 resbuf[0] = GUINT32_TO_LE (ctx->A);
302 resbuf[1] = GUINT32_TO_LE (ctx->B);
303 resbuf[2] = GUINT32_TO_LE (ctx->C);
304 resbuf[3] = GUINT32_TO_LE (ctx->D);
306 for (i = 0; i < 16; i++)
307 sprintf (result + i * 2, "%02x", ((guchar *) resbuf)[i]);
311 md5_add (gpointer test, GstBuffer * gstbuffer)
313 const void *buffer = GST_BUFFER_DATA (gstbuffer);
314 gsize len = GST_BUFFER_SIZE (gstbuffer);
317 /*const void aligned_buffer = buffer; */
319 /* When we already have some bits in our internal buffer concatenate
320 both inputs first. */
321 if (ctx->buflen != 0) {
322 gsize left_over = ctx->buflen;
323 gsize add = 128 - left_over > len ? len : 128 - left_over;
325 /* Only put full words in the buffer. */
326 /* Forcing alignment here appears to be only an optimization.
327 * The glibc source uses __alignof__, which seems to be a
328 * gratuitous usage of a GCC extension, when sizeof() will
329 * work fine. (And don't question the sanity of using
330 * sizeof(guint32) instead of 4. */
331 /* add -= add % __alignof__ (guint32); */
332 add -= add % sizeof (guint32);
334 memcpy (&ctx->buffer[left_over], buffer, add);
337 if (ctx->buflen > 64) {
338 md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
341 /* The regions in the following copy operation cannot overlap. */
342 memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], ctx->buflen);
345 buffer = (const char *) buffer + add;
349 /* Process available complete blocks. */
351 md5_process_block (buffer, len & ~63, ctx);
352 buffer = (const char *) buffer + (len & ~63);
356 /* Move remaining bytes in internal buffer. */
358 size_t left_over = ctx->buflen;
360 memcpy (&ctx->buffer[left_over], buffer, len);
362 if (left_over >= 64) {
363 md5_process_block (ctx->buffer, 64, ctx);
365 memcpy (ctx->buffer, &ctx->buffer[64], left_over);
367 ctx->buflen = left_over;
372 /* These are the four functions used in the four steps of the MD5 algorithm
373 and defined in the RFC 1321. The first function is a little bit optimized
374 (as found in Colin Plumbs public domain implementation). */
375 /* #define FF(b, c, d) ((b & c) | (~b & d)) */
376 #define FF(b, c, d) (d ^ (b & (c ^ d)))
377 #define FG(b, c, d) FF (d, b, c)
378 #define FH(b, c, d) (b ^ c ^ d)
379 #define FI(b, c, d) (c ^ (b | ~d))
382 md5_process_block (const void *buffer, size_t len, MD5Test * ctx)
384 /* Process LEN bytes of BUFFER, accumulating context into CTX.
385 It is assumed that LEN % 64 == 0. */
386 guint32 correct_words[16];
387 const guint32 *words = buffer;
388 size_t nwords = len / sizeof (guint32);
389 const guint32 *endp = words + nwords;
395 /* First increment the byte count. RFC 1321 specifies the possible
396 length of the file up to 2^64 bits. Here we only compute the
397 number of bytes. Do a double word increment. */
398 ctx->total[0] += len;
399 if (ctx->total[0] < len)
402 /* Process all bytes in the buffer with 64 bytes in each round of
404 while (words < endp) {
405 guint32 *cwp = correct_words;
411 /* First round: using the given function, the context and a constant
412 the next context is computed. Because the algorithms processing
413 unit is a 32-bit word and it is determined to work on words in
414 little endian byte order we perhaps have to change the byte order
415 before the computation. To reduce the work for the next steps
416 we store the swapped words in the array CORRECT_WORDS. */
418 #define OP(a, b, c, d, s, T) \
421 a += FF (b, c, d) + (*cwp++ = GUINT32_TO_LE (*words)) + T; \
428 /* It is unfortunate that C does not provide an operator for
429 cyclic rotation. Hope the C compiler is smart enough. */
430 #define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
432 /* Before we start, one word to the strange constants.
433 They are defined in RFC 1321 as
435 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
439 OP (A, B, C, D, 7, 0xd76aa478);
440 OP (D, A, B, C, 12, 0xe8c7b756);
441 OP (C, D, A, B, 17, 0x242070db);
442 OP (B, C, D, A, 22, 0xc1bdceee);
443 OP (A, B, C, D, 7, 0xf57c0faf);
444 OP (D, A, B, C, 12, 0x4787c62a);
445 OP (C, D, A, B, 17, 0xa8304613);
446 OP (B, C, D, A, 22, 0xfd469501);
447 OP (A, B, C, D, 7, 0x698098d8);
448 OP (D, A, B, C, 12, 0x8b44f7af);
449 OP (C, D, A, B, 17, 0xffff5bb1);
450 OP (B, C, D, A, 22, 0x895cd7be);
451 OP (A, B, C, D, 7, 0x6b901122);
452 OP (D, A, B, C, 12, 0xfd987193);
453 OP (C, D, A, B, 17, 0xa679438e);
454 OP (B, C, D, A, 22, 0x49b40821);
456 /* For the second to fourth round we have the possibly swapped words
457 in CORRECT_WORDS. Redefine the macro to take an additional first
458 argument specifying the function to use. */
460 #define OP(f, a, b, c, d, k, s, T) \
463 a += f (b, c, d) + correct_words[k] + T; \
470 OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
471 OP (FG, D, A, B, C, 6, 9, 0xc040b340);
472 OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
473 OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
474 OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
475 OP (FG, D, A, B, C, 10, 9, 0x02441453);
476 OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
477 OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
478 OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
479 OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
480 OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
481 OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
482 OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
483 OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
484 OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
485 OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
488 OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
489 OP (FH, D, A, B, C, 8, 11, 0x8771f681);
490 OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
491 OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
492 OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
493 OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
494 OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
495 OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
496 OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
497 OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
498 OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
499 OP (FH, B, C, D, A, 6, 23, 0x04881d05);
500 OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
501 OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
502 OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
503 OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
506 OP (FI, A, B, C, D, 0, 6, 0xf4292244);
507 OP (FI, D, A, B, C, 7, 10, 0x432aff97);
508 OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
509 OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
510 OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
511 OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
512 OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
513 OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
514 OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
515 OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
516 OP (FI, C, D, A, B, 6, 15, 0xa3014314);
517 OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
518 OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
519 OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
520 OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
521 OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
523 /* Add the starting values of the context. */
530 /* Put checksum in context given as argument. */
538 md5_get_value (gpointer test, GValue * value)
543 g_value_set_string (value, "---");
544 } else if (ctx->result[0] == 0) {
545 gchar *str = g_new (gchar, 33);
548 md5_read_ctx (ctx, str);
549 g_value_take_string (value, str);
551 g_value_set_string (value, ctx->result);
559 const GstTestInfo tests[] = {
560 {length_get_spec, length_new, length_add,
561 length_finish, length_get_value, g_free},
562 {buffer_count_get_spec, length_new, buffer_count_add,
563 length_finish, length_get_value, g_free},
564 {timedur_get_spec, timedur_new, timedur_add,
565 timedur_finish, timedur_get_value, g_free},
566 {md5_get_spec, md5_new, md5_add,
567 md5_finish, md5_get_value, g_free}