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