OSDN Git Service

Implement encrypt/decrypt.
[tombo/Tombo.git] / iOS / Tombo / Tombo / Storage.m
index f273205..23acb2a 100644 (file)
@@ -1,5 +1,6 @@
 #import "Storage.h"
 #import "FileItem.h"
+#import "CryptCore.h"
 
 @implementation Storage
 
         FileItem *item = [FileItem alloc];
         item.path = [currentPath stringByAppendingString: f];
         item.name = [f stringByDeletingPathExtension];
+                
         BOOL bDir = NO;
         [fileManager fileExistsAtPath:item.path isDirectory:&bDir];
         item.isDirectory = bDir;
+        
+        if (!bDir) {
+            if ([@"chi" isEqualToString:[f pathExtension]]) {
+                item.isCrypt = YES;
+            }
+        }
+        
         [result addObject:item];
     }
     return result;
     return [currentDirectory isEqualToString:@"/"];
 }
 
-// save note
--(FileItem *)save:(NSString *)note item:(FileItem *)item {
-    if (!item) return nil;
+- (void)saveDataWithBOM:(NSString *)note file:(NSString *)path {
+    const char *noteBytes = [note cStringUsingEncoding:NSUTF8StringEncoding];
+    int n = strlen(noteBytes);
+    NSMutableData *data = [[NSMutableData alloc] initWithLength:n + 3];
+    char *buf = (char *)[data mutableBytes];
+    memcpy(buf + 3, noteBytes, n);
+    *(char*)(buf + 0) = 0xEF;
+    *(char*)(buf + 1) = 0xBB;
+    *(char*)(buf + 2) = 0xBF;
+    
+    [data writeToFile:path atomically:YES];
+}
 
-    // Decide new title.
+- (NSString *)pickupTitle:(NSString *)note {
     NSRange r;
     r.location = 0;
     r.length = 0;
     NSRange titleRange = [note lineRangeForRange:r];
     NSString *title = [note substringWithRange:titleRange];
+    
     if ([title characterAtIndex:(title.length - 1)] == '\n') {
         title = [title substringToIndex:(title.length - 1)];
     }
     if (title.length == 0) {
         title = @"New document";
     }
+    return title;
+}
+
+- (FileItem *)savePlain:(NSString *)note item:(FileItem *)item {
+    if (!item) return nil;
+
+    NSString *title = [self pickupTitle:note];
 
     // If title is changed, rename one.
     FileItem *result;    
     }
 
     // Save note.
+    [self saveDataWithBOM:note file:result.path];
+    
+    return result;
+}
+
+- (FileItem *)saveCrypt:(NSString *)note item:(FileItem *)item password:(NSString *)password {
+    NSString *title = [self pickupTitle:note];
+    
+    FileItem *result;
+    if (!item.name || ![title isEqualToString: item.name]) {
+        result = [self decideFileName:title path:item.path];
+        
+        if (item.name) {
+            NSError *error = nil;
+            [fileManager moveItemAtPath:item.path toPath:result.path error:&error];            
+        }
+    } else {
+        result = item;
+    }
+    
+    // Save note.
+    const char *noteBytes = [note cStringUsingEncoding:NSUTF8StringEncoding];
+    int n = strlen(noteBytes);
+    NSMutableData *data = [[NSMutableData alloc] initWithLength:n + 3];
+    char *buf = (char *)[data mutableBytes];
+    memcpy(buf + 3, noteBytes, n);
+    *(char*)(buf + 0) = 0xEF;
+    *(char*)(buf + 1) = 0xBB;
+    *(char*)(buf + 2) = 0xBF;
+
     NSError *error = nil;
-    [note writeToFile:result.path atomically:YES encoding:NSUTF8StringEncoding error:&error];
+    NSData *encData = [CryptCore encrypt:password data:data error:&error];
+    if (error) return nil;
     
+    if (![encData writeToFile:result.path atomically:YES]) return nil;
     return result;
 }
