~ubuntu-branches/ubuntu/wily/regionset/wily

« back to all changes in this revision

Viewing changes to dvd_udf.c

  • Committer: Bazaar Package Importer
  • Author(s): Josselin Mouette
  • Date: 2004-01-04 21:34:31 UTC
  • Revision ID: james.westby@ubuntu.com-20040104213431-citkfxqbf7wggbnr
Tags: upstream-0.1
Import upstream version 0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * dvdudf: parse and read the UDF volume information of a DVD Video
 
3
 * Copyright (C) 1999 Christian Wolff for convergence integrated media GmbH
 
4
 * 
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License
 
7
 * as published by the Free Software Foundation; either version 2
 
8
 * of the License, or (at your option) any later version.
 
9
 * 
 
10
 * This program is distributed in the hope that it will be useful, 
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 * 
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
18
 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
 
19
 * 
 
20
 * The author can be reached at scarabaeus@convergence.de, 
 
21
 * the project's page is at http://linuxtv.org/dvd/
 
22
 *
 
23
 * Removed all CSS related stuff to be able to publish "regionset"
 
24
 *   by Mirko D�lle <cooper@linvdr.org>
 
25
 */
 
26
 
 
27
/* This is needed for 64 bit file seek */
 
28
// Since older libraries don't seem to support this, i did a workaround
 
29
#define _LARGEFILE64_SOURCE 1
 
30
 
 
31
#include <stdio.h>
 
32
#include <stdlib.h>
 
33
#include <string.h>
 
34
#include <dirent.h>
 
35
#include <limits.h>
 
36
#include <sys/ioctl.h>
 
37
#include <sys/types.h>
 
38
#include <sys/stat.h>
 
39
 
 
40
#if defined(__OpenBSD__)
 
41
# include <sys/dvdio.h>
 
42
#elif defined(__linux__)
 
43
# include <linux/cdrom.h>
 
44
#else
 
45
# error "Need the DVD ioctls"
 
46
#endif
 
47
 
 
48
#include "dvd_udf.h"
 
49
 
 
50
#ifndef u8
 
51
#define u8 unsigned char
 
52
#endif
 
53
 
 
54
#ifndef u16
 
55
#define u16 unsigned short
 
56
#endif
 
57
 
 
58
#ifndef u32
 
59
#define u32 unsigned long
 
60
#endif
 
61
 
 
62
#ifndef u64
 
63
#define u64 unsigned long long
 
64
#endif
 
65
 
 
66
#ifndef NULL
 
67
#define NULL ((void *)0)
 
68
#endif
 
69
 
 
70
// Maximum length of filenames for UDF
 
71
#define MAX_FILE_LEN 2048
 
72
 
 
73
// default name for split udf image files
 
74
#define SPLITNAME "DVDVIDEO"
 
75
 
 
76
FILE* dvdromfile = NULL;  // CD/DVD-ROM block device or image file
 
77
char Path[PATH_MAX];
 
78
char Filename[PATH_MAX];
 
79
 
 
80
struct DVD_Video_Disc {
 
81
        int segments;
 
82
        int currentsegment;
 
83
        long int *segmentlength;
 
84
        int segtablelen;
 
85
        int phoony_region_mask;
 
86
} disc;
 
87
 
 
88
struct Partition {
 
89
        int valid;
 
90
        char VolumeDesc[128];
 
91
        u16 Flags;
 
92
        u16 Number;
 
93
        char Contents[32];
 
94
        u32 AccessType;
 
95
        u32 Start;
 
96
        u32 Length;
 
97
} partition;
 
98
 
 
99
struct AD {
 
100
        u32 Location;
 
101
        u32 Length;
 
102
        u8 Flags;
 
103
        u16 Partition;
 
104
};
 
105
 
 
106
// for direct data access, LSB first
 
107
#define GETN1(p) ((u8)data[p])
 
108
#define GETN2(p) ((u16)data[p] | ((u16)data[(p) + 1] << 8))
 
109
#define GETN3(p) ((u32)data[p] | ((u32)data[(p) + 1] << 8) | ((u32)data[(p) + 2] << 16))
 
110
#define GETN4(p) ((u32)data[p] | ((u32)data[(p) + 1] << 8) | ((u32)data[(p) + 2] << 16) | ((u32)data[(p) + 3] << 24))
 
111
#define GETN(p, n, target) memcpy(target, &data[p], n)
 
112
 
 
113
#ifdef DVD_AUTH
 
114
        dvd_authinfo ai;
 
115
        dvd_struct dvds;
 
116
        int last_agid = 0;
 
117
#endif
 
118
 
 
119
// searches for <file> in directory <path>, ignoring case
 
