5 // Created by Sam McCall on 4/05/09.
13 @implementation NJMapping {
14 NSMutableDictionary *_entries;
17 // Extra checks during initialization because the data is often loaded
18 // from untrusted serializations.
21 if ((self = [super init])) {
22 self.name = NSLocalizedString(@"Untitled", @"name for new mappings");
23 _entries = [[NSMutableDictionary alloc] init];
28 - (id)initWithName:(NSString *)name {
29 if ((self = [self init])) {
30 if ([name isKindOfClass:NSString.class])
36 - (id)initWithSerialization:(NSDictionary *)serialization {
37 if ((self = [self initWithName:serialization[@"name"]])) {
38 NSDictionary *entries = serialization[@"entries"];
39 if ([entries isKindOfClass:NSDictionary.class]) {
40 for (id key in entries) {
41 if ([key isKindOfClass:NSString.class]) {
42 NJOutput *output = [NJOutput outputDeserialize:entries[key]];
44 _entries[key] = output;
52 - (NJOutput *)objectForKeyedSubscript:(NJInput *)input {
53 return input ? _entries[input.uid] : nil;
56 - (void)setObject:(NJOutput *)output forKeyedSubscript:(NJInput *)input {
59 _entries[input.uid] = output;
61 [_entries removeObjectForKey:input.uid];
65 - (NSDictionary *)serialize {
66 NSMutableDictionary *entries = [[NSMutableDictionary alloc] initWithCapacity:_entries.count];
67 for (id key in _entries) {
68 id serialized = [_entries[key] serialize];
70 entries[key] = serialized;
72 return @{ @"name": _name, @"entries": entries };
75 - (BOOL)writeToURL:(NSURL *)url error:(NSError **)error {
76 [NSProcessInfo.processInfo disableSuddenTermination];
77 NSDictionary *serialization = [self serialize];
78 NSData *json = [NSJSONSerialization dataWithJSONObject:serialization
79 options:NSJSONWritingPrettyPrinted
81 BOOL success = json && [json writeToURL:url options:NSDataWritingAtomic error:error];
82 [NSProcessInfo.processInfo enableSuddenTermination];
87 return _entries.count;
90 - (BOOL)hasConflictWith:(NJMapping *)other {
91 if (other.count < self.count)
92 return [other hasConflictWith:self];
93 for (NSString *uid in _entries) {
94 NJOutput *output = other->_entries[uid];
95 if (output && ![output isEqual:_entries[uid]])
101 + (id)mappingWithContentsOfURL:(NSURL *)url error:(NSError **)error {
102 NSInputStream *stream = [NSInputStream inputStreamWithURL:url];
104 NSDictionary *serialization = stream && !*error
105 ? [NSJSONSerialization JSONObjectWithStream:stream options:0 error:error]
109 if (!serialization && error)
112 if (!([serialization isKindOfClass:NSDictionary.class]
113 && [serialization[@"name"] isKindOfClass:NSString.class]
114 && [serialization[@"entries"] isKindOfClass:NSDictionary.class])) {
115 *error = [NSError errorWithDomain:@"Enjoyable"
117 description:NSLocalizedString(@"invalid mapping file",
118 @"error when imported file was JSON but not a mapping")];
122 return [[NJMapping alloc] initWithSerialization:serialization];
125 - (void)mergeEntriesFrom:(NJMapping *)other {
127 [_entries addEntriesFromDictionary:other->_entries];
130 - (void)postLoadProcess:(id <NSFastEnumeration>)allMappings {
131 for (NJOutput *o in _entries.allValues)
132 [o postLoadProcess:allMappings];