diff options
Diffstat (limited to 'bindings/objc/src/SwordModule.mm')
-rw-r--r-- | bindings/objc/src/SwordModule.mm | 735 |
1 files changed, 735 insertions, 0 deletions
diff --git a/bindings/objc/src/SwordModule.mm b/bindings/objc/src/SwordModule.mm new file mode 100644 index 0000000..12e2ad8 --- /dev/null +++ b/bindings/objc/src/SwordModule.mm @@ -0,0 +1,735 @@ +/* SwordModule.mm - Sword API wrapper for Modules. + + Copyright 2008 Manfred Bergmann + Based on code by Will Thimbleby + + This program is free software; you can redistribute it and/or modify it under the terms of the + GNU General Public License as published by the Free Software Foundation version 2. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. (http://www.gnu.org/licenses/gpl.html) +*/ + +#import "ObjCSword_Prefix.pch" +#import "SwordModule.h" +#import "SwordManager.h" +#import "SwordModuleTextEntry.h" +#import "SwordVerseKey.h" +#import "SwordBible.h" +#import "SwordCommentary.h" +#import "SwordDictionary.h" +#import "SwordBook.h" +#import "SwordFilter.h" + +@interface SwordModule () + +@property (retain, readwrite) NSString *name; +@property (retain, readwrite) NSString *typeString; +@property (retain, readwrite) NSString *descr; +@property (retain, readwrite) NSString *lang; +@property(readwrite, retain) NSMutableDictionary *configEntries; + +- (void)mainInit; + +@end + +@implementation SwordModule + +@synthesize configEntries; +@synthesize type; +@synthesize status; +@synthesize moduleLock; +@synthesize indexLock; +@synthesize swManager; +@synthesize name; +@synthesize typeString; +@synthesize descr; +@synthesize lang; + + ++ (id)moduleForSWModule:(sword::SWModule *)aModule { + return [[[SwordModule alloc] initWithSWModule:aModule] autorelease]; +} + ++ (id)moduleForSWModule:(sword::SWModule *)aModule swordManager:(SwordManager *)aManager { + return [[[SwordModule alloc] initWithSWModule:aModule swordManager:aManager] autorelease]; +} + ++ (id)moduleForType:(ModuleType)aType swModule:(sword::SWModule *)swModule swordManager:(SwordManager *)aManager { + SwordModule *sm; + if(aType == Bible) { + sm = [[[SwordBible alloc] initWithSWModule:swModule swordManager:aManager] autorelease]; + } else if(aType == Commentary) { + sm = [[[SwordCommentary alloc] initWithSWModule:swModule swordManager:aManager] autorelease]; + } else if(aType == Dictionary) { + sm = [[[SwordDictionary alloc] initWithSWModule:swModule swordManager:aManager] autorelease]; + } else if(aType == Genbook) { + sm = [[[SwordBook alloc] initWithSWModule:swModule swordManager:aManager] autorelease]; + } else { + sm = [[[SwordModule alloc] initWithSWModule:swModule swordManager:aManager] autorelease]; + } + + return sm; +} + ++ (ModuleType)moduleTypeForModuleTypeString:(NSString *)typeStr { + ModuleType ret = Bible; + + if(typeStr == nil) { + ALog(@"have a nil typeStr!"); + return ret; + } + + if([typeStr isEqualToString:SWMOD_TYPES_BIBLES]) { + ret = Bible; + } else if([typeStr isEqualToString:SWMOD_TYPES_COMMENTARIES]) { + ret = Commentary; + } else if([typeStr isEqualToString:SWMOD_TYPES_DICTIONARIES]) { + ret = Dictionary; + } else if([typeStr isEqualToString:SWMOD_TYPES_GENBOOKS]) { + ret = Genbook; + } + + return ret; +} + ++ (ModuleCategory)moduleCategoryForModuleCategoryString:(NSString *)categoryStr { + ModuleCategory ret = NoCategory; + + if(categoryStr == nil) { + ALog(@"have a nil categoryStr!"); + return ret; + } + + if([categoryStr isEqualToString:SWMOD_CATEGORY_MAPS]) { + ret = Maps; + } else if([categoryStr isEqualToString:SWMOD_CATEGORY_IMAGES]) { + ret = Images; + } else if([categoryStr isEqualToString:SWMOD_CATEGORY_DAILYDEVS]) { + ret = DailyDevotion; + } else if([categoryStr isEqualToString:SWMOD_CATEGORY_ESSEYS]) { + ret = Essays; + } else if([categoryStr isEqualToString:SWMOD_CATEGORY_GLOSSARIES]) { + ret = Glossary; + } else if([categoryStr isEqualToString:SWMOD_CATEGORY_CULTS]) { + ret = Cults; + } + + return ret; +} + +#pragma mark - Initializer + +- (void)mainInit { + category = Unset; + self.name = [self retrieveName]; + self.typeString = [self retrieveType]; + self.descr = [self retrieveDescr]; + self.lang = [self retrieveLang]; + + self.type = [SwordModule moduleTypeForModuleTypeString:self.typeString]; + self.moduleLock = [[[NSRecursiveLock alloc] init] autorelease]; + self.indexLock = [[[NSLock alloc] init] autorelease]; + self.configEntries = [NSMutableDictionary dictionary]; +} + +- (id)initWithName:(NSString *)aName swordManager:(SwordManager *)aManager { + self = [super init]; + if(self) { + swModule = [aManager getSWModuleWithName:aName]; + self.swManager = aManager; + + [self mainInit]; + } + + return self; +} + +- (id)initWithSWModule:(sword::SWModule *)aModule { + return [self initWithSWModule:aModule swordManager:nil]; +} + +- (id)initWithSWModule:(sword::SWModule *)aModule swordManager:(SwordManager *)aManager { + self = [super init]; + if(self) { + swModule = aModule; + self.swManager = aManager; + + [self mainInit]; + } + + return self; +} + +- (void)finalize { + [super finalize]; +} + +- (void)dealloc { + [self setConfigEntries:nil]; + [self setSwManager:nil]; + [self setModuleLock:nil]; + [self setIndexLock:nil]; + [self setName:nil]; + [self setDescr:nil]; + [self setTypeString:nil]; + [self setLang:nil]; + + [super dealloc]; +} + +#pragma mark - Filters + +- (void)addRenderFilter:(SwordFilter *)aFilter { + swModule->AddRenderFilter([aFilter swFilter]); +} + +- (void)addStripFilter:(SwordFilter *)aFilter { + swModule->AddStripFilter([aFilter swFilter]); +} + +#pragma mark - Module access semaphores + +- (void)lockModuleAccess { + [moduleLock lock]; +} + +- (void)unlockModuleAccess { + [moduleLock unlock]; +} + +#pragma mark - Conf entries + +- (NSAttributedString *)fullAboutText { + return [[[NSAttributedString alloc] initWithString:@""] autorelease]; +} + +- (NSInteger)error { + return swModule->Error(); +} + +- (NSString *)retrieveName { + NSString *str = [NSString stringWithCString:swModule->Name() encoding:NSUTF8StringEncoding]; + if(!str) { + str = [NSString stringWithCString:swModule->Name() encoding:NSISOLatin1StringEncoding]; + } + return str; +} + +- (NSString *)retrieveDescr { + NSString *str = [NSString stringWithCString:swModule->Description() encoding:NSUTF8StringEncoding]; + if(!str) { + str = [NSString stringWithCString:swModule->Description() encoding:NSISOLatin1StringEncoding]; + } + return str; +} + +- (NSString *)retrieveLang { + NSString *str = [NSString stringWithCString:swModule->Lang() encoding:NSUTF8StringEncoding]; + if(!str) { + str = [NSString stringWithCString:swModule->Lang() encoding:NSISOLatin1StringEncoding]; + } + return str; +} + +- (NSString *)retrieveType { + NSString *str = [NSString stringWithCString:swModule->Type() encoding:NSUTF8StringEncoding]; + if(!str) { + str = [NSString stringWithCString:swModule->Type() encoding:NSISOLatin1StringEncoding]; + } + return str; +} + +- (NSString *)categoryString { + NSString *cat = [configEntries objectForKey:SWMOD_CONFENTRY_CATEGORY]; + if(cat == nil) { + cat = [self configFileEntryForConfigKey:SWMOD_CONFENTRY_CATEGORY]; + if(cat != nil) { + [configEntries setObject:cat forKey:SWMOD_CONFENTRY_CATEGORY]; + } + } + + return cat; +} + +- (ModuleCategory)category { + if(category == Unset) { + category = [SwordModule moduleCategoryForModuleCategoryString:[self categoryString]]; + } + return category; +} + +- (NSString *)cipherKey { + NSString *cipherKey = [configEntries objectForKey:SWMOD_CONFENTRY_CIPHERKEY]; + if(cipherKey == nil) { + cipherKey = [self configFileEntryForConfigKey:SWMOD_CONFENTRY_CIPHERKEY]; + if(cipherKey != nil) { + [configEntries setObject:cipherKey forKey:SWMOD_CONFENTRY_CIPHERKEY]; + } + } + + return cipherKey; +} + +- (NSString *)version { + NSString *version = [configEntries objectForKey:SWMOD_CONFENTRY_VERSION]; + if(version == nil) { + version = [self configFileEntryForConfigKey:SWMOD_CONFENTRY_VERSION]; + if(version != nil) { + [configEntries setObject:version forKey:SWMOD_CONFENTRY_VERSION]; + } + } + + return version; +} + +- (NSString *)minVersion { + NSString *minVersion = [configEntries objectForKey:SWMOD_CONFENTRY_MINVERSION]; + if(minVersion == nil) { + minVersion = [self configFileEntryForConfigKey:SWMOD_CONFENTRY_MINVERSION]; + if(minVersion != nil) { + [configEntries setObject:minVersion forKey:SWMOD_CONFENTRY_MINVERSION]; + } + } + + return minVersion; +} + +/** this might be RTF string but the return value will be converted to UTF8 */ +- (NSString *)aboutText { + NSMutableString *aboutText = [configEntries objectForKey:SWMOD_CONFENTRY_ABOUT]; + if(aboutText == nil) { + aboutText = [NSMutableString stringWithString:[self configFileEntryForConfigKey:SWMOD_CONFENTRY_ABOUT]]; + if(aboutText != nil) { + //search & replace the RTF markup: + // "\\qc" - for centering --->>> ignore these + // "\\pard" - for resetting paragraph attributes --->>> ignore these + // "\\par" - for paragraph breaks --->>> honour these + // "\\u{num}?" - for unicode characters --->>> honour these + [aboutText replaceOccurrencesOfString:@"\\qc" withString:@"" options:0 range:NSMakeRange(0, [aboutText length])]; + [aboutText replaceOccurrencesOfString:@"\\pard" withString:@"" options:0 range:NSMakeRange(0, [aboutText length])]; + [aboutText replaceOccurrencesOfString:@"\\par" withString:@"\n" options:0 range:NSMakeRange(0, [aboutText length])]; + + NSMutableString *retStr = [[@"" mutableCopy] autorelease]; + for(NSUInteger i=0; i<[aboutText length]; i++) { + unichar c = [aboutText characterAtIndex:i]; + + if(c == '\\' && ((i+1) < [aboutText length])) { + unichar d = [aboutText characterAtIndex:(i+1)]; + if (d == 'u') { + //we have an unicode character! + @try { + NSInteger unicodeChar = 0; + NSMutableString *unicodeCharString = [[@"" mutableCopy] autorelease]; + int j = 0; + BOOL negative = NO; + if ([aboutText characterAtIndex:(i+2)] == '-') { + //we have a negative unicode char + negative = YES; + j++;//skip past the '-' + } + while(isdigit([aboutText characterAtIndex:(i+2+j)])) { + [unicodeCharString appendFormat:@"%C", [aboutText characterAtIndex:(i+2+j)]]; + j++; + } + unicodeChar = [unicodeCharString integerValue]; + if (negative) unicodeChar = 65536 - unicodeChar; + i += j+2; + [retStr appendFormat:@"%C", unicodeChar]; + } + @catch (NSException * e) { + [retStr appendFormat:@"%C", c]; + } + //end dealing with the unicode character. + } else { + [retStr appendFormat:@"%C", c]; + } + } else { + [retStr appendFormat:@"%C", c]; + } + } + + aboutText = retStr; + } else { + aboutText = [NSMutableString string]; + } + [configEntries setObject:aboutText forKey:SWMOD_CONFENTRY_ABOUT]; + } + + return aboutText; +} + +/** this is only relevant for bible and commentaries */ +- (NSString *)versification { + return @""; +} + +- (BOOL)isEditable { + BOOL ret = NO; + NSString *editable = [configEntries objectForKey:SWMOD_CONFENTRY_EDITABLE]; + if(editable == nil) { + editable = [self configFileEntryForConfigKey:SWMOD_CONFENTRY_EDITABLE]; + if(editable != nil) { + [configEntries setObject:editable forKey:SWMOD_CONFENTRY_EDITABLE]; + } + } + + if(editable) { + if([editable isEqualToString:@"YES"]) { + ret = YES; + } + } + + return ret; +} + +- (BOOL)isRTL { + BOOL ret = NO; + NSString *direction = [configEntries objectForKey:SWMOD_CONFENTRY_DIRECTION]; + if(direction == nil) { + direction = [self configFileEntryForConfigKey:SWMOD_CONFENTRY_DIRECTION]; + if(direction != nil) { + [configEntries setObject:direction forKey:SWMOD_CONFENTRY_DIRECTION]; + } + } + + if(direction) { + if([direction isEqualToString:SW_DIRECTION_RTL]) { + ret = YES; + } + } + + return ret; +} + +- (BOOL)isUnicode { + return swModule->isUnicode(); +} + +- (BOOL)isEncrypted { + BOOL encrypted = YES; + if([self cipherKey] == nil) { + encrypted = NO; + } + + return encrypted; +} + +- (BOOL)isLocked { + /** is module locked/has cipherkey config entry but cipherkey entry is empty */ + BOOL locked = NO; + NSString *key = [self cipherKey]; + if(key != nil) { + // check user defaults, that's where we store the entered keys + NSDictionary *cipherKeys = [[NSUserDefaults standardUserDefaults] objectForKey:DefaultsModuleCipherKeysKey]; + if([key length] == 0 && [[cipherKeys allKeys] containsObject:[self name]] == NO) { + locked = YES; + } + } + + return locked; +} + +// general feature access +- (BOOL)hasFeature:(NSString *)feature { + BOOL has = NO; + + if(swModule->getConfig().has("Feature", [feature UTF8String])) { + has = YES; + } else if (swModule->getConfig().has("GlobalOptionFilter", [[NSString stringWithFormat:@"GBF%@", feature] UTF8String])) { + has = YES; + } else if (swModule->getConfig().has("GlobalOptionFilter", [[NSString stringWithFormat:@"ThML%@", feature] UTF8String])) { + has = YES; + } else if (swModule->getConfig().has("GlobalOptionFilter", [[NSString stringWithFormat:@"UTF8%@", feature] UTF8String])) { + has = YES; + } else if (swModule->getConfig().has("GlobalOptionFilter", [[NSString stringWithFormat:@"OSIS%@", feature] UTF8String])) { + has = YES; + } else if (swModule->getConfig().has("GlobalOptionFilter", [feature UTF8String])) { + has = YES; + } + + return has; +} + +- (NSString *)configFileEntryForConfigKey:(NSString *)entryKey { + NSString *result = nil; + + [moduleLock lock]; + const char *entryStr = swModule->getConfigEntry([entryKey UTF8String]); + if(entryStr) { + result = [NSString stringWithUTF8String:entryStr]; + if(!result) { + result = [NSString stringWithCString:entryStr encoding:NSISOLatin1StringEncoding]; + } + } + [moduleLock unlock]; + + return result; +} + +#pragma mark - Module unlocking + +- (BOOL)unlock:(NSString *)unlockKey { + + if (![self isEncrypted]) { + return NO; + } + + NSMutableDictionary *cipherKeys = [NSMutableDictionary dictionaryWithDictionary: + [[NSUserDefaults standardUserDefaults] objectForKey:DefaultsModuleCipherKeysKey]]; + [cipherKeys setObject:unlockKey forKey:[self name]]; + [[NSUserDefaults standardUserDefaults] setObject:cipherKeys forKey:DefaultsModuleCipherKeysKey]; + + [swManager setCipherKey:unlockKey forModuleNamed:[self name]]; + + return YES; +} + +#pragma mark - Module positioning + +- (void)incKeyPosition { + swModule->increment(1); +} + +- (void)decKeyPosition { + swModule->decrement(1); +} + +- (void)setKeyString:(NSString *)aKeyString { + swModule->setKey([aKeyString UTF8String]); +} + +- (void)setSwordKey:(SwordKey *)aKey { + swModule->setKey([aKey swKey]); +} + +- (SwordKey *)createKey { + sword::SWKey *sk = swModule->CreateKey(); + SwordKey *newKey = [SwordKey swordKeyWithSWKey:sk makeCopy:YES]; + delete sk; + + return newKey; +} + +- (SwordKey *)getKey { + return [SwordKey swordKeyWithSWKey:swModule->getKey()]; +} + +- (SwordKey *)getKeyCopy { + return [SwordKey swordKeyWithSWKey:swModule->getKey() makeCopy:YES]; +} + +#pragma mark - Module metadata processing + +- (id)attributeValueForParsedLinkData:(NSDictionary *)data { + return [self attributeValueForParsedLinkData:data withTextRenderType:TextTypeStripped]; +} + +- (id)attributeValueForParsedLinkData:(NSDictionary *)data withTextRenderType:(TextPullType)textType { + id ret = nil; + + NSString *passage = [data objectForKey:ATTRTYPE_PASSAGE]; + if(passage) { + passage = [[passage stringByReplacingOccurrencesOfString:@"+" withString:@" "] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } + NSString *attrType = [data objectForKey:ATTRTYPE_TYPE]; + if([attrType isEqualToString:@"n"]) { + NSString *footnoteText = [self entryAttributeValueFootnoteOfType:attrType + indexValue:[data objectForKey:ATTRTYPE_VALUE] + forKey:[SwordKey swordKeyWithRef:passage]]; + ret = footnoteText; + } else if([attrType isEqualToString:@"x"] || [attrType isEqualToString:@"scriptRef"] || [attrType isEqualToString:@"scripRef"]) { + NSString *key = @""; + if([attrType isEqualToString:@"x"]) { + key = [self entryAttributeValueFootnoteOfType:attrType + indexValue:[data objectForKey:ATTRTYPE_VALUE] + forKey:[SwordKey swordKeyWithRef:passage]]; + } else { + key = [[[data objectForKey:ATTRTYPE_VALUE] stringByReplacingOccurrencesOfString:@"+" + withString:@" "] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; + } + if(textType == TextTypeRendered) { + ret = [self renderedTextEntriesForRef:key]; + } else { + ret = [self strippedTextEntriesForRef:key]; + } + } + + return ret; +} + +- (void)setProcessEntryAttributes:(BOOL)flag { + swModule->processEntryAttributes(flag); +} + +- (BOOL)processEntryAttributes { + return swModule->isProcessEntryAttributes(); +} + +- (NSString *)entryAttributeValuePreverse { + NSString *ret = [NSString stringWithUTF8String:swModule->getEntryAttributes()["Heading"]["Preverse"]["0"].c_str()]; + + return ret; +} + +- (NSString *)entryAttributeValueFootnoteOfType:(NSString *)fnType indexValue:(NSString *)index { + NSString *ret = @""; + if([fnType isEqualToString:@"x"]) { + ret = [NSString stringWithUTF8String:swModule->getEntryAttributes()["Footnote"][[index UTF8String]]["refList"].c_str()]; + } else if([fnType isEqualToString:@"n"]) { + ret = [NSString stringWithUTF8String:swModule->getEntryAttributes()["Footnote"][[index UTF8String]]["body"].c_str()]; + } + return ret; +} + +- (NSArray *)entryAttributeValuesLemma { + NSMutableArray *array = [NSMutableArray array]; + + // parse entry attributes and look for Lemma (String's numbers) + sword::AttributeTypeList::iterator words; + sword::AttributeList::iterator word; + sword::AttributeValue::iterator strongVal; + words = swModule->getEntryAttributes().find("Word"); + if(words != swModule->getEntryAttributes().end()) { + for(word = words->second.begin();word != words->second.end(); word++) { + strongVal = word->second.find("Lemma"); + if(strongVal != word->second.end()) { + // pass empty "Text" entries + if(strongVal->second == "G3588") { + if (word->second.find("Text") == word->second.end()) + continue; // no text? let's skip + } + NSMutableString *stringValStr = [NSMutableString stringWithUTF8String:(const char *)strongVal->second]; + if(stringValStr) { + [stringValStr replaceOccurrencesOfString:@"|x-Strongs:" withString:@" " options:0 range:NSMakeRange(0, [stringValStr length])]; + [array addObject:stringValStr]; + } + } + } + } + return [NSArray arrayWithArray:array]; +} + +- (NSString *)entryAttributeValuePreverseForKey:(SwordKey *)aKey { + [moduleLock lock]; + [self setSwordKey:aKey]; + swModule->RenderText(); // force processing of key + NSString *value = [self entryAttributeValuePreverse]; + [moduleLock unlock]; + return value; +} + +- (NSString *)entryAttributeValueFootnoteOfType:(NSString *)fnType indexValue:(NSString *)index forKey:(SwordKey *)aKey { + [moduleLock lock]; + [self setSwordKey:aKey]; + swModule->RenderText(); // force processing of key + NSString *value = [self entryAttributeValueFootnoteOfType:fnType indexValue:index]; + [moduleLock unlock]; + return value; +} + + +- (NSString *)description { + return [self name]; +} + +#pragma mark - Module text access + +- (NSString *)renderedText { + NSString *ret = @""; + ret = [NSString stringWithUTF8String:swModule->RenderText()]; + if(!ret) { + ret = [NSString stringWithCString:swModule->RenderText() encoding:NSISOLatin1StringEncoding]; + } + return ret; +} + +- (NSString *)renderedTextFromString:(NSString *)aString { + NSString *ret = @""; + ret = [NSString stringWithUTF8String:swModule->RenderText([aString UTF8String])]; + if(!ret) { + ret = [NSString stringWithCString:swModule->RenderText([aString UTF8String]) encoding:NSISOLatin1StringEncoding]; + } + return ret; +} + +- (NSString *)strippedText { + NSString *ret = @""; + ret = [NSString stringWithUTF8String:swModule->StripText()]; + if(!ret) { + ret = [NSString stringWithCString:swModule->StripText() encoding:NSISOLatin1StringEncoding]; + } + return ret; +} + +- (NSString *)strippedTextFromString:(NSString *)aString { + NSString *ret = @""; + ret = [NSString stringWithUTF8String:swModule->RenderText([aString UTF8String])]; + if(!ret) { + ret = [NSString stringWithCString:swModule->RenderText([aString UTF8String]) encoding:NSISOLatin1StringEncoding]; + } + return ret; +} + +- (NSArray *)strippedTextEntriesForRef:(NSString *)reference { + return [self textEntriesForReference:reference textType:TextTypeStripped]; +} + +- (NSArray *)renderedTextEntriesForRef:(NSString *)reference { + return [self textEntriesForReference:reference textType:TextTypeRendered]; +} + +- (SwordModuleTextEntry *)textEntryForKey:(SwordKey *)aKey textType:(TextPullType)aType { + SwordModuleTextEntry *ret = nil; + + if(aKey) { + [moduleLock lock]; + [self setSwordKey:aKey]; + if(![self error]) { + NSString *txt = @""; + if(aType == TextTypeRendered) { + txt = [self renderedText]; + } else { + txt = [self strippedText]; + } + + if(txt) { + ret = [SwordModuleTextEntry textEntryForKey:[aKey keyText] andText:txt]; + } else { + ALog(@"Nil key"); + } + } + [moduleLock unlock]; + } + + return ret; +} + +- (SwordModuleTextEntry *)textEntryForKeyString:(NSString *)aKeyString textType:(TextPullType)aType { + return [self textEntryForKey:[SwordKey swordKeyWithRef:aKeyString] textType:aType]; +} + +- (NSArray *)textEntriesForReference:(NSString *)aReference textType:(TextPullType)textType { + NSArray *ret = nil; + + SwordModuleTextEntry *entry = [self textEntryForKey:[SwordKey swordKeyWithRef:aReference] + textType:textType]; + if(entry) { + ret = [NSArray arrayWithObject:entry]; + } + + return ret; +} + +- (void)writeEntry:(SwordModuleTextEntry *)anEntry {} + +- (long)entryCount { + return 0; +} + +- (sword::SWModule *)swModule { + return swModule; +} + +@end |