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.
44 length_get_spec (const GstTestInfo * info, gboolean compare_value)
47 return g_param_spec_int64 ("expected-length", "expected length",
48 "expected length of stream", -1, G_MAXINT64, -1,
49 G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
51 return g_param_spec_int64 ("length", "length", "length of stream",
52 -1, G_MAXINT64, -1, G_PARAM_READABLE);
57 length_new (const GstTestInfo * info)
59 return g_new0 (LengthTest, 1);
63 length_add (gpointer test, GstBuffer * buffer)
67 t->value += GST_BUFFER_SIZE (buffer);
71 length_finish (gpointer test, GValue * value)
75 if (g_value_get_int64 (value) == -1)
78 return t->value == g_value_get_int64 (value);
82 length_get_value (gpointer test, GValue * value)
86 g_value_set_int64 (value, t ? t->value : -1);
94 buffer_count_get_spec (const GstTestInfo * info, gboolean compare_value)
97 return g_param_spec_int64 ("expected-buffer-count", "expected buffer count",
98 "expected number of buffers in stream",
99 -1, G_MAXINT64, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
101 return g_param_spec_int64 ("buffer-count", "buffer count",
102 "number of buffers in stream", -1, G_MAXINT64, -1, G_PARAM_READABLE);
107 buffer_count_add (gpointer test, GstBuffer * buffer)
109 LengthTest *t = test;
115 *** TIMESTAMP / DURATION MATCHING ***
122 GstClockTime expected;
127 timedur_get_spec (const GstTestInfo * info, gboolean compare_value)
130 return g_param_spec_int64 ("allowed-timestamp-deviation",
131 "allowed timestamp deviation",
132 "allowed average difference in usec between timestamp of next buffer "
133 "and expected timestamp from analyzing last buffer",
134 -1, G_MAXINT64, -1, G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
136 return g_param_spec_int64 ("timestamp-deviation",
137 "timestamp deviation",
138 "average difference in usec between timestamp of next buffer "
139 "and expected timestamp from analyzing last buffer",
140 -1, G_MAXINT64, -1, G_PARAM_READABLE);
145 timedur_new (const GstTestInfo * info)
147 TimeDurTest *ret = g_new0 (TimeDurTest, 1);
149 ret->expected = GST_CLOCK_TIME_NONE;
155 timedur_add (gpointer test, GstBuffer * buffer)
157 TimeDurTest *t = test;
159 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
160 GST_CLOCK_TIME_IS_VALID (t->expected)) {
161 t->diff += labs (GST_BUFFER_TIMESTAMP (buffer) - t->expected);
164 if (GST_BUFFER_TIMESTAMP_IS_VALID (buffer) &&
165 GST_BUFFER_DURATION_IS_VALID (buffer)) {
166 t->expected = GST_BUFFER_TIMESTAMP (buffer) + GST_BUFFER_DURATION (buffer);
168 t->expected = GST_CLOCK_TIME_NONE;
173 timedur_finish (gpointer test, GValue * value)
175 TimeDurTest *t = test;
177 if (g_value_get_int64 (value) == -1)
180 return (t->diff / MAX (1, t->count)) <= g_value_get_int64 (value);
184 timedur_get_value (gpointer test, GValue * value)
186 TimeDurTest *t = test;
188 g_value_set_int64 (value, t ? (t->diff / MAX (1, t->count)) : -1);
197 /* md5 information */
211 static void md5_process_block (const void *buffer, size_t len, MD5Test * ctx);
212 static void md5_read_ctx (MD5Test * ctx, gchar * result);
215 md5_get_spec (const GstTestInfo * info, gboolean compare_value)
218 return g_param_spec_string ("expected-md5", "expected md5",
219 "expected md5 of processing the whole data",
220 "---", G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
222 return g_param_spec_string ("md5", "md5",
223 "md5 of processing the whole data", "---", G_PARAM_READABLE);
227 /* This array contains the bytes used to pad the buffer to the next
228 64-byte boundary. (RFC 1321, 3.1: Step 1) */
229 static const guchar fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
232 /* Initialize structure containing state of computation.
233 (RFC 1321, 3.3: Step 3) */
235 md5_new (const GstTestInfo * info)
237 MD5Test *ctx = g_new (MD5Test, 1);
244 ctx->total[0] = ctx->total[1] = 0;
247 memset (ctx->result, 0, 33);
252 /* Process the remaining bytes in the internal buffer and the usual
253 prolog according to the standard and write the result to RESBUF.
255 IMPORTANT: On some systems it is required that RESBUF is correctly
256 aligned for a 32 bits value. */
258 md5_finish (gpointer test, GValue * value)
261 const gchar *str_val = g_value_get_string (value);
263 /* Take yet unprocessed bytes into account. */
264 guint32 bytes = ctx->buflen;
267 /* Now count remaining bytes. */
268 ctx->total[0] += bytes;
269 if (ctx->total[0] < bytes)
272 pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes;
273 memcpy (&ctx->buffer[bytes], fillbuf, pad);
275 /* Put the 64-bit file length in *bits* at the end of the buffer. */
276 *(guint32 *) & ctx->buffer[bytes + pad] = GUINT32_TO_LE (ctx->total[0] << 3);
277 *(guint32 *) & ctx->buffer[bytes + pad + 4] =
278 GUINT32_TO_LE ((ctx->total[1] << 3) | (ctx->total[0] >> 29));
280 /* Process last bytes. */
281 md5_process_block (ctx->buffer, bytes + pad + 8, ctx);
283 md5_read_ctx (ctx, ctx->result);
284 if (g_str_equal (str_val, "---"))
286 if (g_str_equal (str_val, ctx->result))
291 /* Put result from CTX in first 16 bytes following RESBUF. The result
292 must be in little endian byte order.
294 IMPORTANT: On some systems it is required that RESBUF is correctly
295 aligned for a 32 bits value. */
297 md5_read_ctx (MD5Test * ctx, gchar * result)
302 resbuf[0] = GUINT32_TO_LE (ctx->A);
303 resbuf[1] = GUINT32_TO_LE (ctx->B);
304 resbuf[2] = GUINT32_TO_LE (ctx->C);
305 resbuf[3] = GUINT32_TO_LE (ctx->D);
307 for (i = 0; i < 16; i++)
308 sprintf (result + i * 2, "%02x", ((guchar *) resbuf)[i]);
312 md5_add (gpointer test, GstBuffer * gstbuffer)
314 const void *buffer = GST_BUFFER_DATA (gstbuffer);
315 gsize len = GST_BUFFER_SIZE (gstbuffer);
318 /*const void aligned_buffer = buffer; */
320 /* When we already have some bits in our internal buffer concatenate
321 both inputs first. */
322 if (ctx->buflen != 0) {
323 gsize left_over = ctx->buflen;
324 gsize add = 128 - left_over > len ? len : 128 - left_over;
326 /* Only put full words in the buffer. */
327 /* Forcing alignment here appears to be only an optimization.
328 * The glibc source uses __alignof__, which seems to be a
329 * gratuitous usage of a GCC extension, when sizeof() will
330 * work fine. (And don't question the sanity of using
331 * sizeof(guint32) instead of 4. */
332 /* add -= add % __alignof__ (guint32); */
333 add -= add % sizeof (guint32);
335 memcpy (&ctx->buffer[left_over], buffer, add);
338 if (ctx->buflen > 64) {
339 md5_process_block (ctx->buffer, ctx->buflen & ~63, ctx);
342 /* The regions in the following copy operation cannot overlap. */
343 memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], ctx->buflen);
346 buffer = (const char *) buffer + add;
350 /* Process available complete blocks. */
352 md5_process_block (buffer, len & ~63, ctx);
353 buffer = (const char *) buffer + (len & ~63);
357 /* Move remaining bytes in internal buffer. */
359 size_t left_over = ctx->buflen;
361 memcpy (&ctx->buffer[left_over], buffer, len);
363 if (left_over >= 64) {
364 md5_process_block (ctx->buffer, 64, ctx);
366 memcpy (ctx->buffer, &ctx->buffer[64], left_over);
368 ctx->buflen = left_over;
373 /* These are the four functions used in the four steps of the MD5 algorithm
374 and defined in the RFC 1321. The first function is a little bit optimized
375 (as found in Colin Plumbs public domain implementation). */
376 /* #define FF(b, c, d) ((b & c) | (~b & d)) */
377 #define FF(b, c, d) (d ^ (b & (c ^ d)))
378 #define FG(b, c, d) FF (d, b, c)
379 #define FH(b, c, d) (b ^ c ^ d)
380 #define FI(b, c, d) (c ^ (b | ~d))
383 md5_process_block (const void *buffer, size_t len, MD5Test * ctx)
385 /* Process LEN bytes of BUFFER, accumulating context into CTX.
386 It is assumed that LEN % 64 == 0. */
387 guint32 correct_words[16];
388 const guint32 *words = buffer;
389 size_t nwords = len / sizeof (guint32);
390 const guint32 *endp = words + nwords;
396 /* First increment the byte count. RFC 1321 specifies the possible
397 length of the file up to 2^64 bits. Here we only compute the
398 number of bytes. Do a double word increment. */
399 ctx->total[0] += len;
400 if (ctx->total[0] < len)
403 /* Process all bytes in the buffer with 64 bytes in each round of
405 while (words < endp) {
406 guint32 *cwp = correct_words;
412 /* First round: using the given function, the context and a constant
413 the next context is computed. Because the algorithms processing
414 unit is a 32-bit word and it is determined to work on words in
415 little endian byte order we perhaps have to change the byte order
416 before the computation. To reduce the work for the next steps
417 we store the swapped words in the array CORRECT_WORDS. */
419 #define OP(a, b, c, d, s, T) \
422 a += FF (b, c, d) + (*cwp++ = GUINT32_TO_LE (*words)) + T; \
429 /* It is unfortunate that C does not provide an operator for
430 cyclic rotation. Hope the C compiler is smart enough. */
431 #define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
433 /* Before we start, one word to the strange constants.
434 They are defined in RFC 1321 as
436 T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
440 OP (A, B, C, D, 7, 0xd76aa478);
441 OP (D, A, B, C, 12, 0xe8c7b756);
442 OP (C, D, A, B, 17, 0x242070db);
443 OP (B, C, D, A, 22, 0xc1bdceee);
444 OP (A, B, C, D, 7, 0xf57c0faf);
445 OP (D, A, B, C, 12, 0x4787c62a);
446 OP (C, D, A, B, 17, 0xa8304613);
447 OP (B, C, D, A, 22, 0xfd469501);
448 OP (A, B, C, D, 7, 0x698098d8);
449 OP (D, A, B, C, 12, 0x8b44f7af);
450 OP (C, D, A, B, 17, 0xffff5bb1);
451 OP (B, C, D, A, 22, 0x895cd7be);
452 OP (A, B, C, D, 7, 0x6b901122);
453 OP (D, A, B, C, 12, 0xfd987193);
454 OP (C, D, A, B, 17, 0xa679438e);
455 OP (B, C, D, A, 22, 0x49b40821);
457 /* For the second to fourth round we have the possibly swapped words
458 in CORRECT_WORDS. Redefine the macro to take an additional first
459 argument specifying the function to use. */
461 #define OP(f, a, b, c, d, k, s, T) \
464 a += f (b, c, d) + correct_words[k] + T; \
471 OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
472 OP (FG, D, A, B, C, 6, 9, 0xc040b340);
473 OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
474 OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
475 OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
476 OP (FG, D, A, B, C, 10, 9, 0x02441453);
477 OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
478 OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
479 OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
480 OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
481 OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
482 OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
483 OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
484 OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
485 OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
486 OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
489 OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
490 OP (FH, D, A, B, C, 8, 11, 0x8771f681);
491 OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
492 OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
493 OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
494 OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
495 OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
496 OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
497 OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
498 OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
499 OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
500 OP (FH, B, C, D, A, 6, 23, 0x04881d05);
501 OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
502 OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
503 OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
504 OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
507 OP (FI, A, B, C, D, 0, 6, 0xf4292244);
508 OP (FI, D, A, B, C, 7, 10, 0x432aff97);
509 OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
510 OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
511 OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
512 OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
513 OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
514 OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
515 OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
516 OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
517 OP (FI, C, D, A, B, 6, 15, 0xa3014314);
518 OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
519 OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
520 OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
521 OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
522 OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
524 /* Add the starting values of the context. */
531 /* Put checksum in context given as argument. */
539 md5_get_value (gpointer test, GValue * value)
544 g_value_set_string (value, "---");
545 } else if (ctx->result[0] == 0) {
546 gchar *str = g_new (gchar, 33);
549 md5_read_ctx (ctx, str);
550 g_value_take_string (value, str);
552 g_value_set_string (value, ctx->result);
560 const GstTestInfo tests[] = {
561 {length_get_spec, length_new, length_add,
562 length_finish, length_get_value, g_free},
563 {buffer_count_get_spec, length_new, buffer_count_add,
564 length_finish, length_get_value, g_free},
565 {timedur_get_spec, timedur_new, timedur_add,
566 timedur_finish, timedur_get_value, g_free},
567 {md5_get_spec, md5_new, md5_add,
568 md5_finish, md5_get_value, g_free}