+
 // Remove characters which can't use file name from given string.
 - (NSString *)removeInvalidFilenameChars:(NSString *)src {
     NSString *result = src;
     [fileManager removeItemAtPath:item.path error:nil];
 }
 
+- (FileItem *)newFolder:(NSString *)folder {
+    NSMutableString *path = [[NSMutableString alloc]initWithCapacity:256];
+    [path appendString:documentRoot];
+    [path appendString:currentDirectory];
+    [path appendString:folder];
+    NSError *error = nil;
+    [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error];
+    
+    FileItem *item = [FileItem allocWithName:folder];
+    item.path = path;
+    item.isDirectory = YES;
+    return item;
+}
+
++(NSString *)load:(NSString *)path {
+    NSData *data = [NSData dataWithContentsOfFile:path];
+    return [Storage trimBOM:data];
+}
+
++(NSString *)trimBOM:(NSData *)data {
+    const char *header = [data bytes];
+    if ([data length] > 3 && 
+        *header == 0xEF && *(header + 1) == 0xBB && *(header + 2) == 0xBF) {
+        // BOM exists. UTF-8.
+        NSString *note = [[NSString alloc] initWithBytes:[data bytes] + 3
+                                                  length:[data length] - 3
+                                                encoding:NSUTF8StringEncoding];
+        return note;
+    }
+
+    NSString *note;
+    
+    if ([[[NSLocale currentLocale] localeIdentifier] isEqualToString:@"ja_JP"]) {
+        note = [[NSString alloc] initWithBytes:[data bytes]
+                                        length:[data length]
+                                      encoding:NSShiftJISStringEncoding];
+        if (note) return note;
+    }
+
+    // UTF-8
+    note = [[NSString alloc] initWithBytes:[data bytes] 
+                                    length:[data length] 
+                                  encoding:NSUTF8StringEncoding];
+    if (note) return note;
+
+    // encode UTF-8 fail.
+    return @"";
+}
+
++ (NSString *)loadCryptFile:(NSString *)path password:(NSString *)password {
+    NSData *encData = [NSData dataWithContentsOfFile:path];
+    NSError *error = nil;
+    NSData *plainData = [CryptCore decrypt:password data:encData error:&error];
+    if (error) return nil;
+    
+    return [Storage trimBOM:plainData];
+}
+
+- (FileItem *)encrypt:(NSString *)key item:(FileItem*)item {
+    NSData *plainData = [NSData dataWithContentsOfFile:item.path];
+    NSError *error = nil;
+    NSData *encData = [CryptCore encrypt:key data:plainData error:&error];
+    if (error) return nil;
+
+    NSMutableString *newPath = [[NSMutableString alloc] initWithCapacity:256];
+    [newPath appendString:[item.path stringByDeletingPathExtension]];
+    [newPath appendString:@".chi"];
+    
+    FileItem *newItem = [self decideFileName:item.name path:newPath];
+    newItem.isCrypt = YES;
+    
+    if (![encData writeToFile:newItem.path atomically:YES]) {
+        return nil;
+    }
+    [fileManager removeItemAtPath:item.path error:&error];
+    return newItem;
+}
+
+- (FileItem *)decrypt:(NSString *)key item:(FileItem*)item {
+    // TODO: implement
+    NSData *encData = [NSData dataWithContentsOfFile:item.path];
+    NSError *error = nil;
+    NSData *plainData = [CryptCore decrypt:key data:encData error:&error];
+    if (error) return nil;
+    
+    NSMutableString *newPath = [[NSMutableString alloc] initWithCapacity:256];
+    [newPath appendString:[item.path stringByDeletingPathExtension]];
+    [newPath appendString:@".txt"];
+    FileItem *newItem = [self decideFileName:item.name path:newPath];
+
+    if (![plainData writeToFile:newItem.path atomically:YES]) {
+        return nil;
+    }
+    [fileManager removeItemAtPath:item.path error:&error];
+    return newItem;    
+}
+
 @end