NSURLHandle implementation

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@7580 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2000-09-21 12:31:29 +00:00
parent e2bf6a6571
commit 47eb44d12d
3 changed files with 387 additions and 205 deletions

View file

@ -1,3 +1,9 @@
2000-09-21 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/gnustep/base/NSURLHandle.h: tidy up.
* Source/NSURLHandle.m: Implement class and add simple implementation
of a concrete subclass for handling file URLs.
2000-09-20 Richard Frith-Macdonald <rfm@gnu.org>
* Headers/gnustep/base/GSXML.h: Added ([-parser:]) and removed

View file

@ -24,6 +24,10 @@
#ifndef _NSURLHandle_h__
#define _NSURLHandle_h__
@class NSData;
@class NSString;
@class NSMutableArray;
@class NSMutableData;
@class NSURLHandle;
@class NSURL;
@ -57,48 +61,40 @@ typedef enum
//=============================================================================
@interface NSURLHandle: NSObject
{
NSMutableData *_data;
NSMutableArray *_clients;
id _data;
NSString *_failure;
NSURLHandleStatus _status;
}
+ (NSURLHandle*) cachedHandleForURL: (NSURL*)url;
+ (BOOL) canInitWithURL: (NSURL*)url;
+ (void) registerURLHandleClass: (Class)urlHandleSubclass;
+ (Class) URLHandleClassForURL: (NSURL*)url;
- (id) initWithURL: (NSURL*)url
cached: (BOOL)cached;
- (NSURLHandleStatus) status;
- (NSString*) failureReason;
- (void) addClient: (id <NSURLHandleClient>)client;
- (void) removeClient: (id <NSURLHandleClient>)client;
- (void) loadInBackground;
- (void) cancelLoadInBackground;
- (NSData*) resourceData;
- (NSData*) availableResourceData;
- (void) flushCachedData;
- (void) backgroundLoadDidFailWithReason: (NSString*)reason;
- (void) beginLoadInBackground;
- (void) cancelLoadInBackground;
- (void) didLoadBytes: (NSData*)newData
loadComplete: (BOOL)loadComplete;
+ (BOOL) canInitWithURL: (NSURL*)url;
+ (NSURLHandle*) cachedHandleForURL: (NSURL*)url;
- (void) endLoadInBackground;
- (NSString*) failureReason;
- (void) flushCachedData;
- (id) initWithURL: (NSURL*)url
cached: (BOOL)cached;
- (void) loadInBackground;
- (NSData*) loadInForeground;
- (id) propertyForKey: (NSString*)propertyKey;
- (id) propertyForKeyIfAvailable: (NSString*)propertyKey;
- (void) removeClient: (id <NSURLHandleClient>)client;
- (NSData*) resourceData;
- (NSURLHandleStatus) status;
- (BOOL) writeData: (NSData*)data;
- (BOOL) writeProperty: (id)propertyValue
forKey: (NSString*)propertyKey;
- (BOOL) writeData: (NSData*)data;
- (NSData*) loadInForeground;
- (void) beginLoadInBackground;
- (void) endLoadInBackground;
@end

View file

