00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #ifdef HAVE_CONFIG_H
00020 #include "config.h"
00021 #endif
00022
00023 #include <stdlib.h>
00024 #include <string.h>
00025 #include <stdio.h>
00026
00027 #ifndef _MSC_VER
00028 #include <sys/param.h>
00029 #include <fcntl.h>
00030 #else
00031 #ifndef MAXPATHLEN
00032 #define MAXPATHLEN 255
00033 #endif
00034 #endif
00035
00036 #include <inttypes.h>
00037 #include <limits.h>
00038 #include <sys/time.h>
00039 #include "dvdnav/dvdnav.h"
00040 #include <dvdread/nav_types.h>
00041 #include <dvdread/ifo_types.h>
00042 #include "remap.h"
00043 #include "vm/decoder.h"
00044 #include "vm/vm.h"
00045 #include "dvdnav_internal.h"
00046
00047 struct block_s {
00048 int domain;
00049 int title;
00050 int program;
00051 unsigned long start_block;
00052 unsigned long end_block;
00053 };
00054
00055 struct remap_s {
00056 char *title;
00057 int maxblocks;
00058 int nblocks;
00059 int debug;
00060 struct block_s *blocks;
00061 };
00062
00063 static remap_t* remap_new( char *title) {
00064 remap_t *map = malloc( sizeof(remap_t));
00065 map->title = strdup(title);
00066 map->maxblocks = 0;
00067 map->nblocks = 0;
00068 map->blocks = NULL;
00069 map->debug = 0;
00070 return map;
00071 }
00072
00073 static int compare_block( block_t *a, block_t *b) {
00074
00075 if (a->domain < b->domain) {
00076 return -1;
00077 } else if (a->domain > b->domain) {
00078 return 1;
00079 }
00080
00081 if (a->title < b->title) {
00082 return -1;
00083 } else if (a->title > b->title) {
00084 return 1;
00085 }
00086
00087 if (a->program < b->program) {
00088 return -1;
00089 } else if (a->program > b->program) {
00090 return 1;
00091 }
00092
00093 if (a->end_block < b->start_block) {
00094 return -1;
00095 } else if (a->start_block > b->end_block) {
00096
00097
00098
00099
00100
00101 return 1;
00102 }
00103
00104 return 0;
00105 }
00106
00107 static block_t *findblock( remap_t *map, block_t *key) {
00108 int lb = 0;
00109 int ub = map->nblocks - 1;
00110 int mid;
00111 int res;
00112
00113 while (lb <= ub) {
00114 mid = lb + (ub - lb)/2;
00115 res = compare_block( key, &map->blocks[mid]);
00116 if (res < 0) {
00117 ub = mid-1;
00118 } else if (res > 0) {
00119 lb = mid+1;
00120 } else {
00121 return &map->blocks[mid];
00122 }
00123 }
00124 return NULL;
00125 }
00126
00127 static void mergeblock( block_t *b, block_t tmp) {
00128 if (tmp.start_block < b->start_block) b->start_block = tmp.start_block;
00129 if (tmp.end_block > b->end_block) b->end_block = tmp.end_block;
00130 }
00131
00132 static void remap_add_node( remap_t *map, block_t block) {
00133 block_t *b;
00134 int n;
00135 b = findblock( map, &block);
00136 if (b) {
00137
00138 mergeblock( b, block);
00139 } else {
00140
00141 if (map->nblocks >= map->maxblocks) {
00142 map->maxblocks += 20;
00143 map->blocks = realloc( map->blocks, sizeof( block_t)*map->maxblocks);
00144 }
00145 n = map->nblocks++;
00146 while (n > 0 && compare_block( &block, &map->blocks[ n-1]) < 0) {
00147 map->blocks[ n] = map->blocks[ n-1];
00148 n--;
00149 }
00150 map->blocks[ n] = block;
00151 }
00152 }
00153
00154 static int parseblock(char *buf, int *dom, int *tt, int *pg,
00155 unsigned long *start, unsigned long *end) {
00156 long tmp;
00157 char *tok;
00158 char *epos;
00159 char *marker[]={"domain", "title", "program", "start", "end"};
00160 int st = 0;
00161 tok = strtok( buf, " ");
00162 while (st < 5) {
00163 if (strcmp(tok, marker[st])) return -st-1000;
00164 tok = strtok( NULL, " ");
00165 if (!tok) return -st-2000;
00166 tmp = strtol( tok, &epos, 0);
00167 if (*epos != 0 && *epos != ',') return -st-3000;
00168 switch (st) {
00169 case 0:
00170 *dom = (int)tmp;
00171 break;
00172 case 1:
00173 *tt = (int)tmp;
00174 break;
00175 case 2:
00176 *pg = (int)tmp;
00177 break;
00178 case 3:
00179 *start = tmp;
00180 break;
00181 case 4:
00182 *end = tmp;
00183 break;
00184 }
00185 st++;
00186 tok = strtok( NULL, " ");
00187 }
00188 return st;
00189 }
00190
00191 remap_t* remap_loadmap( char *title) {
00192 char buf[160];
00193 char fname[MAXPATHLEN];
00194 char *home;
00195 int res;
00196 FILE *fp;
00197 block_t tmp;
00198 remap_t *map;
00199
00200 memset(&tmp, 0, sizeof(tmp));
00201
00202 home = getenv("HOME");
00203 if(!home) {
00204 fprintf(MSG_OUT, "libdvdnav: Unable to find home directory" );
00205 return NULL;
00206 }
00207 snprintf(fname, sizeof(fname), "%s/.dvdnav/%s.map", home, title);
00208
00209
00210 fp = fopen( fname, "r");
00211 if (!fp) {
00212 fprintf(MSG_OUT, "libdvdnav: Unable to find map file '%s'\n", fname);
00213 return NULL;
00214 }
00215
00216
00217 map = remap_new( title);
00218 while (fgets( buf, sizeof(buf), fp) != NULL) {
00219 if (buf[0] == '\n' || buf[0] == '#' || buf[0] == 0) continue;
00220 if (strncasecmp( buf, "debug", 5) == 0) {
00221 map->debug = 1;
00222 } else {
00223 res = parseblock( buf,
00224 &tmp.domain, &tmp.title, &tmp.program, &tmp.start_block, &tmp.end_block);
00225 if (res != 5) {
00226 fprintf(MSG_OUT, "libdvdnav: Ignoring map line (%d): %s\n", res, buf);
00227 continue;
00228 }
00229 remap_add_node( map, tmp);
00230 }
00231 }
00232 fclose(fp);
00233
00234 if (map->nblocks == 0 && map->debug == 0) {
00235 free(map);
00236 return NULL;
00237 }
00238 return map;
00239 }
00240
00241 unsigned long remap_block(
00242 remap_t *map, int domain, int title, int program,
00243 unsigned long cblock, unsigned long offset)
00244 {
00245 block_t key;
00246 block_t *b;
00247
00248 if (map->debug) {
00249 fprintf(MSG_OUT, "libdvdnav: %s: domain %d, title %d, program %d, start %lx, next %lx\n",
00250 map->title, domain, title, program, cblock, cblock+offset);
00251 }
00252
00253 key.domain = domain;
00254 key.title = title;
00255 key.program = program;
00256 key.start_block = key.end_block = cblock + offset;
00257 b = findblock( map, &key);
00258
00259 if (b) {
00260 if (map->debug) {
00261 fprintf(MSG_OUT, "libdvdnav: Redirected to %lx\n", b->end_block);
00262 }
00263 return b->end_block - cblock;
00264 }
00265 return offset;
00266 }