120
// returns 0 and full filename in <filename>
 
121
// or -1 on file not found
 
122
// or -2 on path not found
 
123
int udf_find_file(const char *path, const char *file, char *filename) 
 
124
{
 
125
        DIR *dir;
 
126
        struct dirent *ent;
 
127
 
 
128
#ifdef UDF_DEBUG
 
129
        printf("find file %s / %s\n", path, file);
 
130
#endif
 
131
        if ((dir = opendir(path)) == NULL) return -2;
 
132
        while ((ent = readdir(dir)) != NULL) {
 
133
                if (!strcasecmp(ent->d_name, file)) {
 
134
                        sprintf(filename, "%s%s%s", path, ((path[strlen(path)-1] == '/') ? "" : "/"), ent->d_name);
 
135
                        closedir(dir);
 
136
                        return 0;
 
137
                }
 
138
        }
 
139
        closedir(dir);
 
140
        return -1;
 
141
}
 
142
 
 
143
// updates the segment length table of a DVD Video image directory
 
144
// stores the length of DVDVIDEO.000 and following into an array
 
145
// returns 0 on success, >0 on error
 
146
int udf_update_segments(void) 
 
147
{
 
148
        char file[PATH_MAX];
 
149
        char filename[PATH_MAX];
 
150
        int err;
 
151
        if (disc.currentsegment >= 0) fclose(dvdromfile);
 
152
        disc.currentsegment = -1;
 
153
        disc.segments = 0;
 
154
        err = 0;
 
155
        do {
 
156
                sprintf(file, "%s.%03d", Filename, disc.segments);
 
157
                if (!(err = udf_find_file(Path, file, filename))) {
 
158
                        if ((dvdromfile = fopen(filename, "r")) == NULL) {
 
159
                                err = 1;   // file not readable
 
160
                        } else {
 
161
                                if (disc.segments >= disc.segtablelen) {
 
162
                                        disc.segtablelen += 100;
 
163
                                        disc.segmentlength = (long int *)realloc(disc.segmentlength, disc.segtablelen * sizeof(long int));
 
164
                                        if (disc.segmentlength == NULL) return 1;
 
165
                                }
 
166
                                fseek(dvdromfile, 0L, SEEK_END);
 
167
                                disc.segmentlength[disc.segments++] = ftell(dvdromfile)/DVD_VIDEO_LB_LEN;
 
168
                                fclose(dvdromfile);
 
169
                        }
 
170
                }
 
171
        } while (!err);
 
172
        return 0;
 
173
}
 
174
 
 
175
 
 
176
// reads absolute Logical Block of the disc
 
177
// returns number of read bytes on success, 0 or negative error number on error
 
178
int UDFReadLB(unsigned long int lb_number, unsigned int block_count, unsigned char *data) 
 
179
{
 
180
#if defined off64_t
 
181
        fpos64_t pos;
 
182
#else
 
183
        u64 pos;  // 64 bit position
 
184
#endif
 
185
        int result, segment, segblocks, numread;
 
186
        char file[PATH_MAX];
 
187
        char filename[PATH_MAX];
 
188
        if (disc.segments > 1) {  // split image file
 
189
                segment = 0;
 
190
                result = 0;
 
191
                while (block_count && (segment < disc.segments)) {
 
192
                        if (disc.segmentlength[segment] <= lb_number) {  // that's not our segment yet
 
193
                                lb_number -= disc.segmentlength[segment++];    // skip to next segment
 
194
                        } else {                                  // our segment
 
195
                                if (disc.currentsegment != segment) {          // segment not open, yet?
 
196
                                        if (disc.currentsegment >= 0) fclose(dvdromfile);
 
197
                                        disc.currentsegment = -1;
 
198
                                        sprintf(file, "%s.%03d", Filename, segment);
 
199
                                        if (udf_find_file(Path, file, filename)) return 0;
 
200
                                        if ((dvdromfile = fopen(filename, "r")) == NULL) return 0;
 
201
                                        disc.currentsegment = segment;               // remember open segment number
 
202
                                }
 
203
                                if (fseek(dvdromfile, lb_number * DVD_VIDEO_LB_LEN, SEEK_SET) < 0) break;  // position not found
 
204
                                segblocks = disc.segmentlength[segment] - lb_number;              // remaining blocks in segment
 
205
                                if (block_count < segblocks) segblocks = block_count;             // more than requested?
 
206
                                if ((numread = fread(&data[result], segblocks * DVD_VIDEO_LB_LEN, 1, dvdromfile))) {  // read requested blocks or up to end of segment
 
207
                                        result += segblocks * DVD_VIDEO_LB_LEN;           // add to overall number of read bytes
 
208
                                        block_count -= segblocks;                         // segments done
 
209
                                        lb_number += segblocks;                           // next position
 
210
                                } else {                                            // read error 
 
211
                                        if (!result) {
 
212
                                                result = ferror(dvdromfile);
 
213
                                                if (result > 0) result = -result;
 
214
                                        }
 
215
                                        break;
 
216
                                }
 
217
                        }
 
218
                }
 
219
                return result;
 
220
        } else if (dvdromfile != NULL) {  // block device or one image file
 
221
#if defined off64_t
 
222
                pos = (fpos64_t)lb_number * (fpos64_t)DVD_VIDEO_LB_LEN;
 
223
                if (fsetpos64(dvdromfile, &pos) < 0) return 0; // position not found
 
224
#else
 
225
                pos = (u64)lb_number * (u64)DVD_VIDEO_LB_LEN;
 
226
                fseek(dvdromfile, 0, SEEK_SET);
 
227
                while (pos > LONG_MAX) {
 
228
                        if (fseek(dvdromfile, LONG_MAX, SEEK_CUR)) return 0; // position not found
 
229
                        pos -= LONG_MAX;
 
230
                }
 
231
                if (fseek(dvdromfile, (long int)pos, SEEK_CUR)) return 0; // position not found
 
232
#endif
 
233
                if ((result = fread(data, block_count * DVD_VIDEO_LB_LEN, 1, dvdromfile)) <= 0) {
 
234
                        result = ferror(dvdromfile);
 
235
                        clearerr(dvdromfile);
 
236
                        return ((result > 0) ? -result : result);  // make it negative!
 
237
                } else return result * block_count * DVD_VIDEO_LB_LEN;
 
238
        } else return 0;
 
239
}
 
