Mercurial > mplayer.hg
comparison dvdread/dvd_udf.c @ 24047:de28f9e8cb00
Sync libdvdread with version 0.9.5 (functional changes).
author | diego |
---|---|
date | Wed, 15 Aug 2007 11:47:22 +0000 |
parents | 22cb9d5f1e21 |
children | 1542693b2a30 |
comparison
equal
deleted
inserted
replaced
24046:7e2808fb1807 | 24047:de28f9e8cb00 |
---|---|
35 #include "config.h" | 35 #include "config.h" |
36 | 36 |
37 #include <stdio.h> | 37 #include <stdio.h> |
38 #include <stdlib.h> | 38 #include <stdlib.h> |
39 #include <string.h> | 39 #include <string.h> |
40 #ifndef __MINGW32__ | 40 |
41 #include <sys/ioctl.h> | |
42 #endif | |
43 #include <sys/types.h> | 41 #include <sys/types.h> |
44 #include <sys/stat.h> | 42 #include <sys/stat.h> |
45 #include <unistd.h> | 43 #include <unistd.h> |
44 #include <errno.h> | |
45 | |
46 #if defined(HAVE_INTTYPES_H) | |
46 #include <inttypes.h> | 47 #include <inttypes.h> |
48 #elif defined(HAVE_STDINT_H) | |
49 #include <stdint.h> | |
50 #endif | |
47 | 51 |
48 #include "dvd_reader.h" | 52 #include "dvd_reader.h" |
49 #include "dvd_udf.h" | 53 #include "dvd_udf.h" |
54 #include "dvdread_internal.h" | |
55 | |
56 #ifndef EMEDIUMTYPE | |
57 #define EMEDIUMTYPE ENOENT | |
58 #endif | |
59 | |
60 #ifndef HAVE_UINTPTR_T | |
61 #warning "Assuming that (unsigned long) can hold (void *)" | |
62 typedef unsigned long uintptr_t; | |
63 #endif | |
64 | |
65 #define DVD_ALIGN(ptr) (void *)((((uintptr_t)(ptr)) + (DVD_VIDEO_LB_LEN-1)) \ | |
66 / DVD_VIDEO_LB_LEN * DVD_VIDEO_LB_LEN) | |
67 | |
68 typedef struct { | |
69 void *start; | |
70 void *aligned; | |
71 } dvdalign_ptrs_t; | |
72 | |
73 typedef struct { | |
74 dvdalign_ptrs_t *ptrs; | |
75 uint32_t ptrs_in_use; | |
76 uint32_t ptrs_max; | |
77 } dvdalign_t; | |
78 | |
79 extern void *GetAlignHandle(dvd_reader_t *device); | |
80 extern void SetAlignHandle(dvd_reader_t *device, void *align); | |
81 | |
82 /** | |
83 * Allocates aligned memory (for use with reads from raw/O_DIRECT devices). | |
84 * This memory must be freed with dvdalign_free() | |
85 * The size of the memory that is allocate is num_lbs*2048 bytes. | |
86 * The memory will be suitably aligned for use with | |
87 * block reads from raw/O_DIRECT device. | |
88 * @param num_lbs Number of logical blocks (2048 bytes) to allocate. | |
89 * @return Returns pointer to allocated memory, or NULL on failure | |
90 * This isn't supposed to be fast/efficient, if that is needed | |
91 * this function should be rewritten to use posix_memalign or similar. | |
92 * It's just needed for aligning memory for small block reads from | |
93 * raw/O_DIRECT devices. | |
94 * We assume that 2048 is enough alignment for all systems at the moment. | |
95 * Not thread safe. Only use this from one thread. | |
96 * Depends on sizeof(unsigned long) being at least as large as sizeof(void *) | |
97 */ | |
98 static void *dvdalign_lbmalloc(dvd_reader_t *device, uint32_t num_lbs) | |
99 { | |
100 void *m; | |
101 int n; | |
102 dvdalign_t *a; | |
103 | |
104 m = malloc((num_lbs+1)*DVD_VIDEO_LB_LEN); | |
105 if(m == NULL) { | |
106 return m; | |
107 } | |
108 a = (dvdalign_t *)GetAlignHandle(device); | |
109 if(a == NULL) { | |
110 a = malloc(sizeof(dvdalign_t)); | |
111 if(a == NULL) { | |
112 return a; | |
113 } | |
114 a->ptrs = NULL; | |
115 a->ptrs_in_use = 0; | |
116 a->ptrs_max = 0; | |
117 SetAlignHandle(device, (void *)a); | |
118 } | |
119 | |
120 if(a->ptrs_in_use >= a->ptrs_max) { | |
121 a->ptrs = realloc(a->ptrs, (a->ptrs_max+10)*sizeof(dvdalign_ptrs_t)); | |
122 if(a->ptrs == NULL) { | |
123 free(m); | |
124 return NULL; | |
125 } | |
126 a->ptrs_max+=10; | |
127 for(n = a->ptrs_in_use; n < a->ptrs_max; n++) { | |
128 a->ptrs[n].start = NULL; | |
129 a->ptrs[n].aligned = NULL; | |
130 } | |
131 n = a->ptrs_in_use; | |
132 } else { | |
133 for(n = 0; n < a->ptrs_max; n++) { | |
134 if(a->ptrs[n].start == NULL) { | |
135 break; | |
136 } | |
137 } | |
138 } | |
139 | |
140 a->ptrs[n].start = m; | |
141 a->ptrs[n].aligned = DVD_ALIGN(m); | |
142 | |
143 a->ptrs_in_use++; | |
144 | |
145 /* If this function starts to be used too much print a warning. | |
146 Either there is a memory leak somewhere or we need to rewrite this to | |
147 a more efficient version. | |
148 */ | |
149 if(a->ptrs_in_use > 50) { | |
150 if(dvdread_verbose(device) >= 0) { | |
151 fprintf(stderr, "libdvdread: dvdalign_lbmalloc(), more allocs than supposed: %u\n", a->ptrs_in_use); | |
152 } | |
153 } | |
154 | |
155 return a->ptrs[n].aligned; | |
156 } | |
157 | |
158 /** | |
159 * Frees memory allocated with dvdalign_lbmemory() | |
160 * @param ptr Pointer to memory space to free | |
161 * Not thread safe. | |
162 */ | |
163 static void dvdalign_lbfree(dvd_reader_t *device, void *ptr) | |
164 { | |
165 int n; | |
166 dvdalign_t *a; | |
167 | |
168 a = (dvdalign_t *)GetAlignHandle(device); | |
169 if(a && a->ptrs) { | |
170 for(n = 0; n < a->ptrs_max; n++) { | |
171 if(a->ptrs[n].aligned == ptr) { | |
172 free(a->ptrs[n].start); | |
173 a->ptrs[n].start = NULL; | |
174 a->ptrs[n].aligned = NULL; | |
175 a->ptrs_in_use--; | |
176 if(a->ptrs_in_use == 0) { | |
177 free(a->ptrs); | |
178 a->ptrs = NULL; | |
179 a->ptrs_max = 0; | |
180 free(a); | |
181 a = NULL; | |
182 SetAlignHandle(device, (void *)a); | |
183 } | |
184 return; | |
185 } | |
186 } | |
187 } | |
188 if(dvdread_verbose(device) >= 0) { | |
189 fprintf(stderr, "libdvdread: dvdalign_lbfree(), error trying to free mem: %08lx (%u)\n", (unsigned long)ptr, a ? a->ptrs_in_use : 0); | |
190 } | |
191 } | |
192 | |
50 | 193 |
51 /* Private but located in/shared with dvd_reader.c */ | 194 /* Private but located in/shared with dvd_reader.c */ |
52 extern int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, | 195 extern int UDFReadBlocksRaw( dvd_reader_t *device, uint32_t lb_number, |
53 size_t block_count, unsigned char *data, | 196 size_t block_count, unsigned char *data, |
54 int encrypted ); | 197 int encrypted ); |
55 | 198 |
56 /* It's required to either fail or deliver all the blocks asked for. */ | 199 /** @internal |
200 * Its required to either fail or deliver all the blocks asked for. | |
201 * | |
202 * @param data Pointer to a buffer where data is returned. This must be large | |
203 * enough to hold lb_number*2048 bytes. | |
204 * It must be aligned to system specific (2048) logical blocks size when | |
205 * reading from raw/O_DIRECT device. | |
206 */ | |
57 static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number, | 207 static int DVDReadLBUDF( dvd_reader_t *device, uint32_t lb_number, |
58 size_t block_count, unsigned char *data, | 208 size_t block_count, unsigned char *data, |
59 int encrypted ) | 209 int encrypted ) |
60 { | 210 { |
61 int ret; | 211 int ret; |
147 } UDFCacheType; | 297 } UDFCacheType; |
148 | 298 |
149 extern void *GetUDFCacheHandle(dvd_reader_t *device); | 299 extern void *GetUDFCacheHandle(dvd_reader_t *device); |
150 extern void SetUDFCacheHandle(dvd_reader_t *device, void *cache); | 300 extern void SetUDFCacheHandle(dvd_reader_t *device, void *cache); |
151 | 301 |
152 void FreeUDFCache(void *cache) | 302 |
153 { | 303 void FreeUDFCache(dvd_reader_t *device, void *cache) |
304 { | |
305 int n; | |
306 | |
154 struct udf_cache *c = (struct udf_cache *)cache; | 307 struct udf_cache *c = (struct udf_cache *)cache; |
155 if(c == NULL) { | 308 if(c == NULL) { |
156 return; | 309 return; |
157 } | 310 } |
311 | |
312 for(n = 0; n < c->lb_num; n++) { | |
313 if(c->lbs[n].data) { | |
314 /* free data */ | |
315 dvdalign_lbfree(device, c->lbs[n].data); | |
316 } | |
317 } | |
318 c->lb_num = 0; | |
319 | |
158 if(c->lbs) { | 320 if(c->lbs) { |
159 free(c->lbs); | 321 free(c->lbs); |
160 } | 322 } |
161 if(c->maps) { | 323 if(c->maps) { |
162 free(c->maps); | 324 free(c->maps); |
491 * return 1 on success, 0 on error; | 653 * return 1 on success, 0 on error; |
492 */ | 654 */ |
493 static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType, | 655 static int UDFMapICB( dvd_reader_t *device, struct AD ICB, uint8_t *FileType, |
494 struct Partition *partition, struct AD *File ) | 656 struct Partition *partition, struct AD *File ) |
495 { | 657 { |
496 uint8_t LogBlock[DVD_VIDEO_LB_LEN]; | 658 uint8_t *LogBlock; |
497 uint32_t lbnum; | 659 uint32_t lbnum; |
498 uint16_t TagID; | 660 uint16_t TagID; |
499 struct icbmap tmpmap; | 661 struct icbmap tmpmap; |
500 | 662 |
501 lbnum = partition->Start + ICB.Location; | 663 lbnum = partition->Start + ICB.Location; |
504 *FileType = tmpmap.filetype; | 666 *FileType = tmpmap.filetype; |
505 *File = tmpmap.file; | 667 *File = tmpmap.file; |
506 return 1; | 668 return 1; |
507 } | 669 } |
508 | 670 |
671 LogBlock = dvdalign_lbmalloc(device, 1); | |
672 if(!LogBlock) { | |
673 return 0; | |
674 } | |
675 | |
509 do { | 676 do { |
510 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { | 677 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { |
511 TagID = 0; | 678 TagID = 0; |
512 } else { | 679 } else { |
513 UDFDescriptor( LogBlock, &TagID ); | 680 UDFDescriptor( LogBlock, &TagID ); |
516 if( TagID == 261 ) { | 683 if( TagID == 261 ) { |
517 UDFFileEntry( LogBlock, FileType, partition, File ); | 684 UDFFileEntry( LogBlock, FileType, partition, File ); |
518 tmpmap.file = *File; | 685 tmpmap.file = *File; |
519 tmpmap.filetype = *FileType; | 686 tmpmap.filetype = *FileType; |
520 SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap); | 687 SetUDFCache(device, MapCache, tmpmap.lbn, &tmpmap); |
688 dvdalign_lbfree(device, LogBlock); | |
521 return 1; | 689 return 1; |
522 }; | 690 }; |
523 } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 ) | 691 } while( ( lbnum <= partition->Start + ICB.Location + ( ICB.Length - 1 ) |
524 / DVD_VIDEO_LB_LEN ) && ( TagID != 261 ) ); | 692 / DVD_VIDEO_LB_LEN ) && ( TagID != 261 ) ); |
525 | 693 |
694 dvdalign_lbfree(device, LogBlock); | |
526 return 0; | 695 return 0; |
527 } | 696 } |
528 | 697 |
529 /** | 698 /** |
530 * Dir: Location of directory to scan | 699 * Dir: Location of directory to scan |
535 static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, | 704 static int UDFScanDir( dvd_reader_t *device, struct AD Dir, char *FileName, |
536 struct Partition *partition, struct AD *FileICB, | 705 struct Partition *partition, struct AD *FileICB, |
537 int cache_file_info) | 706 int cache_file_info) |
538 { | 707 { |
539 char filename[ MAX_UDF_FILE_NAME_LEN ]; | 708 char filename[ MAX_UDF_FILE_NAME_LEN ]; |
540 uint8_t directory[ 2 * DVD_VIDEO_LB_LEN ]; | 709 uint8_t *directory; |
541 uint32_t lbnum; | 710 uint32_t lbnum; |
542 uint16_t TagID; | 711 uint16_t TagID; |
543 uint8_t filechar; | 712 uint8_t filechar; |
544 unsigned int p; | 713 unsigned int p; |
545 uint8_t *cached_dir = NULL; | 714 uint8_t *cached_dir = NULL; |
554 if(DVDUDFCacheLevel(device, -1) > 0) { | 723 if(DVDUDFCacheLevel(device, -1) > 0) { |
555 /* caching */ | 724 /* caching */ |
556 | 725 |
557 if(!GetUDFCache(device, LBUDFCache, lbnum, &cached_dir)) { | 726 if(!GetUDFCache(device, LBUDFCache, lbnum, &cached_dir)) { |
558 dir_lba = (Dir.Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN; | 727 dir_lba = (Dir.Length + DVD_VIDEO_LB_LEN) / DVD_VIDEO_LB_LEN; |
559 if((cached_dir = malloc(dir_lba * DVD_VIDEO_LB_LEN)) == NULL) { | 728 if((cached_dir = dvdalign_lbmalloc(device, dir_lba)) == NULL) { |
560 return 0; | 729 return 0; |
561 } | 730 } |
562 if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) { | 731 if( DVDReadLBUDF( device, lbnum, dir_lba, cached_dir, 0) <= 0 ) { |
563 free(cached_dir); | 732 dvdalign_lbfree(device, cached_dir); |
564 cached_dir = NULL; | 733 cached_dir = NULL; |
565 } | 734 } |
566 /* | |
567 if(cached_dir) { | |
568 fprintf(stderr, "malloc dir: %d\n", | |
569 dir_lba * DVD_VIDEO_LB_LEN); | |
570 } | |
571 */ | |
572 SetUDFCache(device, LBUDFCache, lbnum, &cached_dir); | 735 SetUDFCache(device, LBUDFCache, lbnum, &cached_dir); |
573 } else { | 736 } else { |
574 in_cache = 1; | 737 in_cache = 1; |
575 } | 738 } |
576 | 739 |
613 return 1; | 776 return 1; |
614 } | 777 } |
615 return 0; | 778 return 0; |
616 } | 779 } |
617 | 780 |
781 directory = dvdalign_lbmalloc(device, 2); | |
782 if(!directory) { | |
783 return 0; | |
784 } | |
618 if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { | 785 if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { |
786 dvdalign_lbfree(device, directory); | |
619 return 0; | 787 return 0; |
620 } | 788 } |
621 | 789 |
622 p = 0; | 790 p = 0; |
623 while( p < Dir.Length ) { | 791 while( p < Dir.Length ) { |
624 if( p > DVD_VIDEO_LB_LEN ) { | 792 if( p > DVD_VIDEO_LB_LEN ) { |
625 ++lbnum; | 793 ++lbnum; |
626 p -= DVD_VIDEO_LB_LEN; | 794 p -= DVD_VIDEO_LB_LEN; |
627 Dir.Length -= DVD_VIDEO_LB_LEN; | 795 Dir.Length -= DVD_VIDEO_LB_LEN; |
628 if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { | 796 if( DVDReadLBUDF( device, lbnum, 2, directory, 0 ) <= 0 ) { |
797 dvdalign_lbfree(device, directory); | |
629 return 0; | 798 return 0; |
630 } | 799 } |
631 } | 800 } |
632 UDFDescriptor( &directory[ p ], &TagID ); | 801 UDFDescriptor( &directory[ p ], &TagID ); |
633 if( TagID == 257 ) { | 802 if( TagID == 257 ) { |
634 p += UDFFileIdentifier( &directory[ p ], &filechar, | 803 p += UDFFileIdentifier( &directory[ p ], &filechar, |
635 filename, FileICB ); | 804 filename, FileICB ); |
636 if( !strcasecmp( FileName, filename ) ) { | 805 if( !strcasecmp( FileName, filename ) ) { |
806 dvdalign_lbfree(device, directory); | |
637 return 1; | 807 return 1; |
638 } | 808 } |
639 } else { | 809 } else { |
810 dvdalign_lbfree(device, directory); | |
640 return 0; | 811 return 0; |
641 } | 812 } |
642 } | 813 } |
643 | 814 |
815 dvdalign_lbfree(device, directory); | |
644 return 0; | 816 return 0; |
645 } | 817 } |
646 | 818 |
647 | 819 |
648 static int UDFGetAVDP( dvd_reader_t *device, | 820 static int UDFGetAVDP( dvd_reader_t *device, |
649 struct avdp_t *avdp) | 821 struct avdp_t *avdp) |
650 { | 822 { |
651 uint8_t Anchor[ DVD_VIDEO_LB_LEN ]; | 823 uint8_t *Anchor; |
652 uint32_t lbnum, MVDS_location, MVDS_length; | 824 uint32_t lbnum, MVDS_location, MVDS_length; |
653 uint16_t TagID; | 825 uint16_t TagID; |
654 uint32_t lastsector; | 826 uint32_t lastsector; |
655 int terminate; | 827 int terminate; |
656 struct avdp_t; | 828 struct avdp_t; |
662 /* Find Anchor */ | 834 /* Find Anchor */ |
663 lastsector = 0; | 835 lastsector = 0; |
664 lbnum = 256; /* Try #1, prime anchor */ | 836 lbnum = 256; /* Try #1, prime anchor */ |
665 terminate = 0; | 837 terminate = 0; |
666 | 838 |
839 Anchor = dvdalign_lbmalloc(device, 1); | |
840 if(!Anchor) { | |
841 return 0; | |
842 } | |
667 for(;;) { | 843 for(;;) { |
668 if( DVDReadLBUDF( device, lbnum, 1, Anchor, 0 ) > 0 ) { | 844 if( DVDReadLBUDF( device, lbnum, 1, Anchor, 0 ) > 0 ) { |
669 UDFDescriptor( Anchor, &TagID ); | 845 UDFDescriptor( Anchor, &TagID ); |
670 } else { | 846 } else { |
671 TagID = 0; | 847 TagID = 0; |
672 } | 848 } |
673 if (TagID != 2) { | 849 if (TagID != 2) { |
674 /* Not an anchor */ | 850 /* Not an anchor */ |
675 if( terminate ) return 0; /* Final try failed */ | 851 if( terminate ) { |
852 dvdalign_lbfree(device, Anchor); | |
853 errno = EMEDIUMTYPE; | |
854 return 0; /* Final try failed */ | |
855 } | |
676 | 856 |
677 if( lastsector ) { | 857 if( lastsector ) { |
678 | |
679 /* We already found the last sector. Try #3, alternative | 858 /* We already found the last sector. Try #3, alternative |
680 * backup anchor. If that fails, don't try again. | 859 * backup anchor. If that fails, don't try again. |
681 */ | 860 */ |
682 lbnum = lastsector; | 861 lbnum = lastsector; |
683 terminate = 1; | 862 terminate = 1; |
686 if( lastsector ) { | 865 if( lastsector ) { |
687 /* Try #2, backup anchor */ | 866 /* Try #2, backup anchor */ |
688 lbnum = lastsector - 256; | 867 lbnum = lastsector - 256; |
689 } else { | 868 } else { |
690 /* Unable to find last sector */ | 869 /* Unable to find last sector */ |
870 dvdalign_lbfree(device, Anchor); | |
871 errno = EMEDIUMTYPE; | |
691 return 0; | 872 return 0; |
692 } | 873 } |
693 } | 874 } |
694 } else { | 875 } else { |
695 /* It's an anchor! We can leave */ | 876 /* It's an anchor! We can leave */ |
706 avdp->rvds.location = MVDS_location; | 887 avdp->rvds.location = MVDS_location; |
707 avdp->rvds.length = MVDS_length; | 888 avdp->rvds.length = MVDS_length; |
708 | 889 |
709 SetUDFCache(device, AVDPCache, 0, avdp); | 890 SetUDFCache(device, AVDPCache, 0, avdp); |
710 | 891 |
892 dvdalign_lbfree(device, Anchor); | |
711 return 1; | 893 return 1; |
712 } | 894 } |
713 | 895 |
714 /** | 896 /** |
715 * Looks for partition on the disc. Returns 1 if partition found, 0 on error. | 897 * Looks for partition on the disc. Returns 1 if partition found, 0 on error. |
717 * part: structure to fill with the partition information | 899 * part: structure to fill with the partition information |
718 */ | 900 */ |
719 static int UDFFindPartition( dvd_reader_t *device, int partnum, | 901 static int UDFFindPartition( dvd_reader_t *device, int partnum, |
720 struct Partition *part ) | 902 struct Partition *part ) |
721 { | 903 { |
722 uint8_t LogBlock[ DVD_VIDEO_LB_LEN ]; | 904 uint8_t *LogBlock; |
723 uint32_t lbnum, MVDS_location, MVDS_length; | 905 uint32_t lbnum, MVDS_location, MVDS_length; |
724 uint16_t TagID; | 906 uint16_t TagID; |
725 int i, volvalid; | 907 int i, volvalid; |
726 struct avdp_t avdp; | 908 struct avdp_t avdp; |
727 | 909 |
728 | 910 |
729 if(!UDFGetAVDP(device, &avdp)) { | 911 if(!UDFGetAVDP(device, &avdp)) { |
730 return 0; | 912 return 0; |
731 } | 913 } |
732 | 914 |
915 LogBlock = dvdalign_lbmalloc(device, 1); | |
916 if(!LogBlock) { | |
917 return 0; | |
918 } | |
733 /* Main volume descriptor */ | 919 /* Main volume descriptor */ |
734 MVDS_location = avdp.mvds.location; | 920 MVDS_location = avdp.mvds.location; |
735 MVDS_length = avdp.mvds.length; | 921 MVDS_length = avdp.mvds.length; |
736 | 922 |
737 part->valid = 0; | 923 part->valid = 0; |
772 MVDS_location = avdp.mvds.location; | 958 MVDS_location = avdp.mvds.location; |
773 MVDS_length = avdp.mvds.length; | 959 MVDS_length = avdp.mvds.length; |
774 } | 960 } |
775 } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) ); | 961 } while( i-- && ( ( !part->valid ) || ( !volvalid ) ) ); |
776 | 962 |
963 dvdalign_lbfree(device, LogBlock); | |
777 /* We only care for the partition, not the volume */ | 964 /* We only care for the partition, not the volume */ |
778 return part->valid; | 965 return part->valid; |
779 } | 966 } |
780 | 967 |
781 uint32_t UDFFindFile( dvd_reader_t *device, char *filename, | 968 uint32_t UDFFindFile( dvd_reader_t *device, char *filename, |
782 uint32_t *filesize ) | 969 uint32_t *filesize ) |
783 { | 970 { |
784 uint8_t LogBlock[ DVD_VIDEO_LB_LEN ]; | 971 uint8_t *LogBlock; |
785 uint32_t lbnum; | 972 uint32_t lbnum; |
786 uint16_t TagID; | 973 uint16_t TagID; |
787 struct Partition partition; | 974 struct Partition partition; |
788 struct AD RootICB, File, ICB; | 975 struct AD RootICB, File, ICB; |
789 char tokenline[ MAX_UDF_FILE_NAME_LEN ]; | 976 char tokenline[ MAX_UDF_FILE_NAME_LEN ]; |
790 char *token; | 977 char *token; |
791 uint8_t filetype; | 978 uint8_t filetype; |
792 | 979 |
980 if(filesize) { | |
793 *filesize = 0; | 981 *filesize = 0; |
982 } | |
794 tokenline[0] = '\0'; | 983 tokenline[0] = '\0'; |
795 strcat( tokenline, filename ); | 984 strcat( tokenline, filename ); |
796 | 985 |
797 | 986 |
798 if(!(GetUDFCache(device, PartitionCache, 0, &partition) && | 987 if(!(GetUDFCache(device, PartitionCache, 0, &partition) && |
799 GetUDFCache(device, RootICBCache, 0, &RootICB))) { | 988 GetUDFCache(device, RootICBCache, 0, &RootICB))) { |
800 /* Find partition, 0 is the standard location for DVD Video.*/ | 989 /* Find partition, 0 is the standard location for DVD Video.*/ |
801 if( !UDFFindPartition( device, 0, &partition ) ) return 0; | 990 if( !UDFFindPartition( device, 0, &partition ) ) { |
991 return 0; | |
992 } | |
802 SetUDFCache(device, PartitionCache, 0, &partition); | 993 SetUDFCache(device, PartitionCache, 0, &partition); |
803 | 994 |
995 LogBlock = dvdalign_lbmalloc(device, 1); | |
996 if(!LogBlock) { | |
997 return 0; | |
998 } | |
804 /* Find root dir ICB */ | 999 /* Find root dir ICB */ |
805 lbnum = partition.Start; | 1000 lbnum = partition.Start; |
806 do { | 1001 do { |
807 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { | 1002 if( DVDReadLBUDF( device, lbnum++, 1, LogBlock, 0 ) <= 0 ) { |
808 TagID = 0; | 1003 TagID = 0; |
815 UDFLongAD( &LogBlock[ 400 ], &RootICB ); | 1010 UDFLongAD( &LogBlock[ 400 ], &RootICB ); |
816 } | 1011 } |
817 } while( ( lbnum < partition.Start + partition.Length ) | 1012 } while( ( lbnum < partition.Start + partition.Length ) |
818 && ( TagID != 8 ) && ( TagID != 256 ) ); | 1013 && ( TagID != 8 ) && ( TagID != 256 ) ); |
819 | 1014 |
1015 dvdalign_lbfree(device, LogBlock); | |
1016 | |
820 /* Sanity checks. */ | 1017 /* Sanity checks. */ |
821 if( TagID != 256 ) return 0; | 1018 if( TagID != 256 ) { |
822 if( RootICB.Partition != 0 ) return 0; | 1019 return 0; |
1020 } | |
1021 if( RootICB.Partition != 0 ) { | |
1022 return 0; | |
1023 } | |
823 SetUDFCache(device, RootICBCache, 0, &RootICB); | 1024 SetUDFCache(device, RootICBCache, 0, &RootICB); |
824 } | 1025 } |
825 | 1026 |
826 /* Find root dir */ | 1027 /* Find root dir */ |
827 if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) return 0; | 1028 if( !UDFMapICB( device, RootICB, &filetype, &partition, &File ) ) { |
828 if( filetype != 4 ) return 0; /* Root dir should be dir */ | 1029 return 0; |
829 | 1030 } |
1031 if( filetype != 4 ) { | |
1032 return 0; /* Root dir should be dir */ | |
1033 } | |
830 { | 1034 { |
831 int cache_file_info = 0; | 1035 int cache_file_info = 0; |
832 /* Tokenize filepath */ | 1036 /* Tokenize filepath */ |
833 token = strtok(tokenline, "/"); | 1037 token = strtok(tokenline, "/"); |
834 | 1038 |
847 token = strtok( NULL, "/" ); | 1051 token = strtok( NULL, "/" ); |
848 } | 1052 } |
849 } | 1053 } |
850 | 1054 |
851 /* Sanity check. */ | 1055 /* Sanity check. */ |
852 if( File.Partition != 0 ) return 0; | 1056 if( File.Partition != 0 ) { |
1057 return 0; | |
1058 } | |
853 | 1059 |
1060 if(filesize) { | |
854 *filesize = File.Length; | 1061 *filesize = File.Length; |
1062 } | |
855 /* Hack to not return partition.Start for empty files. */ | 1063 /* Hack to not return partition.Start for empty files. */ |
856 if( !File.Location ) | 1064 if( !File.Location ) { |
857 return 0; | 1065 return 0; |
858 else | 1066 } else { |
859 return partition.Start + File.Location; | 1067 return partition.Start + File.Location; |
1068 } | |
860 } | 1069 } |
861 | 1070 |
862 | 1071 |
863 | 1072 |
864 /** | 1073 /** |
865 * Gets a Descriptor . | 1074 * Gets a Descriptor . |
866 * Returns 1 if descriptor found, 0 on error. | 1075 * Returns 1 if descriptor found, 0 on error. |
867 * id, tagid of descriptor | 1076 * id, tagid of descriptor |
868 * bufsize, size of BlockBuf (must be >= DVD_VIDEO_LB_LEN). | 1077 * bufsize, size of BlockBuf (must be >= DVD_VIDEO_LB_LEN) |
1078 * and aligned for raw/O_DIRECT read. | |
869 */ | 1079 */ |
870 static int UDFGetDescriptor( dvd_reader_t *device, int id, | 1080 static int UDFGetDescriptor( dvd_reader_t *device, int id, |
871 uint8_t *descriptor, int bufsize) | 1081 uint8_t *descriptor, int bufsize) |
872 { | 1082 { |
873 uint32_t lbnum, MVDS_location, MVDS_length; | 1083 uint32_t lbnum, MVDS_location, MVDS_length; |
917 MVDS_location = avdp.rvds.location; | 1127 MVDS_location = avdp.rvds.location; |
918 MVDS_length = avdp.rvds.length; | 1128 MVDS_length = avdp.rvds.length; |
919 } | 1129 } |
920 } while( i-- && ( !desc_found ) ); | 1130 } while( i-- && ( !desc_found ) ); |
921 | 1131 |
1132 | |
922 return desc_found; | 1133 return desc_found; |
923 } | 1134 } |
924 | 1135 |
925 | 1136 |
926 static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd) | 1137 static int UDFGetPVD(dvd_reader_t *device, struct pvd_t *pvd) |
927 { | 1138 { |
928 uint8_t pvd_buf[DVD_VIDEO_LB_LEN]; | 1139 uint8_t *pvd_buf; |
929 | 1140 |
930 if(GetUDFCache(device, PVDCache, 0, pvd)) { | 1141 if(GetUDFCache(device, PVDCache, 0, pvd)) { |
931 return 1; | 1142 return 1; |
932 } | 1143 } |
933 | 1144 |
934 if(!UDFGetDescriptor( device, 1, pvd_buf, sizeof(pvd_buf))) { | 1145 pvd_buf = dvdalign_lbmalloc(device, 1); |
1146 if(!pvd_buf) { | |
1147 return 0; | |
1148 } | |
1149 if(!UDFGetDescriptor( device, 1, pvd_buf, 1*DVD_VIDEO_LB_LEN)) { | |
1150 dvdalign_lbfree(device, pvd_buf); | |
935 return 0; | 1151 return 0; |
936 } | 1152 } |
937 | 1153 |
938 memcpy(pvd->VolumeIdentifier, &pvd_buf[24], 32); | 1154 memcpy(pvd->VolumeIdentifier, &pvd_buf[24], 32); |
939 memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128); | 1155 memcpy(pvd->VolumeSetIdentifier, &pvd_buf[72], 128); |
940 SetUDFCache(device, PVDCache, 0, pvd); | 1156 SetUDFCache(device, PVDCache, 0, pvd); |
941 | 1157 |
1158 dvdalign_lbfree(device, pvd_buf); | |
1159 | |
942 return 1; | 1160 return 1; |
943 } | 1161 } |
944 | 1162 |
945 /** | 1163 /** |
946 * Gets the Volume Identifier string, in 8bit unicode (latin-1) | 1164 * Gets the Volume Identifier string, in 8bit unicode (latin-1) |