diff options
Diffstat (limited to 'src/corrupt_mpeg2.c')
-rw-r--r-- | src/corrupt_mpeg2.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/src/corrupt_mpeg2.c b/src/corrupt_mpeg2.c new file mode 100644 index 0000000..86a71c6 --- /dev/null +++ b/src/corrupt_mpeg2.c @@ -0,0 +1,346 @@ +/* + * corrupt_mpeg2.c + * Copyright (C) 2000-2002 Michel Lespinasse <walken@zoy.org> + * Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> + * + * This file is part of mpeg2dec, a free MPEG-2 video stream decoder. + * See http://libmpeg2.sourceforge.net/ for updates. + * + * mpeg2dec is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * mpeg2dec is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <string.h> +#include <errno.h> +#include <getopt.h> +#include <ctype.h> +#ifdef HAVE_IO_H +#include <fcntl.h> +#include <io.h> +#endif +#include <inttypes.h> + +static FILE * in_file; +static FILE * seed_file; +static int seed_loaded = 0; +static uint32_t rsl[55]; +static int rsl_i = -1; + +typedef struct { + uint32_t p, q[8], r; +} randbyte_t; + +#define CORRUPT_RANDOM 0 +#define CORRUPT_VALUE 1 + +typedef struct corrupt_s { + int type; + int chunk_start, chunk_stop; + int bit_start, bit_stop; + union { + randbyte_t prob; + } u; + struct corrupt_s * next; + uint8_t mask; +} corrupt_t; + +#define CORRUPT_LIST_SIZE 10 +static corrupt_t corrupt_list[10]; +static int corrupt_list_index = 0; +static corrupt_t * corrupt_head = NULL; +static int current_chunk = -1, current_bit = 0, target_bit = 0x7fffffff; + +static inline uint32_t fastrand (void) +{ + if (++rsl_i == 55) rsl_i = 0; + return rsl[rsl_i] += rsl[(rsl_i < 31) ? rsl_i + 24 : rsl_i - 31]; +} + +static uint32_t clip (double p) +{ + return (p < 0) ? 0 : ((p >= 1) ? 0xffffffff : (uint32_t)(p*4294967296.0)); +} + +static void randbyte_init (double p, randbyte_t * rnd) +{ + double q, r; + int i; + + rnd->p = clip (p); + r = 1; + for (i = 0; i < 8; i++) { + r *= 1 - p; + q = p / (1 - r); + rnd->q[i] = clip (q); + } + rnd->r = clip (1 - r); +} + +static inline uint8_t randbyte (const randbyte_t * const rnd) +{ + int i, j; + + if (fastrand () > rnd->r || rnd->r == 0) + return 0; + + i = 7; j = 0; + do + if (fastrand () <= (j ? rnd->p : rnd->q[i])) + j |= 1 << i; + while (i--); + return j; +} + +static void print_usage (char ** argv) +{ + fprintf (stderr, "usage: %s [-h] [-l <seed>] [-s <seedfile>] \\\n" + "\t\t[-r prob[,restrict] [-v prob[,restrict]] <file>\n" + "\t-h\tdisplay help\n" + "\t-l load seed\n" + "\t-s save seed file\n" + "\t-r random corruption\n" + "\t-v random value\n" + "restrict: chunk[-endchunk][,bit[-endbit]]\n", argv[0]); + + exit (1); +} + +static void corrupt_arg (corrupt_t * corrupt, int type, char * s, char ** argv) +{ + corrupt->type = type; + if (! *s) + s = (char *)",0-0xff,0-"; + else if (*s != ',' || !isdigit (s[1])) + print_usage (argv); + corrupt->chunk_start = strtol (s + 1, &s, 0); + if (*s != '-') + corrupt->chunk_stop = corrupt->chunk_start; + else if (isdigit (* ++s)) + corrupt->chunk_stop = strtol (s, &s, 0); + else + print_usage (argv); + if (! *s) + s = (char *)",32-"; + else if (*s != ',' || !isdigit (s[1])) + print_usage (argv); + corrupt->bit_start = strtol (s + 1, &s, 0); + if (*s != '-') + corrupt->bit_stop = corrupt->bit_start; + else if (isdigit (* ++s)) + corrupt->bit_stop = strtol (s, &s, 0); + else + corrupt->bit_stop = 0x7ffffffe; + if (corrupt->chunk_start < 0 || + corrupt->chunk_start > corrupt->chunk_stop || + corrupt->chunk_stop >= 0x1000 || + corrupt->bit_start < 0 || corrupt->bit_start > corrupt->bit_stop || *s) + print_usage (argv); + if (corrupt->chunk_stop < 0x100) { + corrupt->chunk_start <<= 4; + corrupt->chunk_stop = (corrupt->chunk_stop << 4) | 0xf; + } +} + +static void handle_args (int argc, char ** argv) +{ + int c; + double prob; + char * s; + corrupt_t * corrupt; + + while ((c = getopt (argc, argv, "hl:s:r:v:")) != -1) + switch (c) { + case 'l': + if (seed_file || seed_loaded) + print_usage (argv); + if (sscanf (optarg, "%08x%08x%08x%08x", + rsl, rsl+1, rsl+2, rsl+3) != 4) + print_usage (argv); + seed_loaded = 1; + break; + + case 's': + if (seed_file || seed_loaded) + print_usage (argv); + seed_file = fopen (optarg, "wt"); + if (!seed_file) + print_usage (argv); + break; + + case 'r': + prob = strtod (optarg, &s); + if (prob < 0 || prob > 1 || + corrupt_list_index == CORRUPT_LIST_SIZE) + print_usage (argv); + corrupt = corrupt_list + corrupt_list_index++; + corrupt_arg (corrupt, CORRUPT_RANDOM, s, argv); + randbyte_init (prob, &corrupt->u.prob); + break; + + case 'v': + prob = strtod (optarg, &s); + if (prob < 0 || prob > 1 || + corrupt_list_index == CORRUPT_LIST_SIZE) + print_usage (argv); + corrupt = corrupt_list + corrupt_list_index++; + corrupt_arg (corrupt, CORRUPT_VALUE, s, argv); + randbyte_init (prob, &corrupt->u.prob); + break; + + default: + print_usage (argv); + } + + if (optind < argc) { + in_file = fopen (argv[optind], "rb"); + if (!in_file) { + fprintf (stderr, "%s - could not open file %s\n", strerror (errno), + argv[optind]); + exit (1); + } + } else + in_file = stdin; + + if (!seed_file && !seed_loaded) + seed_file = fopen ("seed", "wt"); +} + +static void update_corrupt_list (void) +{ + corrupt_t * corrupt; + corrupt_t ** corrupt_link; + + corrupt_link = &corrupt_head; + target_bit = 0x7fffffff; + for (corrupt = corrupt_list; + corrupt < corrupt_list + corrupt_list_index; corrupt++) + if (corrupt->chunk_start <= current_chunk && + corrupt->chunk_stop >= current_chunk && + corrupt->bit_stop >= current_bit) { + if (corrupt->bit_start >= current_bit + 8) { + if (corrupt->bit_start <= target_bit) + target_bit = corrupt->bit_start & ~7; + } else { + *corrupt_link = corrupt; + corrupt_link = &corrupt->next; + if (corrupt->bit_stop >= current_bit + 7) { + corrupt->mask = 0xff; + if (corrupt->bit_stop <= target_bit) + target_bit = (corrupt->bit_stop + 1) & ~7; + } else { + corrupt->mask = -1 << (7 - (corrupt->bit_stop & 7)); + target_bit = current_bit + 8; + } + if (corrupt->bit_start > current_bit) { + corrupt->mask &= 0xff >> (corrupt->bit_start & 7); + target_bit = current_bit + 8; + } + } + } + *corrupt_link = NULL; +} + +static void corrupt (uint8_t * ptr) +{ + corrupt_t * corrupt_ptr; + + if (ptr[0] == 0 && ptr[1] == 0 && ptr[2] == 1) { + current_chunk = (ptr[3] << 4) | (ptr[4] >> 4); + current_bit = 0; + update_corrupt_list (); + } else if (current_bit == target_bit) + update_corrupt_list (); + + current_bit += 8; + + for (corrupt_ptr = corrupt_head; corrupt_ptr; corrupt_ptr = corrupt_ptr->next) + switch (corrupt_ptr->type) { + case CORRUPT_RANDOM: + *ptr ^= randbyte (&corrupt_ptr->u.prob) & corrupt_ptr->mask; + break; + case CORRUPT_VALUE: + *ptr = ((*ptr & ~corrupt_ptr->mask) | + (randbyte (&corrupt_ptr->u.prob) & corrupt_ptr->mask)); + break; + } +} + +static void corrupt_loop (void) +{ +#define BUFFER_SIZE 4096 + static uint8_t buffer1[BUFFER_SIZE + 4]; + static uint8_t buffer2[BUFFER_SIZE + 4]; + static uint8_t terminator[4] = {0xff, 0xff, 0xff, 0xff}; + + uint8_t * buf; + uint8_t * end; + uint8_t * current; + + buf = buffer1; + end = buf + fread (buf, 1, BUFFER_SIZE, in_file); + + while (end == buf + BUFFER_SIZE) { + uint8_t * lastbuf; + uint8_t * lastbuf_end; + + lastbuf = buf; lastbuf_end = buf + BUFFER_SIZE; + buf = (buf == buffer1) ? buffer2 : buffer1; + memcpy (buf, terminator, 4); + end = buf + fread (buf, 1, BUFFER_SIZE, in_file); + memcpy (lastbuf_end, buf, 4); + for (current = lastbuf; current < lastbuf_end; current++) + corrupt (current); + fwrite (lastbuf, BUFFER_SIZE, 1, stdout); + } + + memcpy (end, terminator, 4); + for (current = buf; current < end; current++) + corrupt (current); + fwrite (buf, end - buf, 1, stdout); +} + +int main (int argc, char ** argv) +{ + int i; + +#ifdef HAVE_IO_H + setmode (fileno (stdin), O_BINARY); + setmode (fileno (stdout), O_BINARY); +#endif + + handle_args (argc, argv); + + if (!seed_loaded) { + srand (time (NULL)); + for (i = 0; i < 4; i++) + rsl[i] = rand (); + fprintf (seed_file, "%08x%08x%08x%08x\n", + rsl[0], rsl[1], rsl[2], rsl[3]); + fclose (seed_file); + } + + for (i = 4; i < 55; i++) + rsl[i] = 0; + for (i = 0; i < 1000; i++) + fastrand (); + + corrupt_loop (); + + return 0; +} |