Fix vf_tcdump's compilation
[mplayer/kovensky.git] / libdvdnav / remap.c
blob3e55c63c055f1f0e052beff0cc1721da15d300d3
1 /*
2 * This file is part of libdvdnav, a DVD navigation library.
4 * libdvdnav is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * libdvdnav is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with libdvdnav; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
27 #ifndef _MSC_VER
28 #include <sys/param.h>
29 #include <sys/fcntl.h>
30 #else
31 #ifndef MAXPATHLEN
32 #define MAXPATHLEN 255
33 #endif
34 #endif /* _MSC_VER */
36 #include <inttypes.h>
37 #include <limits.h>
38 #include <sys/time.h>
39 #include "dvdnav/dvdnav.h"
40 #include <dvdread/nav_types.h>
41 #include <dvdread/ifo_types.h>
42 #include "remap.h"
43 #include "vm/decoder.h"
44 #include "vm/vm.h"
45 #include "dvdnav_internal.h"
47 struct block_s {
48 int domain;
49 int title;
50 int program;
51 unsigned long start_block;
52 unsigned long end_block;
55 struct remap_s {
56 char *title;
57 int maxblocks;
58 int nblocks;
59 int debug;
60 struct block_s *blocks;
63 static remap_t* remap_new( char *title) {
64 remap_t *map = malloc( sizeof(remap_t));
65 map->title = strdup(title);
66 map->maxblocks = 0;
67 map->nblocks = 0;
68 map->blocks = NULL;
69 map->debug = 0;
70 return map;
73 static int compare_block( block_t *a, block_t *b) {
74 /* returns -1 if a precedes b, 1 if a follows b, and 0 if a and b overlap */
75 if (a->domain < b->domain) {
76 return -1;
77 } else if (a->domain > b->domain) {
78 return 1;
81 if (a->title < b->title) {
82 return -1;
83 } else if (a->title > b->title) {
84 return 1;
87 if (a->program < b->program) {
88 return -1;
89 } else if (a->program > b->program) {
90 return 1;
93 if (a->end_block < b->start_block) {
94 return -1;
95 } else if (a->start_block > b->end_block) {
97 * if a->start_block == b->end_block then the two regions
98 * aren't strictly overlapping, but they should be merged
99 * anyway since there are zero blocks between them
101 return 1;
104 return 0;
107 static block_t *findblock( remap_t *map, block_t *key) {
108 int lb = 0;
109 int ub = map->nblocks - 1;
110 int mid;
111 int res;
113 while (lb <= ub) {
114 mid = lb + (ub - lb)/2;
115 res = compare_block( key, &map->blocks[mid]);
116 if (res < 0) {
117 ub = mid-1;
118 } else if (res > 0) {
119 lb = mid+1;
120 } else {
121 return &map->blocks[mid];
124 return NULL;
127 static void mergeblock( block_t *b, block_t tmp) {
128 if (tmp.start_block < b->start_block) b->start_block = tmp.start_block;
129 if (tmp.end_block > b->end_block) b->end_block = tmp.end_block;
132 static void remap_add_node( remap_t *map, block_t block) {
133 block_t *b;
134 int n;
135 b = findblock( map, &block);
136 if (b) {
137 /* overlaps an existing block */
138 mergeblock( b, block);
139 } else {
140 /* new block */
141 if (map->nblocks >= map->maxblocks) {
142 map->maxblocks += 20;
143 map->blocks = realloc( map->blocks, sizeof( block_t)*map->maxblocks);
145 n = map->nblocks++;
146 while (n > 0 && compare_block( &block, &map->blocks[ n-1]) < 0) {
147 map->blocks[ n] = map->blocks[ n-1];
148 n--;
150 map->blocks[ n] = block;
154 static int parseblock(char *buf, int *dom, int *tt, int *pg,
155 unsigned long *start, unsigned long *end) {
156 long tmp;
157 char *tok;
158 char *epos;
159 char *marker[]={"domain", "title", "program", "start", "end"};
160 int st = 0;
161 tok = strtok( buf, " ");
162 while (st < 5) {
163 if (strcmp(tok, marker[st])) return -st-1000;
164 tok = strtok( NULL, " ");
165 if (!tok) return -st-2000;
166 tmp = strtol( tok, &epos, 0);
167 if (*epos != 0 && *epos != ',') return -st-3000;
168 switch (st) {
169 case 0:
170 *dom = (int)tmp;
171 break;
172 case 1:
173 *tt = (int)tmp;
174 break;
175 case 2:
176 *pg = (int)tmp;
177 break;
178 case 3:
179 *start = tmp;
180 break;
181 case 4:
182 *end = tmp;
183 break;
185 st++;
186 tok = strtok( NULL, " ");
188 return st;
191 remap_t* remap_loadmap( char *title) {
192 char buf[160];
193 char fname[MAXPATHLEN];
194 char *home;
195 int res;
196 FILE *fp;
197 block_t tmp;
198 remap_t *map;
200 memset(&tmp, 0, sizeof(tmp));
201 /* Build the map filename */
202 home = getenv("HOME");
203 if(!home) {
204 fprintf(MSG_OUT, "libdvdnav: Unable to find home directory" );
205 return NULL;
207 snprintf(fname, sizeof(fname), "%s/.dvdnav/%s.map", home, title);
209 /* Open the map file */
210 fp = fopen( fname, "r");
211 if (!fp) {
212 fprintf(MSG_OUT, "libdvdnav: Unable to find map file '%s'\n", fname);
213 return NULL;
216 /* Load the map file */
217 map = remap_new( title);
218 while (fgets( buf, sizeof(buf), fp) != NULL) {
219 if (buf[0] == '\n' || buf[0] == '#' || buf[0] == 0) continue;
220 if (strncasecmp( buf, "debug", 5) == 0) {
221 map->debug = 1;
222 } else {
223 res = parseblock( buf,
224 &tmp.domain, &tmp.title, &tmp.program, &tmp.start_block, &tmp.end_block);
225 if (res != 5) {
226 fprintf(MSG_OUT, "libdvdnav: Ignoring map line (%d): %s\n", res, buf);
227 continue;
229 remap_add_node( map, tmp);
232 fclose(fp);
234 if (map->nblocks == 0 && map->debug == 0) {
235 free(map);
236 return NULL;
238 return map;
241 unsigned long remap_block(
242 remap_t *map, int domain, int title, int program,
243 unsigned long cblock, unsigned long offset)
245 block_t key;
246 block_t *b;
248 if (map->debug) {
249 fprintf(MSG_OUT, "libdvdnav: %s: domain %d, title %d, program %d, start %lx, next %lx\n",
250 map->title, domain, title, program, cblock, cblock+offset);
253 key.domain = domain;
254 key.title = title;
255 key.program = program;
256 key.start_block = key.end_block = cblock + offset;
257 b = findblock( map, &key);
259 if (b) {
260 if (map->debug) {
261 fprintf(MSG_OUT, "libdvdnav: Redirected to %lx\n", b->end_block);
263 return b->end_block - cblock;
265 return offset;