240
 
 
241
int Unicodedecode(u8 *data, int len, char *target) 
 
242
{
 
243
        int p = 1, i = 0;
 
244
        if ((data[0] == 8) || (data[0] == 16)) do {
 
245
                if (data[0] == 16) p++;  // ignore MSB of unicode16
 
246
                if (p < len) {
 
247
                        target[i++] = data[p++];
 
248
                }
 
249
        } while (p < len);
 
250
        target[i] = '\0';
 
251
        return 0;
 
252
}
 
253
 
 
254
int UDFEntity(u8 *data, u8 *Flags, char *Identifier) 
 
255
{
 
256
        *Flags = data[0];
 
257
        strncpy(Identifier, &data[1], 5);
 
258
        return 0;
 
259
}
 
260
 
 
261
int UDFDescriptor(u8 *data, u16 *TagID) 
 
262
{
 
263
        *TagID = GETN2(0);
 
264
        // TODO: check CRC 'n stuff
 
265
        return 0;
 
266
}
 
267
 
 
268
int UDFExtentAD(u8 *data, u32 *Length, u32 *Location) 
 
269
{
 
270
        *Length   = GETN4(0);
 
271
        *Location = GETN4(4);
 
272
        return 0;
 
273
}
 
274
 
 
275
int UDFShortAD(u8 *data, struct AD *ad) 
 
276
{
 
277
        ad->Length = GETN4(0);
 
278
        ad->Flags = ad->Length >> 30;
 
279
        ad->Length &= 0x3FFFFFFF;
 
280
        ad->Location = GETN4(4);
 
281
        ad->Partition = partition.Number;  // use number of current partition
 
282
        return 0;
 
283
}
 
284
 
 
285
int UDFLongAD(u8 *data, struct AD *ad) 
 
286
{
 
287
        ad->Length = GETN4(0);
 
288
        ad->Flags = ad->Length >> 30;
 
289
        ad->Length &= 0x3FFFFFFF;
 
290
        ad->Location = GETN4(4);
 
291
        ad->Partition = GETN2(8);
 
292
        //GETN(10, 6, Use);
 
293
        return 0;
 
294
}
 
295
 
 
296
int UDFExtAD(u8 *data, struct AD *ad) 
 
297
{
 
298
        ad->Length = GETN4(0);
 
299
        ad->Flags = ad->Length >> 30;
 
300
        ad->Length &= 0x3FFFFFFF;
 
301
        ad->Location = GETN4(12);
 
302
        ad->Partition = GETN2(16);
 
303
        //GETN(10, 6, Use);
 
304
        return 0;
 
305
}
 
306
 
 
307
int UDFICB(u8 *data, u8 *FileType, u16 *Flags) 
 
308
{
 
309
        *FileType = GETN1(11);
 
310
        *Flags = GETN2(18);
 
311
        return 0;
 
312
}
 