@ -2,7 +2,9 @@
Copyright (C) 1999 Free Software Foundation, Inc.
Written by: Manuel Guesdon <mguesdon@sbuilders.com>
Date: Jan 1999
Date: Jan 1999
Update: Richard Frith-Macdonald <rfm@gnu.org>
Date: Sep 2000
This file is part of the GNUstep Library.
@ -21,15 +23,11 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
/*
Note from Manuel Guesdon:
* functions are not implemented. If someone has documentation or ideas on
how it should work...
*/
#include <config.h>
#include <base/behavior.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSData.h>
#include <Foundation/NSEnumerator.h>
#include <Foundation/NSString.h>
#include <Foundation/NSException.h>
#include <Foundation/NSConcreteNumber.h>
@ -37,39 +35,71 @@ how it should work...
#include <Foundation/NSURL.h>
#include <Foundation/NSMapTable.h>
//=============================================================================
@class GSFileURLHandle;
@implementation NSURLHandle
static NSMapTable *cache = 0;
static NSMutableArray *registry = nil;
+ (NSURLHandle*) cachedHandleForURL: (NSURL*)url
{
/*
* Each subclass is supposed to do its own caching, so we must
* find the correct subclass and ask it for its cached handle.
*/
if (self == [NSURLHandle class])
{
Class c = [self URLHandleClassForURL: url];
return [c cachedHandleForURL: url];
}
else
{
[self subclassResponsibility: _cmd];
return nil;
}
}
+ (BOOL) canInitWithURL: (NSURL*)url
{
/*
* The semi-abstract base class can't handle ANY scheme
*/
return NO;
}
+ (void) initialize
{
if (self == [NSURLHandle class])
{
cache = NSCreateMapTable(NSObjectMapKeyCallBacks,
NSObjectMapValueCallBacks, 0);
registry = [NSMutableArray new];
[self registerURLHandleClass: [GSFileURLHandle class]];
}
}
+ (void) registerURLHandleClass: (Class)_urlHandleSubclass
+ (void) registerURLHandleClass: (Class)urlHandleSubclass
{
if ([registry indexOfObjectIdenticalTo: _urlHandleSubclass] == NSNotFound)
{
[registry addObject: _urlHandleSubclass];
}
/*
* Maintain a registry of classes that handle various schemes
* Re-adding a class moves it to the end of the registry - so it will
* be used in preference to any class added earlier.
*/
[registry removeObjectIdenticalTo: urlHandleSubclass];
[registry addObject: urlHandleSubclass];
}
+ (Class) URLHandleClassForURL: (NSURL*)_url
+ (Class) URLHandleClassForURL: (NSURL*)url
{
unsigned count = [registry count];
/*
* Find a class to handle the URL, try most recently registered first.
*/
while (count-- > 0)
{
id found = [registry objectAtIndex: count];
if ([found canInitWithURL: _url] == YES)
if ([found canInitWithURL: url] == YES)
{
return (Class)found;
}
@ -77,185 +107,335 @@ static NSMutableArray *registry = nil;
return 0;
}
- (id) initWithURL: (NSURL*)_url
cached: (BOOL)_cached
- (void) addClient: (id <NSURLHandleClient>)client
{
Class concreteSubclass;
NSURLHandle *instance;
if (_cached == YES)
{
instance = (id)NSMapGet(cache, (void*)_url);
if (instance != nil)
{
RELEASE(self);
return instance;
}
}
concreteSubclass = [NSURLHandle URLHandleClassForURL: _url];
if (concreteSubclass == 0)
{
NSLog(@"Attempt to init NSURLHandle with unsupported URL schema");
RELEASE(self);
}
RELEASE(self);
instance = [concreteSubclass alloc];
instance = [instance initWithURL: _url cached: _cached];
if (instance != nil)
{
NSMapInsert(cache, (void*)_url, (void*)instance);
}
return instance;
[_clients addObject: client];
}
//-----------------------------------------------------------------------------
- (NSURLHandleStatus) status
{
//FIXME
[self notImplemented: _cmd];
return (NSURLHandleStatus)0;
}
//-----------------------------------------------------------------------------
- (NSString*) failureReason
{
//FIXME
[self notImplemented: _cmd];
return nil;
}
//-----------------------------------------------------------------------------
- (void) addClient: (id <NSURLHandleClient>)_client
{
//FIXME
[self notImplemented: _cmd];
}
//-----------------------------------------------------------------------------
- (void) removeClient: (id <NSURLHandleClient>)_client
{
//FIXME
[self notImplemented: _cmd];
}
//-----------------------------------------------------------------------------
- (void) loadInBackground
{
//FIXME
[self notImplemented: _cmd];
}
//-----------------------------------------------------------------------------
- (void) cancelLoadInBackground
{
//FIXME
[self notImplemented: _cmd];
}
//-----------------------------------------------------------------------------
- (NSData*) resourceData
{
//FIXME
[self notImplemented: _cmd];
return nil;
}
//-----------------------------------------------------------------------------
- (NSData*) availableResourceData
{
//FIXME
[self notImplemented: _cmd];
return nil;
return AUTORELEASE([_data copy]);
}
//-----------------------------------------------------------------------------
- (void) flushCachedData
{
NSResetMapTable(cache);
}
//-----------------------------------------------------------------------------
- (void) backgroundLoadDidFailWithReason: (NSString*)reason
{
//FIXME
[self notImplemented: _cmd];
NSEnumerator *enumerator = [_clients objectEnumerator];
id <NSURLHandleClient> client;
_status = NSURLHandleLoadFailed;
[_data setLength: 0];
ASSIGNCOPY(_failure, reason);
while ((client = [enumerator nextObject]) != nil)
{
[client URLHandle: self resourceDidFailLoadingWithReason: _failure];
}
}
//-----------------------------------------------------------------------------
- (void) didLoadBytes: (NSData*)newData
loadComplete: (BOOL)_loadComplete
{
//FIXME
[self notImplemented: _cmd];
}
//-----------------------------------------------------------------------------
+ (BOOL) canInitWithURL: (NSURL*)_url
{
//FIXME
[self notImplemented: _cmd];
return NO;
}
//-----------------------------------------------------------------------------
+ (NSURLHandle*) cachedHandleForURL: (NSURL*)_url
{
return (NSURLHandle*) NSMapGet(cache, (void*)_url);
}
//-----------------------------------------------------------------------------
- (id) propertyForKey: (NSString*)propertyKey
{
//FIXME
[self notImplemented: _cmd];
return nil;
}
//-----------------------------------------------------------------------------
- (id) propertyForKeyIfAvailable: (NSString*)propertyKey
{
//FIXME
[self notImplemented: _cmd];
return nil;
}
//-----------------------------------------------------------------------------
- (BOOL) writeProperty: (id)propertyValue
forKey: (NSString*)propertyKey
{
//FIXME
[self notImplemented: _cmd];
return NO;
}
//-----------------------------------------------------------------------------
- (BOOL) writeData: (NSData*)data
{
//FIXME
[self notImplemented: _cmd];
return NO;
}
//-----------------------------------------------------------------------------
- (NSData*) loadInForeground
{
//FIXME
[self notImplemented: _cmd];
return nil;
}
//-----------------------------------------------------------------------------
- (void) beginLoadInBackground
{
//FIXME
[self notImplemented: _cmd];
_status = NSURLHandleLoadInProgress;
[_data setLength: 0];
[_clients makeObjectsPerformSelector:
@selector(URLHandleResourceDidBeginLoading:)
withObject: self];
}
- (void) cancelLoadInBackground
{
_status = NSURLHandleNotLoaded;
[_data setLength: 0];
[_clients makeObjectsPerformSelector:
@selector(URLHandleResourceDidCancelLoading:)
withObject: self];
[self endLoadInBackground];
}
- (void) dealloc
{
RELEASE(_data);
RELEASE(_failure);
RELEASE(_clients);
[super dealloc];
}
/*
* Mathod called by subclasses during process of loading a resource.
* The base class maintains a copy of the data being read in and
* accumulates separate parts of the data.
*/
- (void) didLoadBytes: (NSData*)newData
loadComplete: (BOOL)loadComplete
{
NSEnumerator *enumerator;
id <NSURLHandleClient> client;
/*
* Let clients know we are starting loading (unless this has already been
* done).
*/
if (_status != NSURLHandleLoadInProgress)
{
_status = NSURLHandleLoadInProgress;
[_data setLength: 0];
[_clients makeObjectsPerformSelector:
@selector(URLHandleResourceDidBeginLoading:)
withObject: self];
}
/*
* If we have been given nil data, there must have been a failure!
*/
if (newData == nil)
{
[self backgroundLoadDidFailWithReason: @"nil data"];
return;
}
/*
* Let clients know we have read some data.
*/
enumerator = [_clients objectEnumerator];
while ((client = [enumerator nextObject]) != nil)
{
[client URLHandle: self resourceDataDidBecomeAvailable: newData];
}
/*
* Accumulate data in cache.
*/
[_data appendData: newData];
if (loadComplete == YES)
{
/*
* Let clients know we have finished loading.
*/
_status = NSURLHandleLoadSucceeded;
[_clients makeObjectsPerformSelector:
@selector(URLHandleResourceDidFinishLoading:)
withObject: self];
}
}
//-----------------------------------------------------------------------------
- (void) endLoadInBackground
{
//FIXME
[self notImplemented: _cmd];
_status = NSURLHandleNotLoaded;
[_data setLength: 0];
}
- (NSString*) failureReason
{
if (_status == NSURLHandleLoadFailed)
return _failure;
else
return nil;
}
- (void) flushCachedData
{
[_data setLength: 0];
}
- (id) init
{
_status = NSURLHandleNotLoaded;
_clients = [NSMutableArray new];
_data = [NSMutableData new];
return self;
}
- (id) initWithURL: (NSURL*)url
cached: (BOOL)cached
{
[self subclassResponsibility: _cmd];
return nil;
}
- (void) loadInBackground
{
[self subclassResponsibility: _cmd];
}
- (NSData*) loadInForeground
{
[self subclassResponsibility: _cmd];
return nil;
}
- (id) propertyForKey: (NSString*)propertyKey
{
[self subclassResponsibility: _cmd];
return nil;
}
- (id) propertyForKeyIfAvailable: (NSString*)propertyKey
{
[self subclassResponsibility: _cmd];
return nil;
}
- (void) removeClient: (id <NSURLHandleClient>)client
{
[_clients removeObjectIdenticalTo: client];
}
- (NSData*) resourceData
{
if (_status == NSURLHandleLoadSucceeded)
{
return [self availableResourceData];
}
else
{
NSData *d = [self loadInForeground];
if (d != nil)
{
[_data setData: d];
}
return d;
}
}
- (NSURLHandleStatus) status
{
return _status;
}
- (BOOL) writeData: (NSData*)data
{
[self subclassResponsibility: _cmd];
return NO;
}
- (BOOL) writeProperty: (id)propertyValue
forKey: (NSString*)propertyKey
{
[self subclassResponsibility: _cmd];
return NO;
}
@end
@interface GSFileURLHandle : NSURLHandle
{
NSString *_path;
}
@end
@implementation GSFileURLHandle
static NSMutableDictionary *fileCache = nil;
+ (NSURLHandle*) cachedHandleForURL: (NSURL*)url
{
NSURLHandle *obj = nil;
if ([url isFileURL] == YES)
{
NSString *path = [url path];
path = [path stringByStandardizingPath];
obj = [fileCache objectForKey: path];
}
return obj;
}
+ (BOOL) canInitWithURL: (NSURL*)url
{
if ([url isFileURL] == YES)
{
return YES;
}
return NO;
}
+ (void) initialize
{
fileCache = [NSMutableDictionary new];
}
- (void) dealloc
{
RELEASE(_path);
[super dealloc];
}
- (id) initWithURL: (NSURL*)url
cached: (BOOL)cached
{
NSString *path;
if ([url isFileURL] == NO)
{
NSLog(@"Attempt to init GSFileURLHandle with bad URL");
RELEASE(self);
return nil;
}
path = [url path];
path = [path stringByStandardizingPath];
if (cached == YES)
{
id obj;
obj = [fileCache objectForKey: path];
if (obj != nil)
{
RELEASE(self);
self = RETAIN(obj);
return self;
}
}
self = [super init];
if (self != nil)
{
_path = [path copy];
if (cached == YES)
{
[fileCache setObject: self forKey: _path];
RELEASE(self);
}
}
return self;
}
- (void) loadInBackground
{
[self loadInForeground];
}
- (NSData*) loadInForeground
{
NSData *d = [NSData dataWithContentsOfFile: _path];
[self didLoadBytes: d loadComplete: YES];
return d;
}
- (id) propertyForKey: (NSString*)propertyKey
{
return nil;
}
- (id) propertyForKeyIfAvailable: (NSString*)propertyKey
{
return nil;
}
- (BOOL) writeData: (NSData*)data
{
/* FIXME */
[self notImplemented: _cmd];
return NO;
}
- (BOOL) writeProperty: (id)propertyValue
forKey: (NSString*)propertyKey
{
return NO;
}
@end