You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
11 KiB
Objective-C
254 lines
11 KiB
Objective-C
/*
|
|
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
|