313
 
 
314
 
 
315
int UDFPartition(u8 *data, u16 *Flags, u16 *Number, char *Contents, u32 *Start, u32 *Length) 
 
316
{
 
317
        *Flags = GETN2(20);
 
318
        *Number = GETN2(22);
 
319
        GETN(24, 32, Contents);
 
320
        *Start = GETN4(188);
 
321
        *Length = GETN4(192);
 
322
        return 0;
 
323
}
 
324
 
 
325
// reads the volume descriptor and checks the parameters
 
326
// returns 0 on OK, 1 on error
 
327
int UDFLogVolume(u8 *data, char *VolumeDescriptor) 
 
328
{
 
329
        u32 lbsize, MT_L, N_PM;
 
330
        //u8 type, PM_L;
 
331
        //u16 sequence;
 
332
        //int i, p;
 
333
        Unicodedecode(&data[84], 128, VolumeDescriptor);
 
334
        lbsize = GETN4(212);  // should be 2048
 
335
        MT_L = GETN4(264);    // should be 6
 
336
        N_PM = GETN4(268);    // should be 1
 
337
        if (lbsize != DVD_VIDEO_LB_LEN) return 1;
 
338
        /*
 
339
        *Partition1 = 0;
 
340
        p = 440;
 
341
        for (i = 0; i < N_PM; i++) {
 
342
                type = GETN1(p);
 
343
                PM_L = GETN1(p + 1);
 
344
                if (type == 1) {
 
345
                        sequence = GETN2(p + 2);
 
346
                        if (sequence == 1) {
 
347
                                *Partition1 = GETN2(p + 4);
 
348
                                return 0;
 
349
                        }
 
350
                }
 
351
                p += PM_L;
 
352
        }
 
353
        return 1;
 
354
        */
 
355
        return 0;
 
356
}
 
357
 
 
358
int UDFFileEntry(u8 *data, u8 *FileType, struct AD *ad) 
 
359
{
 
360
        u8 filetype;
 
361
        u16 flags;
 
362
        u32 L_EA, L_AD;
 
363
        int p;
 
364
 
 
365
        UDFICB(&data[16], &filetype, &flags);
 
366
        *FileType = filetype;
 
367
        L_EA = GETN4(168);
 
368
        L_AD = GETN4(172);
 
369
        p = 176 + L_EA;
 
370
        while (p < 176 + L_EA + L_AD) {
 
371
                switch (flags & 0x0007) {
 
372
                        case 0: UDFShortAD(&data[p], ad); p += 8;  break;
 
373
                        case 1: UDFLongAD(&data[p], ad);  p += 16; break;
 
374
                        case 2: UDFExtAD(&data[p], ad);   p += 20; break;
 
375
                        case 3:
 
376
                                switch (L_AD) {
 
377
                                        case 8:  UDFShortAD(&data[p], ad); break;
 
378
                                        case 16: UDFLongAD(&data[p], ad);  break;
 
379
                                        case 20: UDFExtAD(&data[p], ad);   break;
 
380
                                }
 
381
                                p += L_AD;
 
382
                                break;
 
383
                        default: p += L_AD; break;
 
384
                }
 
385
        }
 
386
        return 0;
 
387
}
 
388
 
 
389
int UDFFileIdentifier(u8 *data, u8 *FileCharacteristics, char *FileName, struct AD *FileICB) 
 
390
{
 
391
        u8 L_FI;
 
392
        u16 L_IU;
 
393
        
 
394
        *FileCharacteristics = GETN1(18);
 
395
        L_FI = GETN1(19);
 
396
        UDFLongAD(&data[20], FileICB);
 
397
        L_IU = GETN2(36);
 
398
        if (L_FI) Unicodedecode(&data[38 + L_IU], L_FI, FileName);
 
399
        else FileName[0] = '\0';
 
400
        return 4 * ((38 + L_FI + L_IU + 3) / 4);
 
401
}
 
402
 
 
403
// Maps ICB to FileAD
 
404
// ICB: Location of ICB of directory to scan
 
405
// FileType: Type of the file
 
406
// File: Location of file the ICB is pointing to
 
407
// return 1 on success, 0 on error;
 
408
int UDFMapICB(struct AD ICB, u8 *FileType, struct AD *File) 
 
