|
MythTV
0.26-pre
|
00001 /* 00002 * This file is part of libdvdnav, a DVD navigation library. 00003 * 00004 * libdvdnav is free software; you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation; either version 2 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * libdvdnav is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License along 00015 * with libdvdnav; if not, write to the Free Software Foundation, Inc., 00016 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 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 /* _MSC_VER */ 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 /* returns -1 if a precedes b, 1 if a follows b, and 0 if a and b overlap */ 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 * if a->start_block == b->end_block then the two regions 00098 * aren't strictly overlapping, but they should be merged 00099 * anyway since there are zero blocks between them 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 /* overlaps an existing block */ 00138 mergeblock( b, block); 00139 } else { 00140 /* new block */ 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 /* Build the map filename */ 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 /* Open the map file */ 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 /* Load the map file */ 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 }
1.7.6.1