Camino only - Refactor Safari and Opera bookmark import/export. Add support for Opera 10 bookmarks. sr=pink

git-svn-id: svn://10.0.0.236/trunk@258793 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
stuart.morgan%alumni.case.edu 2009-10-26 17:36:35 +00:00
parent 37bef9f470
commit 387ccd6471
14 changed files with 581 additions and 208 deletions

View File

@ -92,6 +92,10 @@
00BBBFE80D70A6E400C2D916 /* tab_loading.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 00BBBFE60D70A6E400C2D916 /* tab_loading.tiff */; };
00C6890710560B110082D80F /* BreakpadWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 00C6890610560B110082D80F /* BreakpadWrapper.m */; };
00C6890810560B110082D80F /* BreakpadWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = 00C6890610560B110082D80F /* BreakpadWrapper.m */; };
00F79F591075B622006688AC /* OperaBookmarkConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 00F79F581075B622006688AC /* OperaBookmarkConverter.m */; };
00F79F5A1075B622006688AC /* OperaBookmarkConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 00F79F581075B622006688AC /* OperaBookmarkConverter.m */; };
00F7A08C1077F255006688AC /* SafariBookmarkConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 00F7A08B1077F255006688AC /* SafariBookmarkConverter.m */; };
00F7A08D1077F255006688AC /* SafariBookmarkConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 00F7A08B1077F255006688AC /* SafariBookmarkConverter.m */; };
032FFDD5077351DA00440548 /* Downloads.mm in Sources */ = {isa = PBXBuildFile; fileRef = 032FFDCE077351A800440548 /* Downloads.mm */; };
032FFDD6077351EA00440548 /* Downloads.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 032FFDCF077351A800440548 /* Downloads.tiff */; };
032FFDD7077351EA00440548 /* Downloads.nib in Resources */ = {isa = PBXBuildFile; fileRef = 032FFDD0077351A800440548 /* Downloads.nib */; };
@ -2509,6 +2513,10 @@
00BBBFE60D70A6E400C2D916 /* tab_loading.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; name = tab_loading.tiff; path = chrome/tab_loading.tiff; sourceTree = "<group>"; };
00C6890510560B110082D80F /* BreakpadWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BreakpadWrapper.h; path = src/application/BreakpadWrapper.h; sourceTree = SOURCE_ROOT; };
00C6890610560B110082D80F /* BreakpadWrapper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BreakpadWrapper.m; path = src/application/BreakpadWrapper.m; sourceTree = SOURCE_ROOT; };
00F79F571075B622006688AC /* OperaBookmarkConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OperaBookmarkConverter.h; path = src/bookmarks/OperaBookmarkConverter.h; sourceTree = "<group>"; };
00F79F581075B622006688AC /* OperaBookmarkConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OperaBookmarkConverter.m; path = src/bookmarks/OperaBookmarkConverter.m; sourceTree = "<group>"; };
00F7A08A1077F255006688AC /* SafariBookmarkConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SafariBookmarkConverter.h; path = src/bookmarks/SafariBookmarkConverter.h; sourceTree = "<group>"; };
00F7A08B1077F255006688AC /* SafariBookmarkConverter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SafariBookmarkConverter.m; path = src/bookmarks/SafariBookmarkConverter.m; sourceTree = "<group>"; };
032FFDCD077351A800440548 /* Downloads.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Downloads.h; sourceTree = "<group>"; };
032FFDCE077351A800440548 /* Downloads.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = Downloads.mm; sourceTree = "<group>"; };
032FFDCF077351A800440548 /* Downloads.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Downloads.tiff; sourceTree = "<group>"; };
@ -2951,7 +2959,7 @@
DEE9EBA30AF5C379002BC511 /* SessionManager.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SessionManager.h; path = src/application/SessionManager.h; sourceTree = "<group>"; };
DEE9EBA60AF5C390002BC511 /* SessionManager.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; name = SessionManager.mm; path = src/application/SessionManager.mm; sourceTree = SOURCE_ROOT; };
DEFAA2850F24192200BD51C1 /* Growl.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Growl.xcodeproj; path = growl/Growl.xcodeproj; sourceTree = SOURCE_ROOT; };
DEFAA3430F241C1600BD51C1 /* Growl.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = Growl.framework; path = "growl/build/Release/Growl.framework"; sourceTree = "<group>"; };
DEFAA3430F241C1600BD51C1 /* Growl.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = Growl.framework; path = growl/build/Release/Growl.framework; sourceTree = "<group>"; };
DEFD234F0D021C3A006899B9 /* dom_loadsave.xpt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = file; name = dom_loadsave.xpt; path = ../dist/bin/components/dom_loadsave.xpt; sourceTree = SOURCE_ROOT; };
DEFD23520D021C48006899B9 /* dom_storage.xpt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = file; name = dom_storage.xpt; path = ../dist/bin/components/dom_storage.xpt; sourceTree = SOURCE_ROOT; };
DEFD23550D021C63006899B9 /* content_xmldoc.xpt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = file; name = content_xmldoc.xpt; path = ../dist/bin/components/content_xmldoc.xpt; sourceTree = SOURCE_ROOT; };
@ -4120,6 +4128,10 @@
children = (
336234460E6BC2FB00DD5373 /* HTMLBookmarkConverter.h */,
336234470E6BC2FB00DD5373 /* HTMLBookmarkConverter.m */,
00F79F571075B622006688AC /* OperaBookmarkConverter.h */,
00F79F581075B622006688AC /* OperaBookmarkConverter.m */,
00F7A08A1077F255006688AC /* SafariBookmarkConverter.h */,
00F7A08B1077F255006688AC /* SafariBookmarkConverter.m */,
);
name = "Import and Export";
sourceTree = "<group>";
@ -6359,6 +6371,8 @@
F724342E0FE6DB12008B783E /* AutoCompleteResult.m in Sources */,
F72434300FE6DB19008B783E /* MAAttachedWindow.m in Sources */,
00C6890710560B110082D80F /* BreakpadWrapper.m in Sources */,
00F79F591075B622006688AC /* OperaBookmarkConverter.m in Sources */,
00F7A08C1077F255006688AC /* SafariBookmarkConverter.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -6555,6 +6569,8 @@
F724342D0FE6DB12008B783E /* AutoCompleteResult.m in Sources */,
F724342F0FE6DB19008B783E /* MAAttachedWindow.m in Sources */,
00C6890810560B110082D80F /* BreakpadWrapper.m in Sources */,
00F79F5A1075B622006688AC /* OperaBookmarkConverter.m in Sources */,
00F7A08D1077F255006688AC /* SafariBookmarkConverter.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -54,12 +54,14 @@
url:(NSString*)aURL
lastVisit:(NSDate*)aLastVisit;
+ (Bookmark*)bookmarkWithNativeDictionary:(NSDictionary*)aDict;
+ (Bookmark*)bookmarkWithSafariDictionary:(NSDictionary*)aDict;
- (NSString *)url;
- (NSDate *)lastVisit; // nil if not visited
- (unsigned)numberOfVisits;
// Alternate accessors for persisting to disk; never returns nil.
- (NSString*)savedURL;
- (NSString*)faviconURL;
- (void)setFaviconURL:(NSString*)inURL;

View File

@ -63,7 +63,6 @@ NSString* const URLLoadSuccessKey = @"url_bool";
- (void)clearLastVisit;
// methods used for saving to files; are guaranteed never to return nil
- (id)savedURL;
- (id)savedStatus;
- (id)savedNumberOfVisits;
- (id)savedFaviconURL;
@ -114,14 +113,6 @@ NSString* const URLLoadSuccessKey = @"url_bool";
return bookmark;
}
+ (Bookmark*)bookmarkWithSafariDictionary:(NSDictionary*)aDict
{
NSDictionary* uriDict = [aDict objectForKey:SafariURIDictKey];
return [self bookmarkWithTitle:[uriDict objectForKey:SafariBookmarkTitleKey]
url:[aDict objectForKey:SafariURLStringKey]
lastVisit:nil];
}
- (id)copyWithZone:(NSZone *)zone
{
id bookmarkCopy = [super copyWithZone:zone];
@ -291,7 +282,7 @@ NSString* const URLLoadSuccessKey = @"url_bool";
#pragma mark -
- (id)savedURL
- (NSString*)savedURL
{
return mURL ? mURL : @"";
}
@ -387,28 +378,6 @@ NSString* const URLLoadSuccessKey = @"url_bool";
return itemDict;
}
- (NSDictionary *)writeSafariDictionary
{
NSDictionary* dict = nil;
if (![self isSeparator]) {
NSDictionary *uriDict = [NSDictionary dictionaryWithObjectsAndKeys:
[self savedTitle], SafariBookmarkTitleKey,
[self savedURL], @"",
nil];
if (!uriDict) {
return nil; // when would this happen?
}
dict = [NSDictionary dictionaryWithObjectsAndKeys:
uriDict, SafariURIDictKey,
[self savedURL], SafariURLStringKey,
SafariLeaf, SafariTypeKey,
[self UUID], SafariUUIDKey,
nil];
}
return dict;
}
#pragma mark -
// sorting

View File

@ -100,7 +100,6 @@ enum {
// for reading from disk
- (BOOL)readNativeDictionary:(NSDictionary *)aDict;
- (BOOL)readSafariDictionary:(NSDictionary *)aDict;
// ways to add a new bookmark array
- (BookmarkFolder *)addBookmarkFolder; //adds to end

View File

@ -102,11 +102,9 @@ static int BookmarkItemSort(id firstItem, id secondItem, void* context)
// ways to add a new bookmark
- (BOOL)addBookmarkFromNativeDict:(NSDictionary *)aDict;
- (BOOL)addBookmarkFromSafariDict:(NSDictionary *)aDict;
// ways to add a new bookmark folder
- (BOOL)addBookmarkFolderFromNativeDict:(NSDictionary *)aDict; //read in - adds sequentially
- (BOOL)addBookmarkFolderFromSafariDict:(NSDictionary *)aDict;
// deletes the bookmark or bookmark array
- (BOOL)deleteBookmark:(Bookmark *)childBookmark;
@ -704,19 +702,6 @@ static int BookmarkItemSort(id firstItem, id secondItem, void* context)
return YES;
}
- (BOOL)addBookmarkFromSafariDict:(NSDictionary *)aDict
{
if ([self isRoot])
return NO;
Bookmark* theBookmark = [Bookmark bookmarkWithSafariDictionary:aDict];
if (!theBookmark)
return NO;
[self appendChild:theBookmark];
return YES;
}
//
// Adding arrays
//
@ -735,11 +720,6 @@ static int BookmarkItemSort(id firstItem, id secondItem, void* context)
return [[self addBookmarkFolder] readNativeDictionary:aDict];
}
- (BOOL)addBookmarkFolderFromSafariDict:(NSDictionary *)aDict
{
return [[self addBookmarkFolder] readSafariDictionary:aDict];
}
// normal add while programming running
- (BookmarkFolder *)addBookmarkFolder:(NSString *)aName inPosition:(unsigned)aPosition isGroup:(BOOL)aFlag
{
@ -1188,27 +1168,6 @@ static int BookmarkItemSort(id firstItem, id secondItem, void* context)
return success;
}
- (BOOL)readSafariDictionary:(NSDictionary *)aDict
{
[self setTitle:[aDict objectForKey:BMTitleKey]];
BOOL success = YES;
NSEnumerator* enumerator = [[aDict objectForKey:BMChildrenKey] objectEnumerator];
id aKid;
while ((aKid = [enumerator nextObject]) && success) {
if ([[aKid objectForKey:SafariTypeKey] isEqualToString:SafariLeaf])
success = [self addBookmarkFromSafariDict:(NSDictionary *)aKid];
else if ([[aKid objectForKey:SafariTypeKey] isEqualToString:SafariList])
success = [self addBookmarkFolderFromSafariDict:(NSDictionary *)aKid];
// might also be a WebBookmarkTypeProxy - we'll ignore those
}
if ([[aDict objectForKey:SafariAutoTab] boolValue])
[self setIsGroup:YES];
return success;
}
//
// -writeBookmarksMetadataToPath:
//
@ -1278,67 +1237,4 @@ static int BookmarkItemSort(id firstItem, id secondItem, void* context)
return folderDict;
}
- (NSDictionary *)writeSafariDictionary
{
if (![self isSmartFolder]) {
id item;
NSMutableArray* children = [NSMutableArray array];
NSEnumerator* enumerator = [mChildArray objectEnumerator];
//get chillins first
while ((item = [enumerator nextObject])) {
id aDict = [item writeSafariDictionary];
if (aDict)
[children addObject:aDict];
}
NSString *titleString;
if ([self isToolbar])
titleString = @"BookmarksBar";
else if ([[BookmarkManager sharedBookmarkManager] bookmarkMenuFolder] == self)
titleString = @"BookmarksMenu";
else
titleString = [self title];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
titleString, BMTitleKey,
SafariList, SafariTypeKey,
[self UUID], SafariUUIDKey,
children, BMChildrenKey,
nil];
if ([self isGroup])
[dict setObject:[NSNumber numberWithBool:YES] forKey:SafariAutoTab];
return dict;
// now we handle the smart folders
}
else {
NSString *SafariProxyKey = @"WebBookmarkIdentifier";
NSString *SafariProxyType = @"WebBookmarkTypeProxy";
if ([[BookmarkManager sharedBookmarkManager] rendezvousFolder] == self) {
return [NSDictionary dictionaryWithObjectsAndKeys:
@"Bonjour", BMTitleKey,
@"Bonjour Bookmark Proxy Identifier", SafariProxyKey,
SafariProxyType, SafariTypeKey,
[self UUID], SafariUUIDKey,
nil];
}
else if ([[BookmarkManager sharedBookmarkManager] addressBookFolder] == self) {
return [NSDictionary dictionaryWithObjectsAndKeys:
@"Address Book", BMTitleKey,
@"Address Book Bookmark Proxy Identifier", SafariProxyKey,
SafariProxyType, SafariTypeKey,
[self UUID], SafariUUIDKey,
nil];
}
else if ([[BookmarkManager sharedBookmarkManager] historyFolder] == self) {
return [NSDictionary dictionaryWithObjectsAndKeys:
@"History", BMTitleKey,
@"History Bookmark Proxy Identifier", SafariProxyKey,
SafariProxyType, SafariTypeKey,
[self UUID], SafariUUIDKey,
nil];
}
}
return nil;
}
@end

View File

@ -47,7 +47,7 @@
@interface BookmarkImportDlgController (Private)
- (void)tryAddImportFromBrowser:(NSString *)aBrowserName withBookmarkPath:(NSString *)aPath;
- (BOOL)tryAddImportFromBrowser:(NSString *)aBrowserName withBookmarkPath:(NSString *)aPath;
- (void)tryOmniWeb5Import;
- (void)buildButtonForBrowser:(NSString *)aBrowserName withPathArray:(NSArray *)anArray;
- (NSString *)saltedBookmarkPathForProfile:(NSString *)aPath;
@ -83,7 +83,9 @@
[self tryAddImportFromBrowser:@"iCab" withBookmarkPath:@"~/Library/Preferences/iCab Preferences/Hotlist.html"];
[self tryAddImportFromBrowser:@"iCab 3" withBookmarkPath:@"~/Library/Preferences/iCab Preferences/Hotlist3.html"];
[self tryAddImportFromBrowser:@"Opera" withBookmarkPath:@"~/Library/Preferences/Opera Preferences/Bookmarks"];
if (![self tryAddImportFromBrowser:@"Opera" withBookmarkPath:@"~/Library/Preferences/Opera Preferences/bookmarks.adr"]) {
[self tryAddImportFromBrowser:@"Opera" withBookmarkPath:@"~/Library/Preferences/Opera Preferences/Bookmarks"];
}
[self tryAddImportFromBrowser:@"OmniWeb 4" withBookmarkPath:@"~/Library/Application Support/Omniweb/Bookmarks.html"];
// OmniWeb 5 has between 0 and 3 bookmark files.
[self tryOmniWeb5Import];
@ -115,13 +117,16 @@
// Checks for the existence of the specified bookmarks file, and adds an import option for
// the given browser if the file is found.
- (void)tryAddImportFromBrowser:(NSString *)aBrowserName withBookmarkPath:(NSString *)aPath
// Returns YES if an import option was added.
- (BOOL)tryAddImportFromBrowser:(NSString *)aBrowserName withBookmarkPath:(NSString *)aPath
{
NSFileManager *fm = [NSFileManager defaultManager];
NSString *fullPathString = [aPath stringByStandardizingPath];
if ([fm fileExistsAtPath:fullPathString]) {
[self buildButtonForBrowser:aBrowserName withPathArray:[NSArray arrayWithObject:fullPathString]];
return YES;
}
return NO;
}
// Special treatment for OmniWeb 5

View File

@ -134,7 +134,6 @@ enum
- (void)writeBookmarksMetadataToPath:(NSString*)inPath;
- (void)removeBookmarksMetadataFromPath:(NSString*)inPath;
- (NSDictionary *)writeNativeDictionary;
- (NSDictionary *)writeSafariDictionary;
// methods used for saving to files; are guaranteed never to return nil
- (id)savedTitle;
@ -154,11 +153,9 @@ enum
// Bunch of Keys for reading/writing dictionaries.
// Safari & Camino plist keys
// Camino plist keys
extern NSString* const BMTitleKey;
extern NSString* const BMChildrenKey;
// Camino plist keys
extern NSString* const BMFolderDescKey;
extern NSString* const BMFolderTypeKey;
extern NSString* const BMFolderShortcutKey;
@ -170,13 +167,3 @@ extern NSString* const BMShortcutKey;
extern NSString* const BMLastVisitKey;
extern NSString* const BMNumberVisitsKey;
extern NSString* const BMLinkedFaviconURLKey;
// safari keys
extern NSString* const SafariTypeKey;
extern NSString* const SafariLeaf;
extern NSString* const SafariList;
extern NSString* const SafariAutoTab;
extern NSString* const SafariUUIDKey;
extern NSString* const SafariURIDictKey;
extern NSString* const SafariBookmarkTitleKey;
extern NSString* const SafariURLStringKey;

View File

@ -46,12 +46,9 @@
NSString* const BookmarkItemChangedNotification = @"bookmark_changed";
NSString* const BookmarkItemChangedFlagsKey = @"change_flags";
// all our saving/loading keys
// Safari & Camino plist keys
// Camino plist keys
NSString* const BMTitleKey = @"Title";
NSString* const BMChildrenKey = @"Children";
// Camino plist keys
NSString* const BMFolderDescKey = @"FolderDescription";
NSString* const BMFolderTypeKey = @"FolderType";
NSString* const BMFolderShortcutKey = @"FolderKeyword";
@ -64,16 +61,6 @@ NSString* const BMLastVisitKey = @"LastVisitedDate";
NSString* const BMNumberVisitsKey = @"VisitCount";
NSString* const BMLinkedFaviconURLKey = @"LinkedFaviconURL";
// safari keys
NSString* const SafariTypeKey = @"WebBookmarkType";
NSString* const SafariLeaf = @"WebBookmarkTypeLeaf";
NSString* const SafariList = @"WebBookmarkTypeList";
NSString* const SafariAutoTab = @"WebBookmarkAutoTab";
NSString* const SafariUUIDKey = @"WebBookmarkUUID";
NSString* const SafariURIDictKey = @"URIDictionary";
NSString* const SafariBookmarkTitleKey = @"title";
NSString* const SafariURLStringKey = @"URLString";
@implementation BookmarkShortcutFormatter
- (NSString *)stringForObjectValue:(id)anObject
@ -373,11 +360,6 @@ NSString* const SafariURLStringKey = @"URLString";
return [NSDictionary dictionary];
}
- (NSDictionary *)writeSafariDictionary
{
return [NSDictionary dictionary];
}
- (id)savedTitle
{
return mTitle ? mTitle : @"";

View File

@ -39,19 +39,20 @@
#import <Foundation/Foundation.h>
@class BookmarkItem;
@class BookmarkFolder;
@interface HTMLBookmarkConverter : NSObject {
}
+ (id)htmlBookmarkConverter;
// Reads the bookmarks from |filePath| and returns the root bookmark item
// Reads the bookmarks from |filePath| and returns the root bookmark folder
// from the import (or nil if importing fails). If the file is corrupt, this
// will return as much as it can extract.
- (BookmarkItem*)bookmarksFromFile:(NSString*)filePath;
- (BookmarkFolder*)bookmarksFromFile:(NSString*)filePath;
// Writes the bookmark hierarchy rooted at |rootBookmarkItem| to a Netscape form
// HTML file at |filePath|.
- (void)writeBookmarks:(BookmarkItem*)rootBookmarkItem toFile:(NSString*)filePath;
- (void)writeBookmarks:(BookmarkFolder*)bookmarkRoot toFile:(NSString*)filePath;
@end

View File

@ -82,7 +82,7 @@
return [[[self alloc] init] autorelease];
}
- (BookmarkItem*)bookmarksFromFile:(NSString*)filePath
- (BookmarkFolder*)bookmarksFromFile:(NSString*)filePath
{
NSError* error = nil;
NSXMLDocument* bookmarkDoc = nil;
@ -98,16 +98,19 @@
NSLog(@"Unable to read bookmark file '%@' for import", filePath);
return nil;
}
else {
NSError* error;
NSXMLElement* root = [[[bookmarkDoc rootElement] nodesForXPath:@"/html/body"
error:&error] firstObject];
if (!root) {
NSLog(@"Unable to parse bookmark file '%@' for import", filePath);
return nil;
}
return [self bookmarkItemForElement:root];
NSXMLElement* root = [[[bookmarkDoc rootElement] nodesForXPath:@"/html/body"
error:&error] firstObject];
if (!root) {
NSLog(@"Unable to parse bookmark file '%@' for import", filePath);
return nil;
}
BookmarkItem* rootItem = [self bookmarkItemForElement:root];
if (rootItem && ![rootItem isKindOfClass:[BookmarkFolder class]]) {
BookmarkFolder* newFolder = [[[BookmarkFolder alloc] init] autorelease];
[newFolder appendChild:rootItem];
rootItem = newFolder;
}
return (BookmarkFolder*)rootItem;
}
- (BookmarkItem*)bookmarkItemForElement:(NSXMLElement*)element
@ -252,7 +255,7 @@
#pragma mark -
- (void)writeBookmarks:(BookmarkItem*)rootBookmarkItem toFile:(NSString*)filePath
- (void)writeBookmarks:(BookmarkFolder*)bookmarkRoot toFile:(NSString*)filePath
{
// Create a new, empty file to write bookmarks into
NSFileManager* fileManager = [NSFileManager defaultManager];
@ -285,26 +288,19 @@
@"<TITLE>Bookmarks</TITLE>",
@"<H1>Bookmarks</H1>"] dataUsingEncoding:NSUTF8StringEncoding]];
if ([rootBookmarkItem isKindOfClass:[BookmarkFolder class]]) {
NSEnumerator* folderEnumerator = [[(BookmarkFolder*)rootBookmarkItem children] objectEnumerator];
BookmarkItem* child;
while ((child = [folderEnumerator nextObject])) {
if ([child isKindOfClass:[BookmarkFolder class]]) {
[self writeBookmarkFolder:(BookmarkFolder*)child
toFileHandle:outHandle
withIndentation:1];
}
else {
[self writeBookmark:(Bookmark*)child
toFileHandle:outHandle
withIndentation:1];
}
NSEnumerator* folderEnumerator = [[(BookmarkFolder*)bookmarkRoot children] objectEnumerator];
BookmarkItem* child;
while ((child = [folderEnumerator nextObject])) {
if ([child isKindOfClass:[BookmarkFolder class]]) {
[self writeBookmarkFolder:(BookmarkFolder*)child
toFileHandle:outHandle
withIndentation:1];
}
else {
[self writeBookmark:(Bookmark*)child
toFileHandle:outHandle
withIndentation:1];
}
}
else {
[self writeBookmark:(Bookmark*)rootBookmarkItem
toFileHandle:outHandle
withIndentation:1];
}
[outHandle writeData:[@"</DL><p>\n" dataUsingEncoding:NSUTF8StringEncoding]];

View File

@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Camino code.
*
* The Initial Developer of the Original Code is
* Stuart Morgan
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Stuart Morgan <stuart.morgan@alumni.case.edu>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Foundation/Foundation.h>
@class BookmarkItem;
@class BookmarkFolder;
// Reads Opera bookmark files, converting them to Camino bookmark structures.
@interface OperaBookmarkConverter : NSObject {
}
+ (id)operaBookmarkConverter;
// Reads the bookmarks from |filePath| and returns the root bookmark folder
// from the import (or nil if importing fails).
- (BookmarkFolder*)bookmarksFromFile:(NSString*)filePath;
@end

View File

@ -0,0 +1,166 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Camino code.
*
* The Initial Developer of the Original Code is
* Stuart Morgan
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Stuart Morgan <stuart.morgan@alumni.case.edu>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "OperaBookmarkConverter.h"
#import "NSString+Utils.h"
#import "BookmarkItem.h"
#import "Bookmark.h"
#import "BookmarkFolder.h"
// Opera bookmark file markers and property keys.
static NSString* const kFolderStartMarker = @"#FOLDER";
static NSString* const kFolderEndMarker = @"-";
static NSString* const kBookmarkStartMarker = @"#URL";
static NSString* const kSeparatorMarker = @"#SEPERATOR";
static NSString* const kTitleKey = @"NAME";
static NSString* const kURLKey = @"URL";
static NSString* const kDescriptionKey = @"DESCRIPTION";
static NSString* const kShortcutKey = @"SHORT NAME";
// The format for Opera bookmarks is a flat file with a series of
// space-separated blocks:
//
// MARKER
// KEY=value
// KEY=value
// KEY=value
//
// MARKER
// KEY=value
//
// ...
//
// Folders work the same way, and everything following is enclosed in that
// folder until a line consisting of:
// -
// ends that folder.
@interface OperaBookmarkConverter (Private)
// Consumes lines from enumerator, constructing the appropriate bookmark items,
// until the end of the current folder is reached.
- (void)readLines:(NSEnumerator*)enumerator intoFolder:(BookmarkFolder*)parent;
// Reads key-value pairs from the enumerator until a non-key-value line is
// reached, returning the pairs as a dictionary.
- (NSDictionary*)readProperties:(NSEnumerator*)lineEnumerator;
@end
@implementation OperaBookmarkConverter
+ (id)operaBookmarkConverter
{
return [[[self alloc] init] autorelease];
}
- (BookmarkFolder*)bookmarksFromFile:(NSString*)filePath
{
NSString* fileAsString = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding
error:NULL];
if (!fileAsString) {
NSLog(@"Couldn't read Opera bookmark file.");
return nil;
}
NSRange headerRange = [fileAsString rangeOfString:@"Opera Hotlist"
options:NSCaseInsensitiveSearch];
if (headerRange.location == NSNotFound) {
NSLog(@"Bookmark file not recognized as Opera Hotlist.");
return nil;
}
BookmarkFolder *rootFolder = [[[BookmarkFolder alloc] init] autorelease];
NSArray *lines = [fileAsString componentsSeparatedByString:@"\n"];
[self readLines:[lines objectEnumerator] intoFolder:rootFolder];
return rootFolder;
}
- (void)readLines:(NSEnumerator*)enumerator intoFolder:(BookmarkFolder*)parent
{
NSString *line;
while ((line = [enumerator nextObject])) {
if ([line hasPrefix:kFolderStartMarker]) {
NSDictionary* properties = [self readProperties:enumerator];
BookmarkFolder* folder =
[BookmarkFolder bookmarkFolderWithTitle:[properties objectForKey:kTitleKey]];
[parent appendChild:folder];
[self readLines:enumerator intoFolder:folder];
}
else if ([line hasPrefix:kBookmarkStartMarker]) {
NSDictionary* properties = [self readProperties:enumerator];
BookmarkItem* bookmark =
[Bookmark bookmarkWithTitle:[properties objectForKey:kTitleKey]
url:[properties objectForKey:kURLKey]
lastVisit:nil];
if ([properties objectForKey:kDescriptionKey])
[bookmark setItemDescription:[properties objectForKey:kDescriptionKey]];
if ([properties objectForKey:kShortcutKey])
[bookmark setItemDescription:[properties objectForKey:kShortcutKey]];
[parent appendChild:bookmark];
}
else if ([line hasPrefix:kSeparatorMarker]) {
[parent appendChild:[Bookmark separator]];
}
else if ([line hasPrefix:kFolderEndMarker])
return;
}
}
- (NSDictionary*)readProperties:(NSEnumerator*)lineEnumerator
{
NSMutableDictionary* properties = [NSMutableDictionary dictionary];
NSString *line;
while ((line = [lineEnumerator nextObject])) {
NSRange equalsRange = [line rangeOfString:@"="];
// Each section ends with a blank line, so it's okay that this eats one
// line past the key-value lines.
if (equalsRange.location == NSNotFound)
break;
[properties setObject:[line substringFromIndex:(equalsRange.location + 1)]
forKey:[[line substringToIndex:equalsRange.location]
stringByTrimmingWhitespace]];
}
return properties;
}
@end

View File

@ -0,0 +1,57 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Camino code.
*
* The Initial Developer of the Original Code is
* Stuart Morgan
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Stuart Morgan <stuart.morgan@alumni.case.edu>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import <Foundation/Foundation.h>
@class BookmarkItem;
@class BookmarkFolder;
@interface SafariBookmarkConverter : NSObject {
}
+ (id)safariBookmarkConverter;
// Reads the bookmarks from |filePath| and returns the root bookmark folder
// from the import (or nil if importing fails).
- (BookmarkFolder*)bookmarksFromFile:(NSString*)filePath;
// Writes the bookmark hierarchy rooted at |rootBookmarkItem| to a Safari
// bookmark plist file at |filePath|.
- (void)writeBookmarks:(BookmarkFolder*)bookmarkRoot toFile:(NSString*)filePath;
@end

View File

@ -0,0 +1,243 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Camino code.
*
* The Initial Developer of the Original Code is
* Stuart Morgan
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Stuart Morgan <stuart.morgan@alumni.case.edu>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#import "SafariBookmarkConverter.h"
#import "BookmarkItem.h"
#import "Bookmark.h"
#import "BookmarkFolder.h"
#import "BookmarkManager.h"
static NSString* const kEntryTypeKey = @"WebBookmarkType";
static NSString* const kChildrenKey = @"Children";
static NSString* const kURIDictKey = @"URIDictionary";
static NSString* const kBookmarkTitleKey = @"title";
static NSString* const kBookmarkFolderTitleKey = @"Title";
static NSString* const kTabGroupKey = @"WebBookmarkAutoTab";
static NSString* const kUUIDKey = @"WebBookmarkUUID";
static NSString* const kURLKey = @"URLString";
static NSString* const kProxyKey = @"WebBookmarkIdentifier";
static NSString* const kEntryTypeLeaf = @"WebBookmarkTypeLeaf";
static NSString* const kEntryTypeList = @"WebBookmarkTypeList";
static NSString* const kEntryTypeProxy = @"WebBookmarkTypeProxy";
@interface SafariBookmarkConverter (Private)
// Returns a the correct bookmark item type for the given Safari dictionary.
// Returns nil if the item is an unknown type.
- (BookmarkItem*)bookmarkItemForDictionary:(NSDictionary*)safariDict;
// Returns a native boomark object for the given Safari dictionary.
- (Bookmark*)bookmarkForDictionary:(NSDictionary*)safariDict;
// Returns a native boomark folder object for the given Safari dictionary.
- (BookmarkFolder*)bookmarkFolderForDictionary:(NSDictionary*)safariDict;
// Returns a Safari dictionary of the correct type for the given bookmark item.
// Returns nil if Safari doesn't have a corresponding type (e.g., separators).
- (NSDictionary*)safariDictionaryForBookmarkItem:(BookmarkItem*)bookmarkItem;
// Returns a Safari dictionary for the given bookmark.
- (NSDictionary*)safariDictionaryForBookmark:(Bookmark*)bookmark;
// Returns a Safari dictioray for the given bookmark folder.
// Returns nil if the folder is a special folder that Safari doesn't have.
- (NSDictionary*)safariDictionaryForBookmarkFolder:(BookmarkFolder*)bookmarkFolder;
// Returns the Safari proxy entry for the given smart folder, or nil if there
// is no corresponding Safari entry.
- (NSDictionary*)safariDictionaryForSmartFolder:(BookmarkFolder*)smartFolder;
@end
@implementation SafariBookmarkConverter
+ (id)safariBookmarkConverter
{
return [[[self alloc] init] autorelease];
}
- (BookmarkFolder*)bookmarksFromFile:(NSString*)filePath
{
NSDictionary* dict = [NSDictionary dictionaryWithContentsOfFile:filePath];
if (!dict) {
NSLog(@"Unable to read plist file.");
return nil;
}
if (![dict objectForKey:kEntryTypeKey]) {
NSLog(@"Plist file is not in Safari format.");
return nil;
}
BookmarkFolder* rootFolder = [self bookmarkFolderForDictionary:dict];
return rootFolder;
}
- (BookmarkItem*)bookmarkItemForDictionary:(NSDictionary*)safariDict
{
if ([[safariDict objectForKey:kEntryTypeKey] isEqualToString:kEntryTypeLeaf])
return [self bookmarkForDictionary:safariDict];
if ([[safariDict objectForKey:kEntryTypeKey] isEqualToString:kEntryTypeList])
return [self bookmarkFolderForDictionary:safariDict];
// Could also be WebBookmarkTypeProxy - we'll ignore those.
return nil;
}
- (Bookmark*)bookmarkForDictionary:(NSDictionary*)safariDict
{
NSDictionary* uriDict = [safariDict objectForKey:kURIDictKey];
return [Bookmark bookmarkWithTitle:[uriDict objectForKey:kBookmarkTitleKey]
url:[safariDict objectForKey:kURLKey]
lastVisit:nil];
}
- (BookmarkFolder*)bookmarkFolderForDictionary:(NSDictionary*)safariDict
{
BookmarkFolder* folder = [BookmarkFolder bookmarkFolderWithTitle:
[safariDict objectForKey:kBookmarkFolderTitleKey]];
if ([[safariDict objectForKey:kTabGroupKey] boolValue])
[folder setIsGroup:YES];
NSEnumerator* enumerator = [[safariDict objectForKey:kChildrenKey] objectEnumerator];
id child;
while ((child = [enumerator nextObject])) {
if (![child isKindOfClass:[NSDictionary class]])
continue;
BookmarkItem* bookmarkItem = [self bookmarkItemForDictionary:child];
if (bookmarkItem)
[folder appendChild:bookmarkItem];
}
return folder;
}
#pragma mark -
- (void)writeBookmarks:(BookmarkFolder*)bookmarkRoot toFile:(NSString*)filePath
{
NSDictionary* dict = [self safariDictionaryForBookmarkFolder:bookmarkRoot];
if (![dict writeToFile:[filePath stringByStandardizingPath] atomically:YES])
NSLog(@"Failed to write Safari bookmarks to '%@'", filePath);
}
- (NSDictionary*)safariDictionaryForBookmarkItem:(BookmarkItem*)bookmarkItem
{
if ([bookmarkItem isSeparator])
return nil;
if ([bookmarkItem isKindOfClass:[BookmarkFolder class]])
return [self safariDictionaryForBookmarkFolder:(BookmarkFolder*)bookmarkItem];
return [self safariDictionaryForBookmark:(Bookmark*)bookmarkItem];
}
- (NSDictionary*)safariDictionaryForBookmark:(Bookmark*)bookmark
{
if ([bookmark isSeparator])
return nil;
NSDictionary *uriDict = [NSDictionary dictionaryWithObjectsAndKeys:
[bookmark savedTitle], kBookmarkTitleKey,
[bookmark savedURL], @"",
nil];
return [NSDictionary dictionaryWithObjectsAndKeys:
uriDict, kURIDictKey,
[bookmark savedURL], kURLKey,
kEntryTypeLeaf, kEntryTypeKey,
[bookmark UUID], kUUIDKey,
nil];
}
- (NSDictionary*)safariDictionaryForBookmarkFolder:(BookmarkFolder*)bookmarkFolder
{
if ([bookmarkFolder isSmartFolder])
return [self safariDictionaryForSmartFolder:bookmarkFolder];
NSMutableArray* children = [NSMutableArray array];
NSEnumerator* enumerator = [[bookmarkFolder children] objectEnumerator];
BookmarkItem* item;
while ((item = [enumerator nextObject])) {
NSDictionary* entryDict = [self safariDictionaryForBookmarkItem:item];
if (entryDict)
[children addObject:entryDict];
}
NSString *titleString;
if ([bookmarkFolder isToolbar])
titleString = @"BookmarksBar";
else if ([[BookmarkManager sharedBookmarkManager] bookmarkMenuFolder] == bookmarkFolder)
titleString = @"BookmarksMenu";
else
titleString = [bookmarkFolder title];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:
titleString, kBookmarkFolderTitleKey,
kEntryTypeList, kEntryTypeKey,
[bookmarkFolder UUID], kUUIDKey,
children, kChildrenKey,
nil];
if ([bookmarkFolder isGroup])
[dict setObject:[NSNumber numberWithBool:YES] forKey:kTabGroupKey];
return dict;
}
- (NSDictionary*)safariDictionaryForSmartFolder:(BookmarkFolder*)smartFolder
{
NSString* title = nil;
NSString* proxy = nil;
if (smartFolder == [[BookmarkManager sharedBookmarkManager] rendezvousFolder]) {
title = @"Bonjour";
proxy = @"Bonjour Bookmark Proxy Identifier";
}
else if (smartFolder == [[BookmarkManager sharedBookmarkManager] addressBookFolder]) {
title = @"Address Book";
proxy = @"Address Book Bookmark Proxy Identifier";
}
else if (smartFolder == [[BookmarkManager sharedBookmarkManager] historyFolder]) {
title = @"History";
proxy = @"History Bookmark Proxy Identifier";
}
if (title && proxy) {
return [NSDictionary dictionaryWithObjectsAndKeys:
title, kBookmarkFolderTitleKey,
proxy, kProxyKey,
kEntryTypeProxy, kEntryTypeKey,
[smartFolder UUID], kUUIDKey,
nil];
}
return nil;
}
@end