409
{
 
410
        u8 LogBlock[DVD_VIDEO_LB_LEN];
 
411
        u32 lbnum;
 
412
        u16 TagID;
 
413
 
 
414
        lbnum = partition.Start + ICB.Location;
 
415
        do {
 
416
                if (UDFReadLB(lbnum++, 1, LogBlock) <= 0) TagID = 0;
 
417
                else UDFDescriptor(LogBlock, &TagID);
 
418
                if (TagID == 261) {
 
419
                        UDFFileEntry(LogBlock, FileType, File);
 
420
#ifdef UDF_DEBUG
 
421
                        printf("Found File entry type %d at LB %ld, %ld bytes long\n", *FileType, File->Location, File->Length);
 
422
#endif
 
423
                        return 1;
 
424
                };
 
425
        } while ((lbnum <= partition.Start + ICB.Location + (ICB.Length-1) / DVD_VIDEO_LB_LEN) && (TagID != 261));
 
426
        return 0;
 
427
}
 
428
        
 
429
// Dir: Location of directory to scan
 
430
// FileName: Name of file to look for
 
431
// FileICB: Location of ICB of the found file
 
432
// return 1 on success, 0 on error;
 
433
int UDFScanDir(struct AD Dir, char *FileName, struct AD *FileICB) 
 
434
{
 
435
        u8 LogBlock[DVD_VIDEO_LB_LEN];
 
436
        u32 lbnum;
 
437
        u16 TagID;
 
438
        u8 filechar;
 
439
        char filename[MAX_FILE_LEN];
 
440
        int p;
 
441
        
 
442
        // Scan dir for ICB of file
 
443
        lbnum = partition.Start + Dir.Location;
 
444
        do {
 
445
                if (UDFReadLB(lbnum++, 1, LogBlock) <= 0) TagID = 0;
 
446
                else {
 
447
                        p = 0;
 
448
                        while (p < DVD_VIDEO_LB_LEN) {
 
449
                                UDFDescriptor(&LogBlock[p], &TagID);
 
450
                                if (TagID == 257) {
 
451
                                        p += UDFFileIdentifier(&LogBlock[p], &filechar, filename, FileICB);
 
452
#ifdef UDF_DEBUG
 
453
                                        printf("Found ICB for file '%s' at LB %ld, %ld bytes long\n", filename, FileICB->Location, FileICB->Length);
 
454
#endif
 
455
                                        if (!strcasecmp(FileName, filename)) return 1;
 
456
                                } else p = DVD_VIDEO_LB_LEN;
 
457
                        }
 
458
                }
 
459
        } while (lbnum <= partition.Start + Dir.Location + (Dir.Length-1) / DVD_VIDEO_LB_LEN);
 
460
        return 0;
 
461
}
 
462
 
 
463
// looks for partition on the disc
 
464
//   partnum: number of the partition, starting at 0
 
465
//   part: structure to fill with the partition information
 
466
//   return 1 if partition found, 0 on error;
 
467
int UDFFindPartition(int partnum, struct Partition *part) 
 
468
{
 
469
        u8 LogBlock[DVD_VIDEO_LB_LEN], Anchor[DVD_VIDEO_LB_LEN];
 
470
        u32 lbnum, MVDS_location, MVDS_length;
 
471
        u16 TagID;
 
472
        //u8 Flags;
 
473
        //char Identifier[6];
 
474
        u32 lastsector;
 
475
        int i, terminate, volvalid;
 
476
 
 
477
        // Recognize Volume
 
478
        /*
 
479
        lbnum = 16;
 
480
        do {
 
481
                if (UDFReadLB(lbnum++, 1, LogBlock) <= 0) strcpy(Identifier, "");
 
482
                else UDFEntity(LogBlock, &Flags, Identifier);
 
483
#ifdef UDF_DEBUG
 
484
                printf("Looking for NSR02 at LB %ld, found %s\n", lbnum-1, Identifier);
 
485
#endif
 
486
        } while ((lbnum <= 256) && strcmp("NSR02", Identifier));
 
487
#ifdef UDF_DEBUG
 
488
        if (strcmp("NSR02", Identifier))  printf("Could not recognize volume. Bad.\n");
 
489
        else printf("Found %s at LB %ld. Good.\n", Identifier, lbnum-1);
 
490
#endif
 
491
        */
 
492
 
 
493
        // Find Anchor
 
494
        lastsector = 0;
 
495
        lbnum = 256;   // try #1, prime anchor
 
496
        terminate = 0;
 
497
        while (1) {  // loop da loop
 
498
                if (UDFReadLB(lbnum, 1, Anchor) > 0) {
 
499
                        UDFDescriptor(Anchor, &TagID);
 
500
                } else TagID = 0;
 
501
                if (TagID != 2) {             // not an anchor?
 
502
                        if (terminate) return 0;    // final try failed 
 
503
                        if (lastsector) {           // we already found the last sector
 
504
                                lbnum = lastsector;       // try #3, alternative backup anchor
 
505
                                terminate = 1;            // but that's just about enough, then!
 
506
                        } else {
 
507
                                // TODO: find last sector of the disc (this is optional)
 
508
                                if (lastsector) lbnum = lastsector - 256; // try #2, backup anchor
 
509
                                else return 0;            // unable to find last sector
 
510
                        }
 
511
                } else break;                 // it is an anchor! continue...
 
512
        }
 
513
        UDFExtentAD(&Anchor[16], &MVDS_length, &MVDS_location);  // main volume descriptor
 
514
#ifdef UDF_DEBUG
 
515
        printf("MVDS at LB %ld thru %ld\n", MVDS_location, MVDS_location + (MVDS_length-1) / DVD_VIDEO_LB_LEN);
 
516
#endif
 
517
        
 
518
        part->valid = 0;
 
519
        volvalid = 0;
 
520
        part->VolumeDesc[0] = '\0';
 
521
        i = 1;
 
522
        do {
 
523
                // Find Volume Descriptor
 
524
                lbnum = MVDS_location;
 
525
                do {
 
526
                        if (UDFReadLB(lbnum++, 1, LogBlock) <= 0) TagID = 0;
 
527
                        else UDFDescriptor(LogBlock, &TagID);
 
528
#ifdef UDF_DEBUG
 
529
                        printf("Looking for Descripors at LB %ld, found %d\n", lbnum-1, TagID);
 
530
#endif
 
531
                        if ((TagID == 5) && (!part->valid)) {  // Partition Descriptor
 
532
#ifdef UDF_DEBUG
 
533
                                printf("Partition Descriptor at LB %ld\n", lbnum-1);
 
534
#endif
 
535
                                UDFPartition(LogBlock, &part->Flags, &part->Number, part->Contents, &part->Start, &part->Length);
 
536
                                part->valid = (partnum == part->Number);
 
537
#ifdef UDF_DEBUG
 
538
                                printf("Partition %d at LB %ld thru %ld\n", part->Number, part->Start, part->Start+part->Length-1);
 
539
#endif
 
540
                        } else if ((TagID == 6) && (!volvalid)) {  // Logical Volume Descriptor
 
541
#ifdef UDF_DEBUG
 
542
                                printf("Logical Volume Descriptor at LB %ld\n", lbnum-1);
 
543
#endif
 
544
                                if (UDFLogVolume(LogBlock, part->VolumeDesc)) {  
 
545
                                        //TODO: sector size wrong!
 
546
                                } else volvalid = 1;
 
547
#ifdef UDF_DEBUG
 
548
                                printf("Logical Volume Descriptor: %s\n", part->VolumeDesc);  // name of the disc
 
549
#endif
 
550
                        }
 
551
                } while ((lbnum <= MVDS_location + (MVDS_length-1) / DVD_VIDEO_LB_LEN) && (TagID != 8) && ((!part->valid) || (!volvalid)));
 
552
                if ((!part->valid) || (!volvalid)) UDFExtentAD(&Anchor[24], &MVDS_length, &MVDS_location);  // backup volume descriptor
 
553
        } while (i-- && ((!part->valid) || (!volvalid)));
 
554
        return (part->valid);  // we only care for the partition, not the volume
 
555
}
 
556
 
 
557
// looks for a file on the UDF disc/imagefile
 
558
// filename has to be the absolute pathname on the UDF filesystem, starting with /
 
559
// filesize will be set to the size of the file in bytes, on success
 
560
// returns absolute LB number, or 0 on error
 
561
unsigned long int UDFFindFile(char *filename, unsigned long int *filesize) 
 
