MythTV  0.26-pre
remap.c
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends