OSDN Git Service

MacGui: Remove Target Size as a rate control option as it doesn't really work correct...
[handbrake-jp/handbrake-jp-git.git] / macosx / HBDVDDetector.m
1 /**
2  * HBDriveDetector.m
3  * 8/17/2007
4  * 
5  * This file is part of the HandBrake source code.
6  * Homepage: <http://handbrake.fr/>.
7  * It may be used under the terms of the GNU General Public License.
8  */
9
10 #include <IOKit/IOKitLib.h>
11 #include <IOKit/storage/IOMedia.h>
12 #include <IOKit/storage/IODVDMedia.h>
13
14 #import "HBDVDDetector.h"
15
16
17 @interface HBDVDDetector (Private)
18
19 - (NSString *)bsdNameForPath;
20 - (BOOL)pathHasVideoTS;
21 - (BOOL)deviceIsDVD;
22 - (io_service_t)getIOKitServiceForBSDName;
23 - (BOOL)isDVDService: (io_service_t)service;
24 - (BOOL)isWholeMediaService: (io_service_t)service;
25
26 @end
27
28
29 @implementation HBDVDDetector
30
31 + (HBDVDDetector *)detectorForPath: (NSString *)aPath
32 {
33     return [[[self alloc] initWithPath:aPath] autorelease];
34 }
35
36
37 - (HBDVDDetector *)initWithPath: (NSString *)aPath
38 {
39     NSAssert(aPath, @"nil string passed to drive detector.");
40         if( self = [super init] )       
41         {
42         path = [aPath retain];
43         bsdName = nil;
44         }
45     return self;
46 }
47
48
49 - (void)dealloc
50 {
51     [path release];
52     path = nil;
53     [bsdName release];
54     bsdName = nil;
55     [super dealloc];
56 }
57
58
59 - (BOOL)isVideoDVD
60 {
61     if( !bsdName )
62     {
63         bsdName = [[self bsdNameForPath] retain];
64     }
65     return ( [self pathHasVideoTS] && [self deviceIsDVD] );
66 }
67
68
69 - (NSString *)devicePath
70 {
71     if( !bsdName )
72     {
73         bsdName = [[self bsdNameForPath] retain];
74     }
75     return [NSString stringWithFormat:@"/dev/%@", bsdName];
76 }
77
78 @end
79
80
81 @implementation HBDVDDetector (Private)
82
83 - (NSString *)bsdNameForPath
84 {
85     OSStatus err;
86     FSRef ref;
87     err = FSPathMakeRef( (const UInt8 *) [path fileSystemRepresentation],
88                          &ref, NULL );  
89     if( err != noErr )
90     {
91         return nil;
92     }
93
94     // Get the volume reference number.
95     FSCatalogInfo catalogInfo;
96     err = FSGetCatalogInfo( &ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL,
97                             NULL);
98     if( err != noErr )
99     {
100         return nil;
101     }
102     FSVolumeRefNum volRefNum = catalogInfo.volume;
103
104     // Now let's get the device name
105     GetVolParmsInfoBuffer volumeParms;
106     err = FSGetVolumeParms ( volRefNum, &volumeParms, sizeof( volumeParms ) );
107
108     if( err != noErr )
109     {
110         return nil;
111     }
112
113     // A version 4 GetVolParmsInfoBuffer contains the BSD node name in the vMDeviceID field.
114     // It is actually a char * value. This is mentioned in the header CoreServices/CarbonCore/Files.h.
115     if( volumeParms.vMVersion < 4 )
116     {
117         return nil;
118     }
119
120     // vMDeviceID might be zero as is reported with experimental ZFS (zfs-119) support in Leopard.
121     if( !volumeParms.vMDeviceID )
122     {
123         return nil;
124     }
125
126     return [NSString stringWithUTF8String:(const char *)volumeParms.vMDeviceID];
127 }
128
129
130 - (BOOL)pathHasVideoTS
131 {
132     // Check one level under the path
133     if( [[NSFileManager defaultManager] fileExistsAtPath:
134         [path stringByAppendingPathComponent:@"VIDEO_TS"]] )
135     {
136         return YES;
137     }
138
139     // Now check above the path
140     return [[path pathComponents] containsObject:@"VIDEO_TS"];
141 }
142
143
144 - (BOOL)deviceIsDVD
145 {
146     io_service_t service = [self getIOKitServiceForBSDName];
147     if( service == IO_OBJECT_NULL )
148     {
149         return NO;
150     }
151     BOOL result = [self isDVDService:service];
152     IOObjectRelease(service);
153     return result;
154 }
155
156
157 - (io_service_t)getIOKitServiceForBSDName
158 {
159     CFMutableDictionaryRef  matchingDict;
160     matchingDict = IOBSDNameMatching( kIOMasterPortDefault, 0, [bsdName UTF8String] );
161     if( matchingDict == NULL )
162     {
163         return IO_OBJECT_NULL;
164     }
165         
166     // Fetch the object with the matching BSD node name. There should only be
167     // one match, so IOServiceGetMatchingService is used instead of
168     // IOServiceGetMatchingServices to simplify the code.
169     return IOServiceGetMatchingService( kIOMasterPortDefault, matchingDict );    
170 }
171
172
173 - (BOOL)isDVDService: (io_service_t)service
174 {
175     // Find the IOMedia object that represents the entire (whole) media that the
176     // volume is on. 
177     //
178     // If the volume is on partitioned media, the whole media object will be a
179     // parent of the volume's media object. If the media is not partitioned, the
180     // volume's media object will be the whole media object.
181     // 
182     // The whole media object is indicated in the IORegistry by the presence of
183     // a property with the key "Whole" and value "Yes".
184
185     // Create an iterator across all parents of the service object passed in.
186     kern_return_t  kernResult;
187     io_iterator_t  iter;
188     kernResult = IORegistryEntryCreateIterator( service,
189                                                 kIOServicePlane,
190                                                 kIORegistryIterateRecursively | kIORegistryIterateParents,
191                                                 &iter );
192     if( kernResult != KERN_SUCCESS )
193     {
194         return NO;
195     }
196     if( iter == IO_OBJECT_NULL )
197     {
198         return NO;
199     }
200
201
202     // A reference on the initial service object is released in the do-while loop below,
203     // so add a reference to balance.
204     IOObjectRetain( service );
205
206     BOOL isDVD = NO;
207     do
208     {
209         isDVD = ( [self isWholeMediaService:service] &&
210                   IOObjectConformsTo(service, kIODVDMediaClass) );
211         IOObjectRelease(service);
212     } while( !isDVD && (service = IOIteratorNext(iter)) );
213     IOObjectRelease( iter );
214
215     return isDVD;
216 }
217
218
219 - (BOOL)isWholeMediaService: (io_service_t)service
220 {
221     //
222     // Determine if the object passed in represents an IOMedia (or subclass) object.
223     // If it does, test the "Whole" property.
224     //
225     
226     Boolean isWholeMedia = NO;
227     
228     if( IOObjectConformsTo(service, kIOMediaClass) )
229     {
230         CFTypeRef wholeMedia;
231         wholeMedia = IORegistryEntryCreateCFProperty( service, 
232                                                       CFSTR(kIOMediaWholeKey), 
233                                                       kCFAllocatorDefault, 
234                                                       0);
235         if( !wholeMedia )
236         {
237             return NO;
238         }
239         isWholeMedia = CFBooleanGetValue( (CFBooleanRef)wholeMedia );
240         CFRelease(wholeMedia);
241     }
242
243     return isWholeMedia;
244 }
245
246
247 @end