562
{
 
563
        u8 LogBlock[DVD_VIDEO_LB_LEN];
 
564
        u32 lbnum;
 
565
        u16 TagID;
 
566
        struct AD RootICB, File, ICB;
 
567
        char tokenline[MAX_FILE_LEN];
 
568
        char *token;
 
569
        u8 filetype;
 
570
        
 
571
        int Partition = 0;  // Partition number to look for the file, 
 
572
                                                                                  // 0 is this is the standard location for DVD Video
 
573
        
 
574
        *filesize = 0;
 
575
        tokenline[0] = '\0';
 
576
        strcat(tokenline, filename);
 
577
 
 
578
        // Find partition
 
579
        if (!UDFFindPartition(Partition, &partition)) return 0;
 
580
        // Find root dir ICB
 
581
        lbnum = partition.Start;
 
582
        do {
 
583
                if (UDFReadLB(lbnum++, 1, LogBlock) <= 0) TagID = 0;
 
584
                else UDFDescriptor(LogBlock, &TagID);
 
585
#ifdef UDF_DEBUG
 
586
                printf("Found TagID %d at LB %ld\n", TagID, lbnum-1);
 
587
#endif
 
588
                if (TagID == 256) {  // File Set Descriptor
 
589
                        UDFLongAD(&LogBlock[400], &RootICB);
 
590
                }
 
591
        } while ((lbnum < partition.Start + partition.Length) && (TagID != 8) && (TagID != 256));
 
592
        if (TagID!=256) return 0;
 
593
        if (RootICB.Partition != Partition) return 0;
 
594
        
 
595
        // Find root dir
 
596
        if (!UDFMapICB(RootICB, &filetype, &File)) return 0;
 
597
        if (filetype != 4) return 0;  // root dir should be dir
 
598
#ifdef UDF_DEBUG
 
599
        printf("Root Dir found at %ld\n", File.Location);
 
600
#endif
 
601
 
 
602
        // Tokenize filepath
 
603
        token = strtok(tokenline, "/");
 
604
        while (token != NULL) {
 
605
#ifdef UDF_DEBUG
 
606
                printf("looking for token %s\n", token);
 
607
#endif
 
608
                if (!UDFScanDir(File, token, &ICB)) return 0;
 
609
                if (!UDFMapICB(ICB, &filetype, &File)) return 0;
 
610
                token = strtok(NULL, "/");
 
611
        }
 
612
        *filesize = File.Length;
 
613
        return partition.Start + File.Location;
 
614
}
 
615
 
 
616
 
 
617
 
 
618
// DVD Copy Management: 
 
619
// RPC - Region Playback Control
 
620
 
 
621
// Query RPC status of the drive
 
622
// type: 0=NONE (no drive region setting)
 
623
//       1=SET (drive region is set
 
624
//       2=LAST CHANCE (drive region is set, only one change remains)
 
625
//       3=PERM (region set permanently, may be reset by vendor)
 
626
// vra: number of vendor resets available
 
627
// ucca: number of user controlled changes available
 
628
// region_mask: the bit of the drive's region is set to zero, all other 7 bits to one
 
629
// rpc_scheme: 0=unknown, 1=RPC Phase II, others reserved
 
630
// returns 0 on success, <0 on error
 
631
int UDFRPCGet(int *type, int *vra, int *ucca, int *region_mask, int *rpc_scheme) 
 
632
{
 
633
        int ret;
 
634
        if (disc.segments) {
 
635
                *type = 1;
 
636
                *vra = 4;
 
637
                *ucca = 5;
 
638
                *region_mask = disc.phoony_region_mask;
 
639
                *rpc_scheme = 0;
 
640
        } else {
 
641
#ifdef DVD_LU_SEND_RPC_STATE
 
642
                if (dvdromfile==NULL) return 0;
 
643
                ai.type = DVD_LU_SEND_RPC_STATE;
 
644
                if ((ret = ioctl(fileno(dvdromfile), DVD_AUTH, &ai)) < 0) return ret;
 
645
                *type = ai.lrpcs.type;
 
646
                *vra = ai.lrpcs.vra;
 
647
                *ucca = ai.lrpcs.ucca;
 
648
                *region_mask = ai.lrpcs.region_mask;
 
649
                *rpc_scheme = ai.lrpcs.rpc_scheme;
 
650
#else
 
651
                return -1;
 
652
#endif
 
653
        }
 
654
        return 0;
 
655
}
 
656
 
 
657
// Set new Region for drive
 
658
// region_mask: the bit of the new drive's region is set to zero, all other 7 bits to one
 
659
int UDFRPCSet(int region_mask) 
 
660
{
 
661
        int ret;
 
662
        if (disc.segments) {
 
663
                disc.phoony_region_mask = region_mask;
 
664
        } else {
 
665
#ifdef DVD_HOST_SEND_RPC_STATE
 
666
                if (dvdromfile == NULL) return 0;
 
667
                ai.type = DVD_HOST_SEND_RPC_STATE;
 
668
                ai.hrpcs.pdrc = region_mask & 0xFF;
 
669
                if ((ret = ioctl(fileno(dvdromfile), DVD_AUTH, &ai)) < 0) return ret;
 
670
#else
 
671
                return -1;
 
672
#endif
 
673
        }
 
674
        return 0;
 
675
}
 
676
 
 
677
// open block device or image file
 
678
// returns fileno() of the file on success, or -1 on error
 
679
int UDFOpenDisc(char *filename) 
 
