123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- /*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
- */
-
- #import "CDVFile.h"
- #import "CDVAssetLibraryFilesystem.h"
- #import <Cordova/CDV.h>
- #import <AssetsLibrary/ALAsset.h>
- #import <AssetsLibrary/ALAssetRepresentation.h>
- #import <AssetsLibrary/ALAssetsLibrary.h>
- #import <MobileCoreServices/MobileCoreServices.h>
-
- NSString* const kCDVAssetsLibraryPrefix = @"assets-library://";
- NSString* const kCDVAssetsLibraryScheme = @"assets-library";
-
- @implementation CDVAssetLibraryFilesystem
- @synthesize name=_name, urlTransformer;
-
-
- /*
- The CDVAssetLibraryFilesystem works with resources which are identified
- by iOS as
- asset-library://<path>
- and represents them internally as URLs of the form
- cdvfile://localhost/assets-library/<path>
- */
-
- - (NSURL *)assetLibraryURLForLocalURL:(CDVFilesystemURL *)url
- {
- if ([url.url.scheme isEqualToString:kCDVFilesystemURLPrefix]) {
- NSString *path = [[url.url absoluteString] substringFromIndex:[@"cdvfile://localhost/assets-library" length]];
- return [NSURL URLWithString:[NSString stringWithFormat:@"assets-library:/%@", path]];
- }
- return url.url;
- }
-
- - (CDVPluginResult *)entryForLocalURI:(CDVFilesystemURL *)url
- {
- NSDictionary* entry = [self makeEntryForLocalURL:url];
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:entry];
- }
-
- - (NSDictionary *)makeEntryForLocalURL:(CDVFilesystemURL *)url {
- return [self makeEntryForPath:url.fullPath isDirectory:NO];
- }
-
- - (NSDictionary*)makeEntryForPath:(NSString*)fullPath isDirectory:(BOOL)isDir
- {
- NSMutableDictionary* dirEntry = [NSMutableDictionary dictionaryWithCapacity:5];
- NSString* lastPart = [fullPath lastPathComponent];
- if (isDir && ![fullPath hasSuffix:@"/"]) {
- fullPath = [fullPath stringByAppendingString:@"/"];
- }
- [dirEntry setObject:[NSNumber numberWithBool:!isDir] forKey:@"isFile"];
- [dirEntry setObject:[NSNumber numberWithBool:isDir] forKey:@"isDirectory"];
- [dirEntry setObject:fullPath forKey:@"fullPath"];
- [dirEntry setObject:lastPart forKey:@"name"];
- [dirEntry setObject:self.name forKey: @"filesystemName"];
-
- NSURL* nativeURL = [NSURL URLWithString:[NSString stringWithFormat:@"assets-library:/%@",fullPath]];
- if (self.urlTransformer) {
- nativeURL = self.urlTransformer(nativeURL);
- }
- dirEntry[@"nativeURL"] = [nativeURL absoluteString];
-
- return dirEntry;
- }
-
- /* helper function to get the mimeType from the file extension
- * IN:
- * NSString* fullPath - filename (may include path)
- * OUT:
- * NSString* the mime type as type/subtype. nil if not able to determine
- */
- + (NSString*)getMimeTypeFromPath:(NSString*)fullPath
- {
- NSString* mimeType = nil;
-
- if (fullPath) {
- CFStringRef typeId = UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)[fullPath pathExtension], NULL);
- if (typeId) {
- mimeType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass(typeId, kUTTagClassMIMEType);
- if (!mimeType) {
- // special case for m4a
- if ([(__bridge NSString*)typeId rangeOfString : @"m4a-audio"].location != NSNotFound) {
- mimeType = @"audio/mp4";
- } else if ([[fullPath pathExtension] rangeOfString:@"wav"].location != NSNotFound) {
- mimeType = @"audio/wav";
- } else if ([[fullPath pathExtension] rangeOfString:@"css"].location != NSNotFound) {
- mimeType = @"text/css";
- }
- }
- CFRelease(typeId);
- }
- }
- return mimeType;
- }
-
- - (id)initWithName:(NSString *)name
- {
- if (self) {
- self.name = name;
- }
- return self;
- }
-
- - (CDVPluginResult *)getFileForURL:(CDVFilesystemURL *)baseURI requestedPath:(NSString *)requestedPath options:(NSDictionary *)options
- {
- // return unsupported result for assets-library URLs
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"getFile not supported for assets-library URLs."];
- }
-
- - (CDVPluginResult*)getParentForURL:(CDVFilesystemURL *)localURI
- {
- // we don't (yet?) support getting the parent of an asset
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_READABLE_ERR];
- }
-
- - (CDVPluginResult*)setMetadataForURL:(CDVFilesystemURL *)localURI withObject:(NSDictionary *)options
- {
- // setMetadata doesn't make sense for asset library files
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR];
- }
-
- - (CDVPluginResult *)removeFileAtURL:(CDVFilesystemURL *)localURI
- {
- // return error for assets-library URLs
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR];
- }
-
- - (CDVPluginResult *)recursiveRemoveFileAtURL:(CDVFilesystemURL *)localURI
- {
- // return error for assets-library URLs
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"removeRecursively not supported for assets-library URLs."];
- }
-
- - (CDVPluginResult *)readEntriesAtURL:(CDVFilesystemURL *)localURI
- {
- // return unsupported result for assets-library URLs
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"readEntries not supported for assets-library URLs."];
- }
-
- - (CDVPluginResult *)truncateFileAtURL:(CDVFilesystemURL *)localURI atPosition:(unsigned long long)pos
- {
- // assets-library files can't be truncated
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
- }
-
- - (CDVPluginResult *)writeToFileAtURL:(CDVFilesystemURL *)localURL withData:(NSData*)encData append:(BOOL)shouldAppend
- {
- // text can't be written into assets-library files
- return [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NO_MODIFICATION_ALLOWED_ERR];
- }
-
- - (void)copyFileToURL:(CDVFilesystemURL *)destURL withName:(NSString *)newName fromFileSystem:(NSObject<CDVFileSystem> *)srcFs atURL:(CDVFilesystemURL *)srcURL copy:(BOOL)bCopy callback:(void (^)(CDVPluginResult *))callback
- {
- // Copying to an assets library file is not doable, since we can't write it.
- CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:INVALID_MODIFICATION_ERR];
- callback(result);
- }
-
- - (NSString *)filesystemPathForURL:(CDVFilesystemURL *)url
- {
- NSString *path = nil;
- if ([[url.url scheme] isEqualToString:kCDVAssetsLibraryScheme]) {
- path = [url.url path];
- } else {
- path = url.fullPath;
- }
- if ([path hasSuffix:@"/"]) {
- path = [path substringToIndex:([path length]-1)];
- }
- return path;
- }
-
- - (void)readFileAtURL:(CDVFilesystemURL *)localURL start:(NSInteger)start end:(NSInteger)end callback:(void (^)(NSData*, NSString* mimeType, CDVFileError))callback
- {
- ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
- if (asset) {
- // We have the asset! Get the data and send it off.
- ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
- NSUInteger size = (end > start) ? (end - start) : [assetRepresentation size];
- Byte* buffer = (Byte*)malloc(size);
- NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:start length:size error:nil];
- NSData* data = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES];
- NSString* MIMEType = (__bridge_transfer NSString*)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)[assetRepresentation UTI], kUTTagClassMIMEType);
-
- callback(data, MIMEType, NO_ERROR);
- } else {
- callback(nil, nil, NOT_FOUND_ERR);
- }
- };
-
- ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
- // Retrieving the asset failed for some reason. Send the appropriate error.
- NSLog(@"Error: %@", error);
- callback(nil, nil, SECURITY_ERR);
- };
-
- ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
- [assetsLibrary assetForURL:[self assetLibraryURLForLocalURL:localURL] resultBlock:resultBlock failureBlock:failureBlock];
- }
-
- - (void)getFileMetadataForURL:(CDVFilesystemURL *)localURL callback:(void (^)(CDVPluginResult *))callback
- {
- // In this case, we need to use an asynchronous method to retrieve the file.
- // Because of this, we can't just assign to `result` and send it at the end of the method.
- // Instead, we return after calling the asynchronous method and send `result` in each of the blocks.
- ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset* asset) {
- if (asset) {
- // We have the asset! Populate the dictionary and send it off.
- NSMutableDictionary* fileInfo = [NSMutableDictionary dictionaryWithCapacity:5];
- ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation];
- [fileInfo setObject:[NSNumber numberWithUnsignedLongLong:[assetRepresentation size]] forKey:@"size"];
- [fileInfo setObject:localURL.fullPath forKey:@"fullPath"];
- NSString* filename = [assetRepresentation filename];
- [fileInfo setObject:filename forKey:@"name"];
- [fileInfo setObject:[CDVAssetLibraryFilesystem getMimeTypeFromPath:filename] forKey:@"type"];
- NSDate* creationDate = [asset valueForProperty:ALAssetPropertyDate];
- NSNumber* msDate = [NSNumber numberWithDouble:[creationDate timeIntervalSince1970] * 1000];
- [fileInfo setObject:msDate forKey:@"lastModifiedDate"];
-
- callback([CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:fileInfo]);
- } else {
- // We couldn't find the asset. Send the appropriate error.
- callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]);
- }
- };
- ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError* error) {
- // Retrieving the asset failed for some reason. Send the appropriate error.
- callback([CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]);
- };
-
- ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init];
- [assetsLibrary assetForURL:[self assetLibraryURLForLocalURL:localURL] resultBlock:resultBlock failureBlock:failureBlock];
- return;
- }
- @end
|