You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
k9copy/libdvdnav/remap.c

258 lines
6.2 KiB

/*
* This file is part of libdvdnav, a DVD navigation library.
*
* libdvdnav 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.
*
* libdvdnav 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
* $Id: remap.c,v 1.4 2003/08/25 21:51:40 f1rmb Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#ifndef _MSC_VER
#include <sys/param.h>
#include <sys/fcntl.h>
#else
#ifndef MAXPATHLEN
#define MAXPATHLEN 255
#endif
#endif /* _MSC_VER */
#include <assert.h>
#include "remap.h"
#include "dvdnav_internal.h"
struct block_s {
int domain;
int title;
int program;
unsigned long start_block;
unsigned long end_block;
};
struct remap_s {
char *title;
int maxblocks;
int nblocks;
int debug;
struct block_s *blocks;
};
static remap_t* remap_new( char *title) {
remap_t *map = malloc( sizeof(remap_t));
map->title = strdup(title);
map->maxblocks = 0;
map->nblocks = 0;
map->blocks = NULL;
map->debug = 0;
return map;
}
static int compare_block( block_t *a, block_t *b) {
/* returns -1 if a precedes b, 1 if a follows b, and 0 if a and b overlap */
if (a->domain < b->domain) {
return -1;
} else if (a->domain > b->domain) {
return 1;
}
if (a->title < b->title) {
return -1;
} else if (a->title > b->title) {
return 1;
}
if (a->program < b->program) {
return -1;
} else if (a->program > b->program) {
return 1;
}
if (a->end_block < b->start_block) {
return -1;
} else if (a->start_block > b->end_block) {
/*
* if a->start_block == b->end_block then the two regions
* aren't strictly overlapping, but they should be merged
* anyway since there are zero blocks between them
*/
return 1;
}
return 0;
}
static block_t *findblock( remap_t *map, block_t *key) {
int lb = 0;
int ub = map->nblocks - 1;
int mid;
int res;
while (lb <= ub) {
mid = lb + (ub - lb)/2;
res = compare_block( key, &map->blocks[mid]);
if (res < 0) {
ub = mid-1;
} else if (res > 0) {
lb = mid+1;
} else {
return &map->blocks[mid];
}
}
return NULL;
}
static void mergeblock( block_t *b, block_t tmp) {
if (tmp.start_block < b->start_block) b->start_block = tmp.start_block;
if (tmp.end_block > b->end_block) b->end_block = tmp.end_block;
}
static void remap_add_node( remap_t *map, block_t block) {
block_t *b;
int n;
b = findblock( map, &block);
if (b) {
/* overlaps an existing block */
mergeblock( b, block);
} else {
/* new block */
if (map->nblocks >= map->maxblocks) {
map->maxblocks += 20;
map->blocks = realloc( map->blocks, sizeof( block_t)*map->maxblocks);
}
n = map->nblocks++;
while (n > 0 && compare_block( &block, &map->blocks[ n-1]) < 0) {
map->blocks[ n] = map->blocks[ n-1];
n--;
}
map->blocks[ n] = block;
}
}
static int parseblock(char *buf, int *dom, int *tt, int *pg,
unsigned long *start, unsigned long *end) {
long tmp;
char *tok;
char *epos;
char *marker[]={"domain", "title", "program", "start", "end"};
int st = 0;
tok = strtok( buf, " ");
while (st < 5) {
if (strcmp(tok, marker[st])) return -st-1000;
tok = strtok( NULL, " ");
if (!tok) return -st-2000;
tmp = strtol( tok, &epos, 0);
if (*epos != 0 && *epos != ',') return -st-3000;
switch (st) {
case 0:
*dom = (int)tmp;
break;
case 1:
*tt = (int)tmp;
break;
case 2:
*pg = (int)tmp;
break;
case 3:
*start = tmp;
break;
case 4:
*end = tmp;
break;
}
st++;
tok = strtok( NULL, " ");
}
return st;
}
remap_t* remap_loadmap( char *title) {
char buf[160];
char *fname;
char *home;
int res;
int fname_len=0;
FILE *fp;
block_t tmp;
remap_t *map;
/* Build the map filename */
home = getenv("HOME"); assert(home);
/*strncpy(fname, home, sizeof(fname));
strncat(fname, "/.dvdnav/", sizeof(fname));
strncat(fname, title, sizeof(fname));
strncat(fname, ".map", sizeof(fname));
*/
fname_len = strlen(home)+strlen("/.dvdnav/")+strlen(title)+strlen(".map")+1;
fname = calloc(fname_len, sizeof(char));
snprintf(fname, fname_len, "%s%s%s%s", home, "/.dvdnav/", title, ".map");
/* Open the map file */
fp = fopen( fname, "r");
if (!fp) {
fprintf(MSG_OUT, "libdvdnav: Unable to find map file '%s'\n", fname);
return NULL;
}
/* Load the map file */
map = remap_new( title);
while (fgets( buf, sizeof(buf), fp) != NULL) {
if (buf[0] == '\n' || buf[0] == '#' || buf[0] == 0) continue;
if (strncasecmp( buf, "debug", 5) == 0) {
map->debug = 1;
} else {
res = parseblock( buf,
&tmp.domain, &tmp.title, &tmp.program, &tmp.start_block, &tmp.end_block);
if (res != 5) {
fprintf(MSG_OUT, "libdvdnav: Ignoring map line (%d): %s\n", res, buf);
continue;
}
remap_add_node( map, tmp);
}
}
free(fname);
if (map->nblocks == 0 && map->debug == 0) return NULL;
return map;
}
unsigned long remap_block(
remap_t *map, int domain, int title, int program,
unsigned long cblock, unsigned long offset)
{
block_t key;
block_t *b;
if (map->debug) {
fprintf(MSG_OUT, "libdvdnav: %s: domain %d, title %d, program %d, start %lx, next %lx\n",
map->title, domain, title, program, cblock, cblock+offset);
}
key.domain = domain;
key.title = title;
key.program = program;
key.start_block = key.end_block = cblock + offset;
b = findblock( map, &key);
if (b) {
if (map->debug) {
fprintf(MSG_OUT, "libdvdnav: Redirected to %lx\n", b->end_block);
}
return b->end_block - cblock;
}
return offset;
}