680
{
 
681
        struct stat filestat;
 
682
        int i;
 
683
        char tempfilename[PATH_MAX];
 
684
        if (filename == NULL) return -1;
 
685
        Path[0] = '\0';
 
686
        disc.currentsegment = -1;
 
687
        disc.segmentlength = NULL;
 
688
        disc.segtablelen = 0;
 
689
        disc.phoony_region_mask = 0x00;
 
690
        if (strlen(Filename) < (PATH_MAX-4)) {
 
691
                strcpy(tempfilename, filename);
 
692
        } else {
 
693
                strncpy(tempfilename, filename, PATH_MAX-4);
 
694
        }
 
695
        if (stat(tempfilename, &filestat) < 0) {
 
696
                if (tempfilename[strlen(tempfilename)-1] != '.') strcat(tempfilename, ".");
 
697
                strcat(tempfilename, "000");
 
698
        }
 
699
        if (stat(tempfilename, &filestat) >= 0) {
 
700
                if (S_ISDIR(filestat.st_mode)) {  // directory?  dir/DVDVIDEO.000 obligatory
 
701
#ifdef UDF_DEBUG
 
702
printf("is directory, looking for %s\n", SPLITNAME ".000");
 
703
#endif
 
704
                        if (tempfilename[strlen(tempfilename)-1] != '/') strcat(tempfilename, "/");
 
705
                        strcat(tempfilename, SPLITNAME ".000");
 
706
                        if (stat(tempfilename, &filestat) < 0) return -1;  // file not found
 
707
                }
 
708
                if (S_ISBLK(filestat.st_mode)) {  // block device?
 
709
#ifdef UDF_DEBUG
 
710
printf("is block device.\n");
 
711
#endif
 
712
                        disc.segments = 0;
 
713
                        strcpy(Filename, tempfilename);
 
714
                } else if (S_ISREG(filestat.st_mode)) {  // image file? tempfilename.000 for split image obligatory
 
715
                        i = strlen(tempfilename);
 
716
                        while ((--i >= 0) && (tempfilename[i] != '/'));
 
717
                        if ((i >= 0) && (tempfilename[i] == '/')) { // slash in name?
 
718
                                strncpy(Path, tempfilename, i + 1);         // separate there
 
719
                                strcpy(Filename, &tempfilename[i + 1]);
 
720
                        } else {                            // no slash
 
721
                                strcpy(Path, "./");                // in local directory
 
722
                                strcpy(Filename, tempfilename);
 
723
                        }
 
724
                        if (strncmp(&Filename[strlen(Filename)-4], ".000", 4)) {  // does Filename end on 000?
 
725
                                strcpy(tempfilename, Path);
 
726
                                strcat(tempfilename, Filename);
 
727
                                strcat(tempfilename, ".000");  // or do we have an Filename.000?
 
728
                                if (stat(tempfilename, &filestat) >= 0) {
 
729
                                        disc.segments = 0;  // then it might be split file
 
730
                                } else {
 
731
                                        disc.segments = 1;  // else one image file
 
732
                                }
 
733
                        } else {  // ends on 000, chop that off
 
734
                                i = strlen(Filename)-4;
 
735
                                Filename[i] = '\0';                   // cut off extension
 
736
                                disc.segments = 0;
 
737
                        }
 
738
                        if (!disc.segments) {
 
739
                                strcpy(tempfilename, Path);
 
740
                                strcat(tempfilename, Filename);
 
741
                                strcat(tempfilename, ".001");  // do we have a second segment?
 
742
                                if (stat(tempfilename, &filestat) >= 0) {
 
743
#ifdef UDF_DEBUG
 
744
printf("is split image files.\n");
 
745
#endif
 
746
                                        udf_update_segments();
 
747
                                        if (disc.segments == 1) disc.segmentlength[disc.segments++]=0;  // dummy segment
 
748
                                } else {
 
749
                                        disc.segments = 1;
 
750
                                        strcat(Filename, ".000");
 
751
                                }
 
752
                        }
 
753
                        if (disc.segments == 1) {
 
754
#ifdef UDF_DEBUG
 
755
printf("is one image file.\n");
 
756
#endif
 
757
                        }
 
758
                }
 
759
        } else {
 
760
#ifdef UDF_DEBUG
 
761
printf("stat failed. block device?\n");
 
762
#endif
 
763
                disc.segments = 0;
 
764
                strcpy(Filename, tempfilename);
 
765
        }
 
766
        if (disc.segments <= 1) {
 
767
                strcpy(tempfilename, Path);
 
768
                strcat(tempfilename, Filename);
 
769
                if ((dvdromfile = fopen(tempfilename, "r")) != NULL) {
 
770
                        return fileno(dvdromfile);
 
771
                }
 
772
        } else {
 
773
                return 0;
 
774
        }
 
775
        return -1;
 
776
}
 
777
 
 
778
// closes previously opened block device or image file
 
779
// returns 0 on success, or -1 on error
 
780
int UDFCloseDisc(void) 
 
781
{
 
782
        fclose(dvdromfile);
 
783
        return 0;
 
784
}