xref: /aosp_15_r20/external/executorch/backends/apple/coreml/runtime/delegate/asset.mm (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
1//
2// ModelAsset.cpp
3//
4// Copyright © 2024 Apple Inc. All rights reserved.
5//
6// Please refer to the license found in the LICENSE file in the root directory of the source tree.
7
8
9#import <asset.h>
10
11#import <optional>
12
13#import <objc_safe_cast.h>
14
15namespace  {
16
17NSNumber * _Nullable is_regular_file(NSURL *url, NSError * __autoreleasing *error) {
18    NSNumber *result = nil;
19    if (![url getResourceValue:&result forKey:NSURLIsRegularFileKey error:error]) {
20        return nil;
21    }
22
23    return SAFE_CAST(result, NSNumber);
24}
25
26NSNumber * _Nullable get_total_allocated_file_size(NSURL *url, NSError * __autoreleasing *error) {
27    NSNumber *result = nil;
28    if (![url getResourceValue:&result forKey:NSURLTotalFileAllocatedSizeKey error:error]) {
29        return nil;
30    }
31
32    return SAFE_CAST(result, NSNumber);
33}
34
35NSNumber * _Nullable get_allocated_file_size(NSURL *url, NSError * __autoreleasing *error) {
36    NSNumber *result = nil;
37    if (![url getResourceValue:&result forKey:NSURLFileAllocatedSizeKey error:error]) {
38        return nil;
39    }
40
41    return SAFE_CAST(result, NSNumber);
42}
43
44NSDate * _Nullable get_modification_date(NSURL *url, NSError * __autoreleasing *error) {
45    NSDate *result = nil;
46    if (![url getResourceValue:&result forKey:NSURLContentModificationDateKey error:error]) {
47        return nil;
48    }
49
50    return SAFE_CAST(result, NSDate);
51}
52
53void set_error_from_local_error( NSError * __autoreleasing *error, NSError *local_error) {
54    if (local_error && error) {
55        *error = local_error;
56    }
57}
58
59std::optional<executorchcoreml::PackageInfo>
60get_package_info(NSURL *directory_url, NSFileManager *fm, NSError * __autoreleasing *error) {
61    NSArray<NSString *> *properties = @[NSURLIsRegularFileKey, NSURLFileAllocatedSizeKey, NSURLTotalFileAllocatedSizeKey];
62
63    __block NSError *local_error = nil;
64    BOOL (^errorHandler)(NSURL *url, NSError *error) = ^BOOL(NSURL *url, NSError *enumeration_error) {
65        local_error = enumeration_error;
66        return NO;
67    };
68
69    NSDirectoryEnumerator *enumerator = [fm enumeratorAtURL:directory_url
70                                 includingPropertiesForKeys:properties
71                                                    options:NSDirectoryEnumerationProducesRelativePathURLs
72                                               errorHandler:errorHandler];
73
74    auto result = executorchcoreml::PackageInfo {.name = directory_url.lastPathComponent.UTF8String};
75    for (NSURL *item_url in enumerator) {
76        if (local_error != nil) {
77            set_error_from_local_error(error, local_error);
78            return std::nullopt;
79        }
80
81        NSURL *file_url = [NSURL fileURLWithPath:item_url.path relativeToURL:directory_url];
82        if (!file_url) {
83            continue;
84        }
85
86        if (!is_regular_file(file_url, &local_error).boolValue) {
87            continue;
88        }
89
90        NSNumber *size = get_total_allocated_file_size(file_url, &local_error) ?: get_allocated_file_size(file_url, &local_error);
91        if (!size) {
92            break;
93        }
94
95        NSDate *last_modification_date = get_modification_date(file_url, &local_error);
96        if (!last_modification_date) {
97            break;
98        }
99
100        int64_t last_modification_time_interval = static_cast<int64_t>(last_modification_date.timeIntervalSince1970 * 1000);
101        auto fileInfo = executorchcoreml::FileInfo {
102            .relative_path = std::string(item_url.relativePath.UTF8String),
103            .size_in_bytes = size.unsignedLongLongValue,
104            .last_modification_time_interval = last_modification_time_interval
105        };
106
107        result.file_infos.emplace_back(std::move(fileInfo));
108    }
109
110    if (local_error) {
111        set_error_from_local_error(error, local_error);
112        return std::nullopt;
113    }
114
115    return result;
116}
117
118}
119
120namespace executorchcoreml {
121
122std::optional<Asset> Asset::make(NSURL *url,
123                                 NSString *identifier,
124                                 NSFileManager *fm,
125                                 NSError * __autoreleasing *error) {
126    auto package_info = get_package_info(url, fm, error);
127    if (!package_info) {
128        return std::nullopt;
129    }
130
131    return Asset(identifier.UTF8String, url.path.UTF8String, std::move(package_info.value()));
132}
133}
134