Anri-chan/Source/mp4nerf.c

From SDA Knowledge Base

< Anri-chan‎ | Source
Revision as of 10:12, 18 July 2007 by Ballofsnow (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
/*

  for disabling audio commentary tracks in MP4 streams

  author: DJ Grenola
  date: 17 July 2007
  license: none (public domain)
  target: win32 (MINGW), recommend using the free IDE from bloodshed.net
  version: beta 0.1

*/

#define LARGE_FILE_SUPPORT

#ifdef LARGE_FILE_SUPPORT
  /* not necessary for mingw/win32 but will probably become so if we start
     trying to compile it on linux and friends */
  #define _FILE_OFFSET_BITS 64
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* #define VERBOSE */

#define CHECKBYTES_LEN 8
#define CHECKBYTES     { 0x74, 0x6B, 0x68, 0x64, 0x00, 0x00, 0x00, 0x01 }
#define REPBYTES       { 0x74, 0x6B, 0x68, 0x64, 0x00, 0x00, 0x00, 0x00 }
#define NUM_TO_SKIP    2
#define BUFSIZE        1024*1024

#ifdef LARGE_FILE_SUPPORT
  #define FOPEN fopen64
  #define FSEEK fseeko64
  #define FTELL ftello64
  #define OFF_T off64_t
#else
  #define FOPEN fopen
  #define FSEEK fseek
  #define FTELL ftell
  #define OFF_T int
#endif

typedef long long int s64;

void usage(char *argv0);

unsigned char checkbytes[CHECKBYTES_LEN]=CHECKBYTES;
unsigned char repbytes[CHECKBYTES_LEN]=REPBYTES;
unsigned char buffer[BUFSIZE];

int main (int argc, char **argv) {
  FILE *f;
  unsigned int matches=0;
  unsigned int bufstart=0;
  unsigned int bytes_to_read;
  unsigned int error=0;
  s64 br;
  OFF_T pos=0,tmp64;
  char *fname=NULL;
  printf ("MP4 audio track disabler\n");
  printf ("beta 0.1, DJ Grenola\n\n");
  printf ("This software comes with no warranty.\n\n");
  if ((argc!=2 && argc!=3) || (argc==3 && strcmp(argv[1],"-x"))) {
    usage(argv[0]);
    return 0;
  }
  fname=argv[argc-1];
  if ((f=FOPEN(fname,"r+b"))==NULL) {
    printf ("[-] Failed to open file \"%s\".\n", fname);
    return 1;
  }
  printf ("[+] Using %u KiB chunks.\n", BUFSIZE/1024);
  printf ("[+] Scanning file \"%s\".\n", fname);
  while (~0) {
    int i;
    bytes_to_read=BUFSIZE-bufstart;
    br=fread(buffer+bufstart,1,bytes_to_read,f);
    pos+=br;
#ifdef VERBOSE
    printf ("[+] Read %llu bytes.\n", pos);
#endif
    for (i=0;i<br+bufstart;i++) {
      if (!memcmp(checkbytes,buffer+i,CHECKBYTES_LEN)) {
        matches++;
        printf ("[+] Match at offset 0x%0llx", pos-br+(i-bufstart));
        if (argc==2) /* dummy mode */
          printf (", no action taken.\n");
        else {
          if (matches<=NUM_TO_SKIP)
            printf (", ignored.\n");
          else {
            printf (", attempting overwrite ...\n");
            if (matches>NUM_TO_SKIP) {
              /* FIXME: this is kind of dodgy because I don't know if off64_t
                 can be relied upon to be signed ... it works now, but in the
                 future ? */
              tmp64=-br+(i-bufstart);
              if (FSEEK(f,pos+tmp64,SEEK_SET)==-1) {
                error=3;
                printf ("[-] Error seeking to offset.\n");
                goto lbl_end;
              }
              if (fwrite(repbytes,1,CHECKBYTES_LEN,f) != CHECKBYTES_LEN) {
                error=4;
                printf ("[-] Error writing replacement string.\n");
                goto lbl_end;
              }
              /* put file pointer back (if necessary) */
              if (br==bytes_to_read) {
                if (FSEEK(f,pos,SEEK_SET)==-1) {
                  error=5;
                  printf ("[-] Error seeking to original position.\n");
                  goto lbl_end;
                }
              }
              printf ("[+] Replaced successfully.\n");
            }
          }
        }
      }
    }
    bufstart=CHECKBYTES_LEN-1;
    memmove(buffer,buffer+(BUFSIZE-(CHECKBYTES_LEN-1)),CHECKBYTES_LEN-1);
    if (br!=bytes_to_read)
      break;
  }
  lbl_end:
  if (ferror(f) || error) {
    /* FIXME: actually report some sort of useful error instead */
    printf ("[-] Erk. Something went wrong.\n");
    fclose(f);
    return error?error:2;
  }
  fclose(f);
  return 0;
}

void usage(char *argv0) {
  printf ("Usage: %s [-x] <MP4 file>\n\n", argv0);
  printf ("By default, the file is scanned and no changes are made.\n");
  printf ("Use the -x switch to force changes to the file.\n");
}
Personal tools