Added SOPE (r1664) to Inverse's monotone repo.
Monotone-Revision: c98854ace8d5141925016369142b44606e4a148f Monotone-Author: ludovic@Sophos.ca Monotone-Date: 2010-07-29T17:27:45 Monotone-Branch: ca.inverse.sopepull/45/head
commit
f94d0381bb
|
@ -0,0 +1,3 @@
|
|||
Copyright (C) 2000-2005 SKYRIX Software AG
|
||||
|
||||
Contact: info@skyrix.com
|
|
@ -0,0 +1,59 @@
|
|||
# GNUstep makefile
|
||||
|
||||
-include ./config.make
|
||||
|
||||
ifeq ($(GNUSTEP_MAKEFILES),)
|
||||
|
||||
$(warning Note: Your $(GNUSTEP_MAKEFILES) environment variable is empty!)
|
||||
$(warning Either use ./configure or source GNUstep.sh.)
|
||||
|
||||
else
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
|
||||
SUBPROJECTS += \
|
||||
sope-xml \
|
||||
sope-core \
|
||||
sope-mime \
|
||||
sope-appserver \
|
||||
sope-ical \
|
||||
sope-gdl1 \
|
||||
xmlrpc_call
|
||||
|
||||
ifeq ($(HAS_LIBRARY_ldap),yes)
|
||||
SUBPROJECTS += sope-ldap
|
||||
endif
|
||||
|
||||
ifeq ($(FOUNDATION_LIB),apple)
|
||||
ifeq ($(frameworks),yes)
|
||||
SUBPROJECTS += sopex
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
-include $(GNUSTEP_MAKEFILES)/GNUmakefile.preamble
|
||||
include $(GNUSTEP_MAKEFILES)/aggregate.make
|
||||
-include $(GNUSTEP_MAKEFILES)/GNUmakefile.postamble
|
||||
|
||||
include ./Version
|
||||
|
||||
endif
|
||||
|
||||
distclean ::
|
||||
if test -f config.make; then rm config.make; fi
|
||||
if test -d .gsmake; then rm -r .gsmake; fi
|
||||
if test -f config-NGStreams.log; then rm config-NGStreams.log; fi
|
||||
if test -f config-gstepmake.log; then rm config-gstepmake.log; fi
|
||||
|
||||
macosx-pkg ::
|
||||
for i in $(SUBPROJECTS); do \
|
||||
(cd $$i; $(MAKE) macosx-pkg); \
|
||||
done
|
||||
./maintenance/make-osxmpkg.sh \
|
||||
"SOPE-$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION)"
|
||||
|
||||
macosx-dmg :: macosx-pkg
|
||||
./maintenance/make-osxdmg.sh \
|
||||
"SOPE-$(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION)" \
|
||||
osxpkgbuild \
|
||||
"SOPE $(MAJOR_VERSION).$(MINOR_VERSION).$(SUBMINOR_VERSION)"
|
|
@ -0,0 +1,86 @@
|
|||
SOPE Installation Guide
|
||||
=======================
|
||||
|
||||
Prerequisites
|
||||
=============
|
||||
|
||||
- gstep-make
|
||||
- libFoundation or gstep-base or Cocoa Foundation
|
||||
- libxml2/libxml2-dev
|
||||
- autoconf
|
||||
- openldap2/openldap2-dev
|
||||
- postgresql-dev
|
||||
|
||||
sope-xml
|
||||
- libxml2/libxml2-dev
|
||||
|
||||
sope-core
|
||||
- autoconf
|
||||
|
||||
sope-ldap
|
||||
- openldap2/openldap2-dev
|
||||
|
||||
sope-gdl1
|
||||
- postgresql-dev
|
||||
|
||||
|
||||
(Internal) Dependencies
|
||||
=======================
|
||||
|
||||
sope-xml
|
||||
- [self contained]
|
||||
|
||||
sope-core
|
||||
- sope-xml
|
||||
|
||||
sope-mime
|
||||
- sope-core
|
||||
|
||||
sope-ical
|
||||
- sope-xml
|
||||
- sope-core
|
||||
|
||||
sope-ldap
|
||||
|
||||
sope-appserver
|
||||
- sope-xml
|
||||
- sope-core
|
||||
- sope-mime (to be removed!)
|
||||
|
||||
sope-gdl1
|
||||
- sope-core (EOControl/NGExtensions)
|
||||
|
||||
|
||||
Building
|
||||
========
|
||||
|
||||
If the prerequisites are properly fulfilled, building SOPE 4.5 is
|
||||
a simple:
|
||||
|
||||
./configure
|
||||
make -s all
|
||||
|
||||
(a build takes about 5 minutes on a Debian/Athlon 1.8+)
|
||||
|
||||
Installation:
|
||||
|
||||
make -s install
|
||||
|
||||
|
||||
Troubleshooting
|
||||
===============
|
||||
|
||||
* /common.make not found
|
||||
|
||||
If you see errors like "/common.make" not found you either did not configure
|
||||
your SOPE tree _or_ you did not source GNUstep.sh
|
||||
|
||||
* warning: Foundation/NSObject.h: No such file or directory
|
||||
|
||||
You did not install a Foundation library, eg libFoundation
|
||||
|
||||
Building mod_ngobjweb
|
||||
=====================
|
||||
|
||||
TODO: write something
|
||||
Note: a README is in the mod_ngobjweb directory?
|
|
@ -0,0 +1 @@
|
|||
PROJECTLEAD=helge.hess@opengroupware.org
|
|
@ -0,0 +1,66 @@
|
|||
SKYRiX Object Publishing Environment
|
||||
====================================
|
||||
|
||||
This directory contains SOPE, the application server hosting the
|
||||
OpenGroupware.org business logic and web interface.
|
||||
|
||||
SOPE 4.5 is the development version of the upcoming SOPE 4.6 release.
|
||||
|
||||
SKYRiX Libraries for XML Processing (sope-xml)
|
||||
==============================================
|
||||
|
||||
The package contains:
|
||||
- a SAX2 Implementation for Objective-C
|
||||
- SaxObjC driver bundles for: libxml2 (HTML, XML), libical (iCalendar,
|
||||
vCard), expat (XML), plists, pyx, CoreFoundation (XML)
|
||||
- DOM on top of SaxObjC
|
||||
- an XML-RPC implementation (without the transport layer)
|
||||
|
||||
SKYRiX Core Libraries (sope-core)
|
||||
=================================
|
||||
|
||||
The SKYRiX Core libraries (sope-core) contain:
|
||||
- various Foundation extensions
|
||||
- a java.io like stream and socket library
|
||||
|
||||
SKYRiX MIME Libraries (sope-mime)
|
||||
=================================
|
||||
|
||||
- classes for processing MIME entities
|
||||
- a full IMAP4 implementation
|
||||
- prototypical POP3 and SMTP processors
|
||||
|
||||
SKYRiX LDAP Libraries (sope-ldap)
|
||||
=================================
|
||||
|
||||
- an Objective-C wrapper for LDAP directory services
|
||||
|
||||
SKYRiX iCalendar Libraries (sope-ical)
|
||||
======================================
|
||||
|
||||
- classes for iCalendar/vCard objects
|
||||
|
||||
SKYRiX Application Server (SOPE)
|
||||
================================
|
||||
|
||||
The SKYRiX SOPE package is a framework for developing web applications and
|
||||
services. The name "SOPE" (SKYRiX Object Publishing Environment) is
|
||||
inspired by ZOPE ;-)
|
||||
|
||||
It provides
|
||||
- template rendering engine, lots of dynamic elements
|
||||
- HTTP client/server
|
||||
- XML-RPC client
|
||||
- WebDAV server framework
|
||||
- session management
|
||||
- scripting extensions for Foundation, JavaScript bridge
|
||||
- DOM tree rendering library
|
||||
|
||||
mod_ngobjweb
|
||||
============
|
||||
|
||||
An Apache module for forwarding HTTP request from Apache to a SOPE
|
||||
application server. This is a non-streaming proxy so that the application
|
||||
server isn't blocked by IO of slow connections!
|
||||
(this eliminates the need for threading because of IO, the Apache server
|
||||
pool runs the blocking IO operations)
|
|
@ -0,0 +1,120 @@
|
|||
Building Notes
|
||||
==============
|
||||
|
||||
Prerequisites:
|
||||
- Apple Developer Tools
|
||||
|
||||
There are two ways to build SOPE on MacOSX:
|
||||
a) build using gnustep-make
|
||||
b) build using Xcode >= 2.4
|
||||
|
||||
Option a) is usually used when you build SOPE for use with OGo, while b)
|
||||
is more appropriate for SOPE:X applications or other interested
|
||||
3rd parties which already have existing Xcode projects.
|
||||
|
||||
|
||||
Building using gstep-make:
|
||||
==========================
|
||||
|
||||
For the build just enter:
|
||||
./configure
|
||||
make -s install
|
||||
or
|
||||
make -s debug=yes install
|
||||
if you build with debug information.
|
||||
|
||||
|
||||
Building using Xcode:
|
||||
=====================
|
||||
|
||||
For the Xcode build to succeed it is imperative to have everything built
|
||||
in a central location. This can be achieved by navigating to:
|
||||
|
||||
Xcode -> Preferences -> Building
|
||||
|
||||
and select:
|
||||
"Place Build Products in:" [x] Customized location:
|
||||
|
||||
The location itself is arbitrary, mine is: "/Local/BuildArea".
|
||||
|
||||
|
||||
The Xcode build comes in two variants, one for development and the other
|
||||
for deployment.
|
||||
|
||||
Development
|
||||
-----------
|
||||
|
||||
Development usually means you're happily hacking away at your pet
|
||||
projects and sometimes want to update the SOPE frameworks. For this purpose
|
||||
use the "all" target and the accompanied "Development" build style. Later,
|
||||
you can narrow the target down to something more specific. For development
|
||||
we assume the destination for frameworks to be /Library/Frameworks.
|
||||
Once you are done building all the frameworks the loader commands of the
|
||||
frameworks will have that destination path built in. In order to use the
|
||||
frameworks you either have to install them (by copying them manually to
|
||||
their intended destination) or to prepare symlinks from
|
||||
/Library/Frameworks to the place where the built products
|
||||
are. I usually have symlinks from /Library/Frameworks to /Local/BuildArea
|
||||
(see above) for each of the products.
|
||||
|
||||
Also the following products are expected to be in the following locations:
|
||||
*.sax -> /Library/SaxDrivers
|
||||
*.sxp -> /Library/SoProducts
|
||||
|
||||
Either copy them to the appropriate places or symlink them
|
||||
(my suggestion).
|
||||
|
||||
|
||||
Deployment
|
||||
----------
|
||||
|
||||
Deployment in our terms means you want to copy all required SOPE products
|
||||
into an application's app wrapper. For this step all frameworks need to be
|
||||
built in a special fashion, as the "install_name" of the frameworks needs
|
||||
to be prepared to point to a relative path in the app wrapper. The
|
||||
situation is even more complicated as all frameworks during linking store
|
||||
the "install names" of other frameworks in their mach loader commands. In
|
||||
order for this step not to break we need to set up an environment which is
|
||||
clearly separated from the Development environment. I chose to use
|
||||
$(USER_LIBRARY_DIR)/EmbeddedFrameworks
|
||||
as the default destination for these builds. In order for your application
|
||||
to easily pick up the built products and copy them into its app wrapper
|
||||
this location needs to be fixed and easily accessible. Note that on my
|
||||
system ~/Library/EmbeddedFrameworks is a symlink to
|
||||
/Library/EmbeddedFrameworks so even if you don't like the location at all
|
||||
it's very easy to point it to someplace else. As soon as you have set this
|
||||
up you can use the "Wrapper Contents" target with the accompanied
|
||||
"Wrapper" build style to build all wrapper contents in the appropriate
|
||||
fashion. When you're done you can copy all the wrapper products into your
|
||||
application's wrapper. The expected destination is the "Frameworks"
|
||||
directory in the wrappers "Contents" directory. For a complete list of
|
||||
what you need to copy into your application's wrapper see the
|
||||
"Direct Dependencies" of all "Wrapper Contents" targets in all SOPE
|
||||
related projects.
|
||||
|
||||
The SOPE umbrella
|
||||
-----------------
|
||||
|
||||
For Deployment purposes, the SOPE umbrella framework comes in pretty
|
||||
handy. If you use it in conjunction with the "Wrapper" build style, it
|
||||
will be created in
|
||||
$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/SOPE.framework
|
||||
and can be copied into your application's app wrapper without further
|
||||
adjustments. It contains all SOPE frameworks and also guarantees that
|
||||
all loader commands of the frameworks and SaxDriver bundles will have been
|
||||
fixed to be relative to the SOPE.framework umbrella.
|
||||
|
||||
|
||||
Prebinding Notes
|
||||
================
|
||||
|
||||
NOTE: AS OF MAC OS X 10.5, PREBINDING IS DEPRECATED.
|
||||
The following is left here as a reference, only.
|
||||
|
||||
General technical information about prebinding is available from Apple at
|
||||
http://developer.apple.com/documentation/Performance/Conceptual/LaunchTime/Tasks/Prebinding.html#//apple_ref/doc/uid/20001858.
|
||||
|
||||
OGo frameworks currently use the range from 0xC0000000 to 0xCFFFFFFF.
|
||||
|
||||
Any questions and feedback regarding our use of this range should go to
|
||||
Marcus Mueller <znek@mulle-kybernetik.com>.
|
|
@ -0,0 +1,4 @@
|
|||
*.apache
|
||||
*_module_structure.m
|
||||
logs
|
||||
shared_debug_obj
|
|
@ -0,0 +1,27 @@
|
|||
// $Id: AWODirectoryConfig.h,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#ifndef __AWODirectoryConfig_H__
|
||||
#define __AWODirectoryConfig_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class WOApplication, WORequestHandler;
|
||||
@class ApacheResourcePool, ApacheCmdParms;
|
||||
|
||||
@interface AWODirectoryConfig : NSObject
|
||||
{
|
||||
WOApplication *application;
|
||||
WORequestHandler *rqHandler;
|
||||
}
|
||||
|
||||
/* configuration */
|
||||
|
||||
- (void)setApplication:(WOApplication *)_app;
|
||||
- (WOApplication *)application;
|
||||
|
||||
- (void)setRequestHandler:(WORequestHandler *)_handler;
|
||||
- (WORequestHandler *)requestHandler;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __AWODirectoryConfig_H__ */
|
|
@ -0,0 +1,137 @@
|
|||
// $Id: AWODirectoryConfig.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "AWODirectoryConfig.h"
|
||||
#include "ApacheWO.h"
|
||||
#include <ApacheAPI/ApacheResourcePool.h>
|
||||
#include <NGObjWeb/WOApplication.h>
|
||||
#include <NGObjWeb/WORequestHandler.h>
|
||||
#include "common.h"
|
||||
|
||||
@implementation AWODirectoryConfig
|
||||
|
||||
- (id)init {
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithConfig:(AWODirectoryConfig *)_cfg {
|
||||
if ((self = [self init])) {
|
||||
self->application = [_cfg->application retain];
|
||||
self->rqHandler = [_cfg->rqHandler retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithBaseConfig:(AWODirectoryConfig *)_base
|
||||
andConfig:(AWODirectoryConfig *)_new
|
||||
{
|
||||
if ((self = [self initWithConfig:_base])) {
|
||||
if (_new->application)
|
||||
ASSIGN(self->application, _new->application);
|
||||
if (_new->rqHandler)
|
||||
ASSIGN(self->rqHandler, _new->rqHandler);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
RELEASE(self->application);
|
||||
RELEASE(self->rqHandler);
|
||||
[super dealloc];
|
||||
}
|
||||
+ (id)mergeBaseConfig:(AWODirectoryConfig *)_base
|
||||
withNewConfig:(AWODirectoryConfig *)_new
|
||||
{
|
||||
return [[[self alloc] initWithBaseConfig:_base andConfig:_new] autorelease];
|
||||
}
|
||||
|
||||
- (NSString *)stringValue {
|
||||
return [self description];
|
||||
}
|
||||
- (NSString *)description {
|
||||
NSMutableString *ms;
|
||||
id tmp;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:64];
|
||||
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
|
||||
|
||||
if ((tmp = [self application]))
|
||||
[ms appendFormat:@" app=%@(0x%p)", [(WOApplication *)tmp name], tmp];
|
||||
if ((tmp = [self requestHandler]))
|
||||
[ms appendFormat:@" rqh=%@", tmp];
|
||||
|
||||
[ms appendString:@">"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
/* configuration */
|
||||
|
||||
- (void)setApplication:(WOApplication *)_app {
|
||||
ASSIGN(self->application, _app);
|
||||
}
|
||||
- (WOApplication *)application {
|
||||
return self->application;
|
||||
}
|
||||
|
||||
- (void)setRequestHandler:(WORequestHandler *)_handler {
|
||||
ASSIGN(self->rqHandler, _handler);
|
||||
}
|
||||
- (WORequestHandler *)requestHandler {
|
||||
return self->rqHandler;
|
||||
}
|
||||
|
||||
/* commands */
|
||||
|
||||
- (id)SetSxApplication:(NSString *)_key {
|
||||
WOApplication *app;
|
||||
|
||||
if ((app = [self application])) {
|
||||
[self logWithFormat:@"application already set !"];
|
||||
}
|
||||
|
||||
if ((app = [ApacheWO applicationForKey:_key className:nil]) == nil) {
|
||||
[self logWithFormat:@"got no application for key '%@'", _key];
|
||||
}
|
||||
else {
|
||||
[self setApplication:app];
|
||||
}
|
||||
|
||||
return nil /* nil means 'no error' */;
|
||||
}
|
||||
|
||||
- (id)SetSxRequestHandler:(NSString *)_className {
|
||||
WORequestHandler *rqh;
|
||||
Class rqhClazz;
|
||||
|
||||
if ((rqh = [self requestHandler])) {
|
||||
[self logWithFormat:@"requestHandler already set !"];
|
||||
}
|
||||
|
||||
if ((rqhClazz = NSClassFromString(_className)) == Nil) {
|
||||
return [NSString stringWithFormat:
|
||||
@"did not find request handler for class '%@'",
|
||||
_className];
|
||||
}
|
||||
|
||||
if ((rqh = [[rqhClazz alloc] init]) == nil) {
|
||||
return [NSString stringWithFormat:
|
||||
@"could not allocate request handler of class '%@'",
|
||||
_className];
|
||||
}
|
||||
|
||||
[self setRequestHandler:rqh];
|
||||
RELEASE(rqh);
|
||||
|
||||
return nil /* nil means 'no error' */;
|
||||
}
|
||||
|
||||
- (id)LogText:(NSString *)_txt {
|
||||
if ([_txt length] == 0)
|
||||
/* return an error text */
|
||||
return @"missing echo text !";
|
||||
|
||||
//[self appendString:_txt];
|
||||
|
||||
return nil /* nil means 'no error' */;
|
||||
}
|
||||
|
||||
@end /* AWODirectoryConfig */
|
|
@ -0,0 +1,22 @@
|
|||
// $Id: AWOServerConfig.h,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#ifndef __AWOServerConfig_H__
|
||||
#define __AWOServerConfig_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class AliasMap;
|
||||
@class NSMutableDictionary, NSMutableArray;
|
||||
@class WOApplication, WORequestHandler;
|
||||
@class ApacheResourcePool, ApacheServer, ApacheCmdParms;
|
||||
|
||||
@interface AWOServerConfig : NSObject
|
||||
{
|
||||
@public
|
||||
AliasMap *appAlias;
|
||||
AliasMap *handlerAlias;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __AWOServerConfig_H__ */
|
|
@ -0,0 +1,104 @@
|
|||
// $Id: AWOServerConfig.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "AWOServerConfig.h"
|
||||
#include "AliasMap.h"
|
||||
#include <ApacheAPI/ApacheResourcePool.h>
|
||||
#include <ApacheAPI/ApacheServer.h>
|
||||
#include <ApacheAPI/ApacheCmdParms.h>
|
||||
#include <NGObjWeb/WOApplication.h>
|
||||
#include <NGObjWeb/WORequestHandler.h>
|
||||
#include "common.h"
|
||||
|
||||
@implementation AWOServerConfig
|
||||
|
||||
- (id)initWithServer:(ApacheServer *)_server {
|
||||
//NSLog(@"%s: init with server: %@", __PRETTY_FUNCTION__, _server);
|
||||
self->appAlias = [[AliasMap alloc] initWithCapacity:8];
|
||||
self->handlerAlias = [[AliasMap alloc] initWithCapacity:8];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithConfig:(AWOServerConfig *)_cfg {
|
||||
if ((self = [self init])) {
|
||||
self->appAlias = [[AliasMap alloc] initWithAliasMap:_cfg->appAlias];
|
||||
self->handlerAlias =
|
||||
[[AliasMap alloc] initWithAliasMap:_cfg->handlerAlias];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)initWithBaseConfig:(AWOServerConfig *)_base
|
||||
andConfig:(AWOServerConfig *)_new
|
||||
{
|
||||
if ((self = [self initWithConfig:_base])) {
|
||||
[self->appAlias addEntriesFromAliasMap:_new->appAlias];
|
||||
[self->handlerAlias addEntriesFromAliasMap:_new->handlerAlias];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
RELEASE(self->appAlias);
|
||||
RELEASE(self->handlerAlias);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
+ (id)mergeBaseConfig:(AWOServerConfig *)_base
|
||||
withNewConfig:(AWOServerConfig *)_new
|
||||
{
|
||||
return [[[self alloc] initWithBaseConfig:_base andConfig:_new] autorelease];
|
||||
}
|
||||
|
||||
- (NSString *)stringValue {
|
||||
return [self description];
|
||||
}
|
||||
- (NSString *)description {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:64];
|
||||
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
|
||||
|
||||
[ms appendFormat:@" appAlias=%@", self->appAlias];
|
||||
|
||||
[ms appendString:@">"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
/* commands */
|
||||
|
||||
- (id)SxApplicationAlias:(NSString *)_name:(NSString *)_uri {
|
||||
NSString *tmp;
|
||||
|
||||
if ((tmp = [self->appAlias uriForKey:_name baseURI:@"/"])) {
|
||||
return [NSString stringWithFormat:@"app %@ already mapped to %@",
|
||||
_name, tmp];
|
||||
}
|
||||
|
||||
//[self logWithFormat:@"aliasing app %@ to %@", _name, _uri];
|
||||
|
||||
[self->appAlias mapKey:_name toURI:_uri];
|
||||
|
||||
return nil /* nil means 'no error' */;
|
||||
}
|
||||
|
||||
- (id)SxHandlerAlias:(NSString *)_handler:(NSString *)_uri {
|
||||
NSString *tmp;
|
||||
|
||||
if ((tmp = [self->handlerAlias uriForKey:_handler baseURI:@"/"])) {
|
||||
return [NSString stringWithFormat:@"handler %@ already mapped to %@",
|
||||
_handler, tmp];
|
||||
}
|
||||
|
||||
//[self logWithFormat:@"aliasing handler %@ to %@", _handler, _uri];
|
||||
|
||||
[self->handlerAlias mapKey:_handler toURI:_uri];
|
||||
|
||||
return nil /* nil means 'no error' */;
|
||||
}
|
||||
|
||||
- (id)LoadBundle:(NSString *)_bundleName {
|
||||
[self logWithFormat:@"should load bundle %@", _bundleName];
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end /* AWOServerConfig */
|
|
@ -0,0 +1,40 @@
|
|||
// $Id: AliasMap.h,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#ifndef __AliasMap_H__
|
||||
#define __AliasMap_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
An alias-map maps some kind of key to a URI. During lookups the
|
||||
URI is processed to find the longest matching prefix.
|
||||
|
||||
Note: a URI may be mapped to only one key, but a key can be mapped
|
||||
to multiple URIs ! (key<->URI is 1:n)
|
||||
*/
|
||||
|
||||
@class NSMutableDictionary, NSMutableArray;
|
||||
|
||||
@interface AliasMap : NSObject < NSCopying >
|
||||
{
|
||||
NSMutableArray *uris;
|
||||
NSMutableDictionary *uri2key;
|
||||
NSMutableDictionary *key2uris;
|
||||
}
|
||||
|
||||
- (id)initWithCapacity:(unsigned)_capacity;
|
||||
- (id)initWithAliasMap:(AliasMap *)_map;
|
||||
|
||||
/* modification */
|
||||
|
||||
- (BOOL)mapKey:(id)_key toURI:(NSString *)_uri;
|
||||
- (BOOL)addEntriesFromAliasMap:(AliasMap *)_map;
|
||||
|
||||
/* query */
|
||||
|
||||
- (id)keyForURI:(NSString *)_uri;
|
||||
- (NSString *)uriForKey:(id)_key baseURI:(NSString *)_uri;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __AliasMap_H__ */
|
|
@ -0,0 +1,139 @@
|
|||
// $Id: AliasMap.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "AliasMap.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation AliasMap
|
||||
|
||||
- (id)initWithCapacity:(unsigned)_capacity {
|
||||
self->uri2key = [[NSMutableDictionary alloc] initWithCapacity:_capacity];
|
||||
self->key2uris = [[NSMutableDictionary alloc] initWithCapacity:_capacity];
|
||||
self->uris = [[NSMutableArray alloc] initWithCapacity:_capacity];
|
||||
return self;
|
||||
}
|
||||
- (id)initWithAliasMap:(AliasMap *)_map {
|
||||
self->uri2key = [_map->uri2key mutableCopy];
|
||||
self->key2uris = [_map->key2uris mutableCopy];
|
||||
self->uris = [_map->uris mutableCopy];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
return [self initWithCapacity:16];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
RELEASE(self->key2uris);
|
||||
RELEASE(self->uri2key);
|
||||
RELEASE(self->uris);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* modification */
|
||||
|
||||
- (BOOL)mapKey:(id)_key toURI:(NSString *)_uri {
|
||||
id tmp;
|
||||
NSMutableArray *kuris;
|
||||
|
||||
if (_uri == nil) return NO;
|
||||
if (_key == nil) return NO;
|
||||
|
||||
if ((tmp = [self->uri2key objectForKey:_uri]))
|
||||
/* already mapped !!! */
|
||||
return NO;
|
||||
|
||||
[self->uri2key setObject:_key forKey:_uri];
|
||||
[self->uris addObject:_uri];
|
||||
|
||||
if ((kuris = [self->key2uris objectForKey:_key]) == nil)
|
||||
kuris = [[NSMutableArray alloc] initWithCapacity:4];
|
||||
else
|
||||
kuris = [kuris mutableCopy];
|
||||
|
||||
[kuris addObject:_uri];
|
||||
|
||||
[self->key2uris setObject:kuris forKey:_key];
|
||||
RELEASE(kuris);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)addEntriesFromAliasMap:(AliasMap *)_map {
|
||||
[self->uri2key addEntriesFromDictionary:_map->uri2key];
|
||||
[self->key2uris addEntriesFromDictionary:_map->key2uris];
|
||||
[self->uris addObjectsFromArray:_map->uris];
|
||||
return YES;
|
||||
}
|
||||
|
||||
/* query */
|
||||
|
||||
- (NSString *)longestMatchingURIForURI:(NSString *)_uri
|
||||
fromArray:(NSArray *)_baseSet
|
||||
{
|
||||
NSEnumerator *e;
|
||||
NSString *auri, *longest = nil;
|
||||
unsigned max = 0, len;
|
||||
|
||||
if ((len = [_uri length]) == 0)
|
||||
return nil;
|
||||
|
||||
/* foreach registered URI */
|
||||
e = [_baseSet objectEnumerator];
|
||||
|
||||
while ((auri = [e nextObject])) {
|
||||
unsigned l = [auri length];
|
||||
|
||||
/* quick precondition: prefix can't be longer than the string .. */
|
||||
if (l > len)
|
||||
continue;
|
||||
|
||||
if ([_uri hasPrefix:auri]) {
|
||||
if (len == l) /* found an exact match */
|
||||
return auri;
|
||||
|
||||
if (l > max) { /* found a new longer uri ... */
|
||||
longest = auri;
|
||||
max = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return longest;
|
||||
}
|
||||
|
||||
- (id)keyForURI:(NSString *)_uri {
|
||||
NSString *aliasURI;
|
||||
|
||||
aliasURI = [self longestMatchingURIForURI:_uri fromArray:self->uris];
|
||||
if ([aliasURI length] == 0)
|
||||
return nil;
|
||||
|
||||
return [self->uri2key objectForKey:aliasURI];
|
||||
}
|
||||
|
||||
- (NSString *)uriForKey:(id)_key baseURI:(NSString *)_uri {
|
||||
NSArray *kuris;
|
||||
NSString *aliasURI;
|
||||
unsigned kcount;
|
||||
|
||||
kuris = [self->key2uris objectForKey:_key];
|
||||
if ((kcount = [kuris count] == 0))
|
||||
return nil;
|
||||
|
||||
if (kcount == 1) /* only one possibility */
|
||||
aliasURI = [kuris objectAtIndex:0];
|
||||
else {
|
||||
aliasURI = [self longestMatchingURIForURI:_uri fromArray:kuris];
|
||||
NSAssert(aliasURI != nil, @"no matching URI in structure ???");
|
||||
}
|
||||
|
||||
return aliasURI;
|
||||
}
|
||||
|
||||
/* copying */
|
||||
|
||||
- (id)copyWithZone:(NSZone *)_zone {
|
||||
return [[AliasMap alloc] initWithAliasMap:self];
|
||||
}
|
||||
|
||||
@end /* AliasMap */
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
DirectoryConfigClass = "AWODirectoryConfig";
|
||||
ServerConfigClass = "AWOServerConfig";
|
||||
|
||||
/* directory config */
|
||||
SetSxApplication = {
|
||||
selector = "SetSxApplication:";
|
||||
overrides = ( ACCESS_CONF, OR_OPTIONS );
|
||||
argspec = "TAKE1";
|
||||
usage = "usage: SetSxApplication <appname>";
|
||||
};
|
||||
SetSxRequestHandler = {
|
||||
selector = "SetSxRequestHandler:";
|
||||
overrides = ( ACCESS_CONF, OR_OPTIONS );
|
||||
argspec = "TAKE1";
|
||||
usage = "usage: SetSxRequestHandler <rqhandlerclass>";
|
||||
};
|
||||
LogText = {
|
||||
selector = "LogText:";
|
||||
overrides = ( ACCESS_CONF, OR_OPTIONS );
|
||||
argspec = "TAKE1";
|
||||
usage = "usage: LogText <sometext>";
|
||||
};
|
||||
|
||||
/* server config */
|
||||
|
||||
LoadBundle = {
|
||||
selector = "LoadBundle:";
|
||||
overrides = ( RSRC_CONF );
|
||||
argspec = "TAKE1";
|
||||
usage = "usage: LoadBundle <bundleName|bundlePath>";
|
||||
};
|
||||
|
||||
SxApplicationAlias = {
|
||||
selector = "SxApplicationAlias::";
|
||||
overrides = ( RSRC_CONF );
|
||||
argspec = "TAKE2";
|
||||
usage = "usage: SxApplicationAlias <appkey> <baseuri>";
|
||||
};
|
||||
SxHandlerAlias = {
|
||||
selector = "SxHandlerAlias::";
|
||||
overrides = ( RSRC_CONF );
|
||||
argspec = "TAKE2";
|
||||
usage = "usage: SxHandlerAlias <handlerkey> <baseuri>";
|
||||
};
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
CVSID="$Id: ApacheHandlers.plist,v 1.1 2004/06/08 11:06:00 helge Exp $";
|
||||
|
||||
/* Note: only lowercase letters are allowed in handler names ! */
|
||||
|
||||
Name2Selector = {
|
||||
"objc-echo" = "performObjcEchoRequest:";
|
||||
"sx-handler" = "performSxHandlerRequest:config:";
|
||||
"wox-page" = "performWoxPageRequest:";
|
||||
"sx-alias-handler" = "performSxAliasHandlerRequest:";
|
||||
};
|
||||
|
||||
MimeType2Selector = {
|
||||
"application/x-httpd-wox" = "performWoxPageRequest:";
|
||||
"application/x-httpd-wo" = "handleApplicationXHttpdWoRequest:config:";
|
||||
"httpd/unix-directory" = "handleDirectoryRequest:config:";
|
||||
"skyrix/request-handler" = "handleSkyrixRqHandler:config:";
|
||||
// "*/*" = "handleGenericRequest:config:";
|
||||
};
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// $Id: ApacheResourceManager.h,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#ifndef __ApacheResourceManager_H__
|
||||
#define __ApacheResourceManager_H__
|
||||
|
||||
#include <NGObjWeb/WOResourceManager.h>
|
||||
|
||||
@class NSMutableDictionary;
|
||||
@class ApacheRequest;
|
||||
@class AWODirectoryConfig;
|
||||
@class WOComponent;
|
||||
|
||||
@interface ApacheResourceManager : WOResourceManager
|
||||
{
|
||||
ApacheRequest *request;
|
||||
AWODirectoryConfig *config;
|
||||
NSMutableDictionary *nameToURL;
|
||||
WOComponent *component; /* non-retained */
|
||||
}
|
||||
|
||||
- (id)initWithApacheRequest:(ApacheRequest *)_rq
|
||||
config:(AWODirectoryConfig *)_cfg;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __ApacheResourceManager_H__ */
|
|
@ -0,0 +1,227 @@
|
|||
// $Id: ApacheResourceManager.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "ApacheResourceManager.h"
|
||||
#include "AWODirectoryConfig.h"
|
||||
#include <ApacheAPI/ApacheRequest.h>
|
||||
#include <ApacheAPI/ApacheServer.h>
|
||||
#include <ApacheAPI/ApacheTable.h>
|
||||
#include <NGObjWeb/WOComponent.h>
|
||||
#include <NGObjWeb/WOApplication.h>
|
||||
#include <NGObjWeb/WOContext.h>
|
||||
#include "common.h"
|
||||
|
||||
@interface NSObject(UsedARPrivates)
|
||||
|
||||
- (void)setComponentClass:(Class)_class;
|
||||
|
||||
- (id)_definitionWithName:(NSString *)_name
|
||||
url:(NSURL *)_url
|
||||
baseURL:(NSURL *)_burl
|
||||
frameworkName:(NSString *)_fwname;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ApacheResourceManager
|
||||
|
||||
static NSMutableDictionary *md = nil;
|
||||
|
||||
- (id)initWithURI:(NSString *)_uri {
|
||||
return self;
|
||||
}
|
||||
+ (id)resourceManagerForURI:(NSString *)_uri {
|
||||
ApacheResourceManager *rm;
|
||||
NSRange r;
|
||||
|
||||
if ([_uri length] > 1) {
|
||||
r = [_uri rangeOfString:@"/" options:NSBackwardsSearch];
|
||||
if (r.length == 0) {
|
||||
NSLog(@"%s: strange uri: %@", __PRETTY_FUNCTION__, _uri);
|
||||
return nil;
|
||||
}
|
||||
|
||||
_uri = [_uri substringToIndex:(r.location + r.length)];
|
||||
}
|
||||
|
||||
if ((rm = [md objectForKey:_uri]))
|
||||
return rm;
|
||||
|
||||
if ((rm = [[ApacheResourceManager alloc] initWithURI:_uri]) == nil)
|
||||
return nil;
|
||||
|
||||
if (md == nil)
|
||||
md = [[NSMutableDictionary alloc] init];
|
||||
[md setObject:rm forKey:_uri];
|
||||
return AUTORELEASE(rm);
|
||||
}
|
||||
|
||||
- (id)initWithApacheRequest:(ApacheRequest *)_rq
|
||||
config:(AWODirectoryConfig *)_cfg
|
||||
{
|
||||
self->request = [_rq retain];
|
||||
self->config = [_cfg retain];
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
RELEASE(self->nameToURL);
|
||||
RELEASE(self->request);
|
||||
RELEASE(self->config);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* URLs */
|
||||
|
||||
- (NSURL *)refererURL {
|
||||
id rurl;
|
||||
|
||||
if ((rurl = [[self->request headersIn] objectForKey:@"Referer"]))
|
||||
rurl = [NSURL URLWithString:rurl];
|
||||
return rurl;
|
||||
}
|
||||
|
||||
- (NSURL *)requestURL {
|
||||
ApacheServer *srv = [self->request server];
|
||||
id rurl;
|
||||
|
||||
rurl = [NSString stringWithFormat:@"http://%@:%i%@",
|
||||
[srv serverHostName],
|
||||
[srv port],
|
||||
[self->request uri]];
|
||||
rurl = [NSURL URLWithString:rurl];
|
||||
return rurl;
|
||||
}
|
||||
|
||||
/* operations */
|
||||
|
||||
- (NSURL *)_templateBaseURLForComponentNamed:(id)_name {
|
||||
ApacheRequest *srq;
|
||||
NSURL *url = nil;
|
||||
|
||||
if (_name == nil || [_name isEqual:[self->request uri]])
|
||||
return [self requestURL];
|
||||
|
||||
if ([_name isKindOfClass:[NSURL class]]) {
|
||||
srq = [self->request subRequestLookupURI:[_name uri]];
|
||||
}
|
||||
else {
|
||||
if ([[_name pathExtension] length] == 0)
|
||||
_name = [_name stringByAppendingPathExtension:@"wox"];
|
||||
|
||||
srq = [self->request subRequestLookupURI:_name];
|
||||
}
|
||||
|
||||
if ([srq doesFileExist]) {
|
||||
url = [[[NSURL alloc] initWithString:[srq uri]
|
||||
relativeToURL:[self requestURL]]
|
||||
autorelease];
|
||||
}
|
||||
else {
|
||||
[self logWithFormat:@"file does not exist: %@ (%@)",
|
||||
[srq filename], [srq fileType]];
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
- (id)definitionForComponent:(id)_name
|
||||
languages:(NSArray *)_languages
|
||||
{
|
||||
id cdef;
|
||||
NSURL *url, *baseURL;
|
||||
|
||||
if ((baseURL = [self->nameToURL objectForKey:_name]) == nil) {
|
||||
//[self logWithFormat:@"def for component: %@)", _name];
|
||||
|
||||
if ((baseURL = [self _templateBaseURLForComponentNamed:_name]) == nil) {
|
||||
[self logWithFormat:@"did not find template URL for component %@",_name];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (self->nameToURL == nil)
|
||||
self->nameToURL = [[NSMutableDictionary alloc] initWithCapacity:16];
|
||||
|
||||
[self->nameToURL setObject:baseURL forKey:_name];
|
||||
}
|
||||
|
||||
/* lookup file for URI */
|
||||
|
||||
if (baseURL == nil)
|
||||
return nil;
|
||||
else if ([baseURL isFileURL]) {
|
||||
[self logWithFormat:@"baseURL(%@) cannot be a file URL !", baseURL];
|
||||
#if DEBUG
|
||||
exit(1);
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
ApacheRequest *srq;
|
||||
NSString *fn;
|
||||
|
||||
fn = [baseURL path];
|
||||
#if DEBUG
|
||||
if ([fn indexOfString:@"INTERNALLY GENERATED"] != NSNotFound) {
|
||||
[self logWithFormat:@"baseURL(%@) broken !", baseURL];
|
||||
exit(2);
|
||||
}
|
||||
#endif
|
||||
|
||||
//[self logWithFormat:@"LOOKUP: %@", fn];
|
||||
srq = [self->request subRequestLookupURI:[baseURL path] method:@"HEAD"];
|
||||
|
||||
fn = [srq filename];
|
||||
//[self logWithFormat:@"File: %@", fn];
|
||||
|
||||
url = [[[NSURL alloc] initFileURLWithPath:fn] autorelease];
|
||||
|
||||
//NSLog(@"mapped:\n base %@\n content %@", baseURL, url);
|
||||
}
|
||||
|
||||
/* create definition */
|
||||
|
||||
cdef = [self _definitionWithName:_name
|
||||
url:url
|
||||
baseURL:baseURL
|
||||
frameworkName:nil];
|
||||
|
||||
[cdef setComponentClass:[WOComponent class]];
|
||||
|
||||
return cdef;
|
||||
}
|
||||
|
||||
- (NSString *)urlForResourceNamed:(NSString *)_name
|
||||
inFramework:(NSString *)_frameworkName
|
||||
languages:(NSArray *)_languages
|
||||
request:(WORequest *)_request
|
||||
{
|
||||
NSURL *compURL, *rURL;
|
||||
|
||||
//[self logWithFormat:@"URL for resource named %@", _name];
|
||||
|
||||
if ((compURL = [self->component baseURL]) == nil) {
|
||||
compURL = [[[[WOApplication application] context] component] baseURL];
|
||||
|
||||
if (compURL) {
|
||||
#if 0
|
||||
[self logWithFormat:@"use current component URL: %@",
|
||||
[compURL absoluteString]];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (compURL == nil) {
|
||||
compURL = [[[WOApplication application] context] baseURL];
|
||||
if (self->component)
|
||||
[self logWithFormat:@"component has no base, using context: %@",
|
||||
[compURL absoluteString]];
|
||||
else
|
||||
[self logWithFormat:@"using component URL as base: %@",
|
||||
[compURL absoluteString]];
|
||||
}
|
||||
|
||||
//[self logWithFormat:@" relative to %@", [compURL absoluteString]];
|
||||
|
||||
rURL = [NSURL URLWithString:_name relativeToURL:compURL];
|
||||
//[self logWithFormat:@" URL: %@", [rURL absoluteString]];
|
||||
|
||||
return [rURL absoluteString];
|
||||
}
|
||||
|
||||
@end /* ApacheResourceManager */
|
|
@ -0,0 +1,61 @@
|
|||
// $Id: ApacheWO+Echo.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "ApacheWO.h"
|
||||
#include "common.h"
|
||||
#include <ApacheAPI/ApacheAPI.h>
|
||||
|
||||
@implementation ApacheWO(EchoHandler)
|
||||
|
||||
- (int)performObjcEchoRequest:(ApacheRequest *)_rq {
|
||||
NSAutoreleasePool *pool;
|
||||
id cfg;
|
||||
NSString *s;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
/* get directory specific info ! */
|
||||
cfg = [self configForDirectory:_rq];
|
||||
|
||||
[self performWoxPageRequest:_rq];
|
||||
|
||||
NSLog(@"CFG: %@", cfg);
|
||||
|
||||
/* setup header */
|
||||
[_rq setContentType:@"text/html"];
|
||||
|
||||
/* send header to client */
|
||||
[_rq sendHttpHeader];
|
||||
|
||||
/* send body to client */
|
||||
[_rq rputs:"<h3>\n"];
|
||||
[_rq rputs:"echo !"];
|
||||
[_rq rputs:"</h3>\n"];
|
||||
|
||||
s = [cfg stringValue];
|
||||
if ([s length] > 0)
|
||||
[_rq rputs:[s cString]];
|
||||
[_rq rputs:"<br />\n\n"];
|
||||
|
||||
[_rq rputs:"<b>URI:</b><pre>"];
|
||||
[_rq rputs:[[_rq uri] cString]];
|
||||
[_rq rputs:"</pre>\n"];
|
||||
|
||||
[_rq rputs:"<b>description:</b><pre>"];
|
||||
[_rq rputs:[[_rq description] cString]];
|
||||
[_rq rputs:"</pre>\n"];
|
||||
|
||||
[_rq rputs:"<b>headers-in:</b><pre>"];
|
||||
[_rq rputs:[[[_rq headersIn] description] cString]];
|
||||
[_rq rputs:"</pre>\n"];
|
||||
|
||||
[_rq rputs:"<b>headers-in-dict:</b><pre>"];
|
||||
[_rq rputs:[[[[_rq headersIn] asDictionary] description] cString]];
|
||||
[_rq rputs:"</pre>\n"];
|
||||
|
||||
RELEASE(pool);
|
||||
|
||||
/* say we are done ... */
|
||||
return ApacheHandledRequest;
|
||||
}
|
||||
|
||||
@end /* ApacheWO(EchoHandler) */
|
|
@ -0,0 +1,65 @@
|
|||
// $Id: ApacheWO+Echo2.m,v 1.1 2004/06/14 15:02:00 helge Exp $
|
||||
|
||||
#include "ApacheWO.h"
|
||||
#include "AWODirectoryConfig.h"
|
||||
#include "ApacheResourceManager.h"
|
||||
#include "WORequest+Apache.h"
|
||||
#include "WOResponse+Apache.h"
|
||||
#include <ApacheAPI/ApacheRequest.h>
|
||||
#include "common.h"
|
||||
|
||||
@implementation ApacheWO(Echo2Handler)
|
||||
|
||||
- (WOResponse *)echoResponseForRequest:(WORequest *)woRequest
|
||||
apacheRequest:(ApacheRequest *)_rq
|
||||
config:(id)cfg
|
||||
{
|
||||
WOResponse *woResponse;
|
||||
|
||||
[self logWithFormat:@"generated response was <nil> .."];
|
||||
woResponse = [[[WOResponse alloc] initWithRequest:woRequest] autorelease];
|
||||
|
||||
/* construct response */
|
||||
|
||||
[woResponse setHeader:@"text/html" forKey:@"content-type"];
|
||||
[woResponse appendContentString:@"<h3>WOResponse Content</h3>"];
|
||||
|
||||
[woResponse appendContentHTMLString:[cfg stringValue]];
|
||||
[woResponse appendContentString:@"<br />\n\n"];
|
||||
|
||||
[woResponse appendContentString:@"<b>URI:</b><pre>"];
|
||||
[woResponse appendContentHTMLString:[woRequest uri]];
|
||||
[woResponse appendContentString:@"</pre>\n"];
|
||||
|
||||
[woResponse appendContentString:@"<b>Description:</b><pre>"];
|
||||
[woResponse appendContentHTMLString:[woRequest description]];
|
||||
[woResponse appendContentString:@"</pre>\n"];
|
||||
|
||||
[woResponse appendContentString:@"<b>Request Headers:</b><pre>"];
|
||||
[woResponse appendContentHTMLString:[[woRequest headers] description]];
|
||||
[woResponse appendContentString:@"</pre>\n"];
|
||||
|
||||
[woResponse appendApacheResponseInfo:
|
||||
[_rq subRequestLookupURI:@"/docs/subdir/test.wox"]];
|
||||
[woResponse appendContentString:@"<br />"];
|
||||
|
||||
[woResponse appendApacheResponseInfo:
|
||||
[_rq subRequestLookupFile:@"test.wox"]];
|
||||
[woResponse appendContentString:@"<br />"];
|
||||
|
||||
[woResponse appendApacheResponseInfo:
|
||||
[_rq subRequestLookupURI:@"/docs/subdir/non_existent.wox"]];
|
||||
[woResponse appendContentString:@"<br />"];
|
||||
|
||||
[woResponse appendApacheResponseInfo:
|
||||
[_rq subRequestLookupURI:@"/docs/subdir/"]];
|
||||
[woResponse appendContentString:@"<br />"];
|
||||
|
||||
[woResponse appendApacheResponseInfo:
|
||||
[_rq subRequestLookupURI:@"/docs/bigimg.gif"]];
|
||||
[woResponse appendContentString:@"<br />"];
|
||||
|
||||
return woResponse;
|
||||
}
|
||||
|
||||
@end /* ApacheWO(Echo2Handler) */
|
|
@ -0,0 +1,83 @@
|
|||
// $Id: ApacheWO+RequestHandler.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "ApacheWO.h"
|
||||
#include "AWODirectoryConfig.h"
|
||||
#include "ApacheResourceManager.h"
|
||||
#include "WORequest+Apache.h"
|
||||
#include "WOResponse+Apache.h"
|
||||
#include "common.h"
|
||||
#include <NGObjWeb/WOApplication.h>
|
||||
#include <NGObjWeb/WORequestHandler.h>
|
||||
#include <ApacheAPI/ApacheAPI.h>
|
||||
|
||||
/*
|
||||
implements a WORequestHandler "dispatcher"
|
||||
|
||||
All WORequestHandler classes are registered in the ApacheHandlers.plist
|
||||
with the single dispatchRequest: selector. This method creates an object
|
||||
of the request handler class and let it dispatch the request.
|
||||
*/
|
||||
|
||||
@implementation ApacheWO(RequestHandler)
|
||||
|
||||
- (int)dispatchRequest:(ApacheRequest *)_rq
|
||||
usingHandlerNamed:(NSString *)_hname
|
||||
inApplication:(WOApplication *)_app
|
||||
{
|
||||
WORequestHandler *handler;
|
||||
WORequest *woRequest;
|
||||
WOResponse *woResponse;
|
||||
int result;
|
||||
|
||||
if ((handler = [_app requestHandlerForKey:_hname]) == nil) {
|
||||
[self logWithFormat:@"did not find request handler for key '%@'",
|
||||
_hname];
|
||||
return ApacheDeclineRequest;
|
||||
}
|
||||
|
||||
woRequest = [[[WORequest alloc] initWithApacheRequest:_rq] autorelease];
|
||||
|
||||
woResponse = [_app dispatchRequest:woRequest usingHandler:handler];
|
||||
|
||||
/* send response */
|
||||
|
||||
if (woResponse)
|
||||
result = [woResponse sendResponseUsingApacheRequest:_rq];
|
||||
else
|
||||
result = 500;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (int)dispatchRequestHandler:(ApacheRequest *)_rq {
|
||||
NSAutoreleasePool *pool;
|
||||
AWODirectoryConfig *cfg;
|
||||
WOApplication *app;
|
||||
int result;
|
||||
|
||||
if (_rq == NULL)
|
||||
return ApacheDeclineRequest;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
/* get directory specific info (app, request-handler) ! */
|
||||
|
||||
cfg = [self configForDirectory:_rq];
|
||||
|
||||
if ((app = [cfg application]) == nil) {
|
||||
[self logWithFormat:@"missing app .."];
|
||||
goto done;
|
||||
}
|
||||
|
||||
result = [self dispatchRequest:_rq
|
||||
usingHandlerNamed:[_rq handler]
|
||||
inApplication:app];
|
||||
|
||||
done:
|
||||
RELEASE(pool);
|
||||
|
||||
/* say we are done ... */
|
||||
return result;
|
||||
}
|
||||
|
||||
@end /* ApacheWO(WoxPageHandler) */
|
|
@ -0,0 +1,76 @@
|
|||
// $Id: ApacheWO+hooks.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "ApacheWO.h"
|
||||
#include "AliasMap.h"
|
||||
#include "AWOServerConfig.h"
|
||||
#include <ApacheAPI/ApacheRequest.h>
|
||||
#include <ApacheAPI/ApacheTable.h>
|
||||
#include "common.h"
|
||||
|
||||
@implementation ApacheWO(Hooks)
|
||||
|
||||
- (int)handleTranslationForRequest:(ApacheRequest *)_rq {
|
||||
AWOServerConfig *cfg;
|
||||
NSString *uri = [_rq uri];
|
||||
NSString *app, *rqh;
|
||||
|
||||
cfg = [self configForServer:_rq];
|
||||
|
||||
//[self logWithFormat:@"translate URI '%@' (cfg=%@) ...", uri, cfg];
|
||||
|
||||
/* check handler aliases */
|
||||
|
||||
if ((rqh = [cfg->handlerAlias keyForURI:uri])) {
|
||||
NSString *prefix;
|
||||
|
||||
prefix = [cfg->handlerAlias uriForKey:rqh baseURI:uri];
|
||||
//[self logWithFormat:@"found handler: %@ (prefix=%@)", rqh, prefix];
|
||||
|
||||
[_rq setFilename:prefix];
|
||||
[_rq setPathInfo:[uri substringFromIndex:[prefix length]]];
|
||||
[_rq setHandler:@"sx-alias-handler"];
|
||||
return ApacheHandledRequest;
|
||||
}
|
||||
|
||||
/* check app aliases */
|
||||
|
||||
if ((app = [cfg->appAlias keyForURI:uri])) {
|
||||
NSString *prefix;
|
||||
|
||||
prefix = [cfg->appAlias uriForKey:app baseURI:uri];
|
||||
[self logWithFormat:@"found app: %@ (prefix=%@)", app, prefix];
|
||||
|
||||
[_rq setFilename:prefix];
|
||||
[_rq setPathInfo:[uri substringFromIndex:[prefix length]]];
|
||||
[_rq setHandler:@"sx-application"];
|
||||
return ApacheHandledRequest;
|
||||
}
|
||||
|
||||
return ApacheDeclineRequest;
|
||||
}
|
||||
|
||||
#if 0
|
||||
- (int)checkUserIdFromRequest:(ApacheRequest *)_req {
|
||||
[self logWithFormat:@"check uid for URI '%@' ...", [_req uri]];
|
||||
return ApacheDeclineRequest;
|
||||
}
|
||||
#endif
|
||||
|
||||
- (int)checkTypeForRequest:(ApacheRequest *)_req {
|
||||
/* do not process .wo directories as simple directories .. */
|
||||
|
||||
//[self logWithFormat:@"check type for URI '%@' ...", [_req uri]];
|
||||
|
||||
if ([_req isDirectory]) {
|
||||
NSString *fext;
|
||||
|
||||
fext = [[[_req filename] lastPathComponent] pathExtension];
|
||||
if ([fext isEqualToString:@"wo"]) {
|
||||
[_req setContentType:@"application/x-httpd-wo"];
|
||||
return ApacheHandledRequest;
|
||||
}
|
||||
}
|
||||
return ApacheDeclineRequest;
|
||||
}
|
||||
|
||||
@end /* ApacheWO(Hooks) */
|
|
@ -0,0 +1,144 @@
|
|||
// $Id: ApacheWO+woxpage.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "ApacheWO.h"
|
||||
#include "AliasMap.h"
|
||||
#include "WORequestHandler+Apache.h"
|
||||
#include "AWODirectoryConfig.h"
|
||||
#include "AWOServerConfig.h"
|
||||
#include "ApacheWOTransaction.h"
|
||||
#include "ApacheResourceManager.h"
|
||||
#include "WORequest+Apache.h"
|
||||
#include "WOResponse+Apache.h"
|
||||
#include "common.h"
|
||||
#include <NGObjWeb/WOApplication.h>
|
||||
#include <NGObjWeb/WORequestHandler.h>
|
||||
#include <ApacheAPI/ApacheAPI.h>
|
||||
|
||||
@interface WORequest(UsedPrivatesApache)
|
||||
- (void)setRequestHandlerPath:(NSString *)_path;
|
||||
- (ApacheRequest *)apacheRequest;
|
||||
@end
|
||||
|
||||
@interface ApacheWO(EchoResponseE)
|
||||
- (WOResponse *)echoResponseForRequest:(WORequest *)woRequest
|
||||
apacheRequest:(ApacheRequest *)_rq
|
||||
config:(id)cfg;
|
||||
@end
|
||||
|
||||
@implementation ApacheWO(WoxPageHandler)
|
||||
|
||||
- (int)performSxApplicationRequest:(ApacheRequest *)_rq {
|
||||
AWOServerConfig *cfg;
|
||||
NSString *uri = [_rq uri];
|
||||
NSString *appKey;
|
||||
WOApplication *app;
|
||||
WORequest *woRequest;
|
||||
WOResponse *woResponse;
|
||||
int result;
|
||||
|
||||
if (uri == nil)
|
||||
return ApacheDeclineRequest;
|
||||
|
||||
woRequest = [[[WORequest alloc] initWithApacheRequest:_rq] autorelease];
|
||||
|
||||
cfg = [self configForServer:_rq];
|
||||
appKey = [cfg->appAlias keyForURI:uri];
|
||||
app = [ApacheWO applicationForKey:appKey className:nil];
|
||||
|
||||
[self logWithFormat:@"performSxApplicationRequest on app %@ ...", app];
|
||||
woResponse = [app dispatchRequest:woRequest];
|
||||
|
||||
/* send response */
|
||||
|
||||
if (woResponse)
|
||||
result = [woResponse sendResponseUsingApacheRequest:_rq];
|
||||
else
|
||||
result = 500;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (int)performSxHandlerRequest:(ApacheRequest *)_rq
|
||||
config:(AWODirectoryConfig *)cfg
|
||||
{
|
||||
WORequestHandler *handler;
|
||||
|
||||
if ((handler = [cfg requestHandler]) == nil) {
|
||||
handler = [[cfg application] defaultRequestHandler];
|
||||
[self logWithFormat:@"using default request handler ..."];
|
||||
}
|
||||
|
||||
return [[self currentWOTransaction] dispatchUsingHandler:handler];
|
||||
}
|
||||
|
||||
- (int)performSxAliasHandlerRequest:(ApacheRequest *)_rq {
|
||||
ApacheWOTransaction *tx;
|
||||
WORequestHandler *handler;
|
||||
NSString *key;
|
||||
|
||||
tx = [self currentWOTransaction];
|
||||
key = [tx->serverConfig->handlerAlias keyForURI:[_rq uri]];
|
||||
handler = [[tx application] requestHandlerForKey:key];
|
||||
|
||||
return [tx dispatchUsingHandler:handler];
|
||||
}
|
||||
|
||||
- (int)performWoxPageRequest:(ApacheRequest *)_rq {
|
||||
WORequestHandler *rh;
|
||||
WORequest *woRq;
|
||||
|
||||
rh = [[[NSClassFromString(@"WOPageRequestHandler") alloc] init] autorelease];
|
||||
if (rh == nil)
|
||||
[self logWithFormat:@"couldn't allocate page request handler .."];
|
||||
|
||||
/* fill request special vars */
|
||||
woRq = [[self currentWOTransaction] request];
|
||||
[woRq setHeader: [woRq uri] forKey:@"x-httpd-pagename"];
|
||||
[woRq setRequestHandlerPath:[[woRq uri] lastPathComponent]];
|
||||
|
||||
return [[self currentWOTransaction] dispatchUsingHandler:rh];
|
||||
}
|
||||
|
||||
- (int)handleApplicationXHttpdWoRequest:(ApacheRequest *)_rq config:_cfg {
|
||||
NSString *uri = [_rq uri];
|
||||
|
||||
[self logWithFormat:@"handleApplicationXHttpdWoxRequest (uri=%@) ...",uri];
|
||||
|
||||
/* remove the slash of .wo directories, deny access to contents .. */
|
||||
if ([uri hasSuffix:@".wo/"]) {
|
||||
uri = [uri substringToIndex:([uri length] - 1)];
|
||||
[self logWithFormat:@"redirect to %@...", uri];
|
||||
|
||||
[[_rq headersOut] setObject:uri forKey:@"location"];
|
||||
[_rq setStatus:302];
|
||||
[_rq sendHttpHeader];
|
||||
return ApacheHandledRequest; /* redirect */
|
||||
}
|
||||
|
||||
return [self performWoxPageRequest:_rq];
|
||||
}
|
||||
|
||||
- (int)handleSkyrixRqHandler:(ApacheRequest *)_rq config:(id)_cfg {
|
||||
NSDictionary *plist;
|
||||
WORequestHandler *rh;
|
||||
|
||||
plist = [NSDictionary dictionaryWithContentsOfFile:[_rq filename]];
|
||||
[self logWithFormat:@"plist: %@", plist];
|
||||
|
||||
if ((rh = [WORequestHandler requestHandlerForConfig:plist]) == nil)
|
||||
return ApacheDeclineRequest;
|
||||
|
||||
return [[self currentWOTransaction] dispatchUsingHandler:rh];
|
||||
}
|
||||
|
||||
- (int)handleDirectoryRequest:(ApacheRequest *)_rq config:(id)_cfg {
|
||||
[self logWithFormat:@"check directory: %@", [_rq filename]];
|
||||
return ApacheDeclineRequest;
|
||||
}
|
||||
- (int)handleGenericRequest:(ApacheRequest *)_rq config:(id)_cfg {
|
||||
[self logWithFormat:@"(generic) check file: %@ (%@)",
|
||||
[_rq filename], [_rq contentType]];
|
||||
return ApacheDeclineRequest;
|
||||
}
|
||||
|
||||
@end /* ApacheWO(WoxPageHandler) */
|
|
@ -0,0 +1,30 @@
|
|||
// $Id: ApacheWO.h,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#ifndef __ApacheWOMod_H__
|
||||
#define __ApacheWOMod_H__
|
||||
|
||||
#include <ApacheAPI/ApacheModule.h>
|
||||
|
||||
@class NSString, NSMutableArray;
|
||||
@class WOApplication;
|
||||
@class ApacheWOTransaction;
|
||||
|
||||
@interface ApacheWO : ApacheModule
|
||||
{
|
||||
NSMutableArray *woTxStack;
|
||||
}
|
||||
|
||||
/* WO transactions */
|
||||
|
||||
- (ApacheWOTransaction *)currentWOTransaction;
|
||||
|
||||
/* application management */
|
||||
|
||||
+ (WOApplication *)applicationForKey:(NSString *)_key
|
||||
className:(NSString *)_className;
|
||||
|
||||
@end
|
||||
|
||||
#include "ApacheWOTransaction.h"
|
||||
|
||||
#endif /* __ApacheWOMod_H__ */
|
|
@ -0,0 +1,115 @@
|
|||
// $Id: ApacheWO.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "ApacheWO.h"
|
||||
#include "common.h"
|
||||
#include <ApacheAPI/ApacheAPI.h>
|
||||
#include <NGObjWeb/WOApplication.h>
|
||||
#include <NGObjWeb/WORequestHandler.h>
|
||||
|
||||
@interface WOApplication(UsedPrivates)
|
||||
- (id)initWithName:(NSString *)_name;
|
||||
@end
|
||||
|
||||
@implementation ApacheWO
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
self->woTxStack = [[NSMutableArray alloc] initWithCapacity:4];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
- (void)dealloc {
|
||||
RELEASE(self->woTxStack);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* transactions */
|
||||
|
||||
- (ApacheWOTransaction *)currentWOTransaction {
|
||||
if ([self->woTxStack count] == 0) return nil;
|
||||
return [self->woTxStack lastObject];
|
||||
}
|
||||
|
||||
- (BOOL)willDispatchRequest:(ApacheRequest *)_rq {
|
||||
/* this is called before a handler is invoked */
|
||||
ApacheWOTransaction *tx;
|
||||
|
||||
if (![super willDispatchRequest:_rq])
|
||||
return NO;
|
||||
|
||||
tx = [[ApacheWOTransaction alloc]
|
||||
initWithApacheRequest:_rq
|
||||
config:[self configForDirectory:_rq]
|
||||
serverConfig:[self configForServer:_rq]];
|
||||
if (tx == nil)
|
||||
return NO;
|
||||
|
||||
//[self logWithFormat:@"pushing WO transaction: %@", tx];
|
||||
|
||||
[self->woTxStack addObject:tx];
|
||||
|
||||
[tx activate];
|
||||
|
||||
RELEASE(tx);
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)didDispatchRequest:(ApacheRequest *)_rq {
|
||||
/* this is called after a handler was invoked */
|
||||
unsigned idx;
|
||||
ApacheWOTransaction *tx;
|
||||
|
||||
if ((idx = [self->woTxStack count]) == 0) {
|
||||
[self logWithFormat:
|
||||
@"tx stack broken, tried to pop tx from empty stack !"];
|
||||
return;
|
||||
}
|
||||
idx--;
|
||||
|
||||
tx = RETAIN([self->woTxStack objectAtIndex:idx]);
|
||||
//[self logWithFormat:@"popping WO transaction: %@.", tx];
|
||||
[tx deactivate];
|
||||
[self->woTxStack removeObjectAtIndex:idx];
|
||||
RELEASE(tx);
|
||||
}
|
||||
|
||||
/* application management */
|
||||
|
||||
+ (WOApplication *)applicationForKey:(NSString *)_key
|
||||
className:(NSString *)_className
|
||||
{
|
||||
static NSMutableDictionary *keyToApp = nil; // THREAD
|
||||
WOApplication *app;
|
||||
Class clazz;
|
||||
|
||||
if (keyToApp == nil)
|
||||
keyToApp = [[NSMutableDictionary alloc] initWithCapacity:16];
|
||||
|
||||
if ((app = [keyToApp objectForKey:_key]))
|
||||
return app;
|
||||
|
||||
if (_className == nil) _className = @"WOApplication";
|
||||
if ((clazz = NSClassFromString(_className)) == nil) {
|
||||
[self logWithFormat:@"did not find class named '%@'", _className];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((app = [[clazz alloc] initWithName:_key]) == nil) {
|
||||
[self logWithFormat:
|
||||
@"couldn't create instance for application of class %@",
|
||||
clazz];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* resource managers are request dependend with our Apache module :-) */
|
||||
[app setResourceManager:nil];
|
||||
|
||||
//[self logWithFormat:@"added application %@ for key %@", app, _key];
|
||||
|
||||
[keyToApp setObject:app forKey:_key];
|
||||
RELEASE(app);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
@end /* ApacheWO */
|
|
@ -0,0 +1,47 @@
|
|||
// $Id: ApacheWOTransaction.h,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#ifndef __ApacheWOTransaction_H__
|
||||
#define __ApacheWOTransaction_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class ApacheRequest;
|
||||
@class WORequest, WOResponse, WOApplication, WORequestHandler;
|
||||
@class AWODirectoryConfig, AWOServerConfig;
|
||||
@class ApacheResourceManager;
|
||||
|
||||
@interface ApacheWOTransaction : NSObject
|
||||
{
|
||||
@public
|
||||
ApacheRequest *request;
|
||||
WORequest *woRequest;
|
||||
WOResponse *woResponse;
|
||||
AWODirectoryConfig *config;
|
||||
AWOServerConfig *serverConfig;
|
||||
WOApplication *application;
|
||||
ApacheResourceManager *resourceManager;
|
||||
}
|
||||
|
||||
- (id)initWithApacheRequest:(ApacheRequest *)_rq
|
||||
config:(AWODirectoryConfig *)_cfg
|
||||
serverConfig:(AWOServerConfig *)_srvcfg;
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (WORequest *)request;
|
||||
- (WOResponse *)response;
|
||||
- (WOApplication *)application;
|
||||
- (ApacheRequest *)apacheRequest;
|
||||
|
||||
/* activation */
|
||||
|
||||
- (void)activate;
|
||||
- (void)deactivate;
|
||||
|
||||
/* dispatch */
|
||||
|
||||
- (int)dispatchUsingHandler:(WORequestHandler *)_handler;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __ApacheWOTransaction_H__ */
|
|
@ -0,0 +1,116 @@
|
|||
// $Id: ApacheWOTransaction.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "ApacheWOTransaction.h"
|
||||
#include "common.h"
|
||||
|
||||
#include "AWODirectoryConfig.h"
|
||||
#include "AWOServerConfig.h"
|
||||
#include "ApacheResourceManager.h"
|
||||
#include "WORequest+Apache.h"
|
||||
#include "WOResponse+Apache.h"
|
||||
#include <ApacheAPI/ApacheRequest.h>
|
||||
#include <NGObjWeb/WORequest.h>
|
||||
#include <NGObjWeb/WOResponse.h>
|
||||
#include <NGObjWeb/WOApplication.h>
|
||||
|
||||
@implementation ApacheWOTransaction
|
||||
|
||||
- (id)initWithApacheRequest:(ApacheRequest *)_rq
|
||||
config:(AWODirectoryConfig *)_cfg
|
||||
serverConfig:(AWOServerConfig *)_srvcfg
|
||||
{
|
||||
if (_rq == nil) {
|
||||
RELEASE(self);
|
||||
return nil;
|
||||
}
|
||||
self->config = RETAIN(_cfg);
|
||||
self->serverConfig = RETAIN(_srvcfg);
|
||||
self->request = RETAIN(_rq);
|
||||
|
||||
if ((self->woRequest = [[WORequest alloc] initWithApacheRequest:_rq])==nil) {
|
||||
NSLog(@"%s: could not create WO request ...", __PRETTY_FUNCTION__);
|
||||
RELEASE(self);
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((self->application = [[_cfg application] retain]) == nil) {
|
||||
NSLog(@"%s: no app is configured ...", __PRETTY_FUNCTION__);
|
||||
RELEASE(self);
|
||||
return nil;
|
||||
}
|
||||
|
||||
self->resourceManager =
|
||||
[[ApacheResourceManager alloc] initWithApacheRequest:_rq config:_cfg];
|
||||
|
||||
if (self->resourceManager == nil) {
|
||||
NSLog(@"%s: could not create resource manager ...", __PRETTY_FUNCTION__);
|
||||
RELEASE(self);
|
||||
return nil;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
RELEASE(self->resourceManager);
|
||||
RELEASE(self->woRequest);
|
||||
RELEASE(self->woResponse);
|
||||
RELEASE(self->application);
|
||||
RELEASE(self->serverConfig);
|
||||
RELEASE(self->config);
|
||||
RELEASE(self->request);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (WOApplication *)application {
|
||||
return [self->config application];
|
||||
}
|
||||
- (WORequest *)request {
|
||||
return self->woRequest;
|
||||
}
|
||||
- (WOResponse *)response {
|
||||
return self->woResponse;
|
||||
}
|
||||
|
||||
- (ApacheRequest *)apacheRequest {
|
||||
return self->request;
|
||||
}
|
||||
|
||||
/* activation */
|
||||
|
||||
- (void)activate {
|
||||
[self->application activateApplication];
|
||||
// should use stack ??
|
||||
[self->application setResourceManager:self->resourceManager];
|
||||
}
|
||||
- (void)deactivate {
|
||||
[self->application setResourceManager:nil];
|
||||
[self->application deactivateApplication];
|
||||
}
|
||||
|
||||
/* dispatch */
|
||||
|
||||
- (int)dispatchUsingHandler:(WORequestHandler *)_handler {
|
||||
WOResponse *response;
|
||||
|
||||
response = [self->application
|
||||
dispatchRequest:self->woRequest
|
||||
usingHandler:_handler];
|
||||
return [response sendResponseUsingApacheRequest:self->request];
|
||||
}
|
||||
|
||||
/* description */
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:64];
|
||||
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
|
||||
[ms appendFormat:@" uri=%@", [[self request] uri]];
|
||||
[ms appendString:@">"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
@end /* ApacheWOTransaction */
|
|
@ -0,0 +1,5 @@
|
|||
2004-06-14 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* created ChangeLog
|
||||
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
# $Id: GNUmakefile,v 1.2 2004/06/14 15:02:00 helge Exp $
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
|
||||
BUNDLE_NAME = ApacheWO
|
||||
|
||||
ApacheWO_PRINCIPAL_CLASS = ApacheWO
|
||||
BUNDLE_EXTENSION = .apache
|
||||
|
||||
# NOTE: Ordering seems to be important !!! (sometimes the ObjC runtime
|
||||
# doesn't find all categories ?!)
|
||||
ApacheWO_OBJC_FILES += \
|
||||
ApacheWO+Echo.m \
|
||||
ApacheWO+woxpage.m \
|
||||
ApacheWO+Echo2.m \
|
||||
ApacheWO+hooks.m \
|
||||
ApacheWO+RequestHandler.m \
|
||||
ApacheWO.m \
|
||||
AWODirectoryConfig.m \
|
||||
AWOServerConfig.m \
|
||||
WORequest+Apache.m \
|
||||
WOResponse+Apache.m \
|
||||
WOComponent+Apache.m \
|
||||
WORequestHandler+Apache.m \
|
||||
ApacheResourceManager.m \
|
||||
AliasMap.m \
|
||||
ApacheWOTransaction.m \
|
||||
|
||||
ApacheWO_BUNDLE_LIBS += \
|
||||
-lApacheAPI \
|
||||
-lNGExtensions \
|
||||
-lNGObjWeb \
|
||||
|
||||
ApacheWO_RESOURCE_FILES = ApacheCommands.plist ApacheHandlers.plist
|
||||
|
||||
# auto info
|
||||
|
||||
ApacheWO_OBJC_FILES += ApacheWO_module_structure.m
|
||||
|
||||
ApacheWO_module_structure.m :
|
||||
$(GNUSTEP_MAKEFILES)/genApacheModule.sh ApacheWO $@
|
||||
|
||||
after-clean ::
|
||||
rm -f ApacheWO_module_structure.m
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/bundle.make
|
|
@ -0,0 +1,17 @@
|
|||
last change:
|
||||
20040608?
|
||||
|
||||
How to start
|
||||
============
|
||||
|
||||
First you need to tweek httpd.conf to reflect you pathes ...
|
||||
Important: you probably need to *install* the bundle before it works,
|
||||
Apache doesn't search for the bundle in the current directory ...
|
||||
|
||||
The easiest way to start it is to invoke:
|
||||
|
||||
# httpd -X -f $PWD/httpd.conf
|
||||
|
||||
The -X option starts Apache in single-process mode (no children are
|
||||
forked) and the -f specifies the local server config file. Note that
|
||||
the server config file needs to be specified as an absolute path.
|
|
@ -0,0 +1,12 @@
|
|||
# $Id: GNUmakefile,v 1.1 2004/06/14 14:59:26 helge Exp $
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
|
||||
BUNDLE_NAME = TestApp
|
||||
|
||||
TestApp_OBJC_FILES = \
|
||||
TestApp.m \
|
||||
|
||||
TestApp_RESOURCE_FILES = \
|
||||
|
||||
include $(GNUSTEP_MAKEFILES)/bundle.make
|
|
@ -0,0 +1,9 @@
|
|||
// $Id: TestApp.m,v 1.1 2004/06/14 14:59:26 helge Exp $
|
||||
|
||||
#include <NGObjWeb/WOApplication.h>
|
||||
|
||||
@interface TestApp : WOApplication
|
||||
@end
|
||||
|
||||
@implementation TestApp
|
||||
@end
|
|
@ -0,0 +1,35 @@
|
|||
// $Id: WOComponent+Apache.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include <NGObjWeb/WOComponent.h>
|
||||
#include <NGObjWeb/WOContext.h>
|
||||
#include <NGObjWeb/WORequest.h>
|
||||
#include <ApacheAPI/ApacheRequest.h>
|
||||
#include "common.h"
|
||||
|
||||
@interface WOContext(Apache)
|
||||
- (ApacheRequest *)apacheRequest;
|
||||
@end
|
||||
|
||||
@implementation WOContext(Apache)
|
||||
|
||||
- (ApacheRequest *)apacheRequest {
|
||||
return [[[self request] userInfo] objectForKey:@"ApacheRequest"];
|
||||
}
|
||||
|
||||
- (id)_jsprop_apacheRequest {
|
||||
return [self apacheRequest];
|
||||
}
|
||||
|
||||
@end /* WOContext(Apache) */
|
||||
|
||||
@implementation WOComponent(Apache)
|
||||
|
||||
- (ApacheRequest *)apacheRequest {
|
||||
return [[self context] apacheRequest];
|
||||
}
|
||||
|
||||
- (id)_jsprop_apacheRequest {
|
||||
return [self apacheRequest];
|
||||
}
|
||||
|
||||
@end /* WOComponent(Apache) */
|
|
@ -0,0 +1,16 @@
|
|||
// $Id: WORequest+Apache.h,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#ifndef __WORequest_Apache_H__
|
||||
#define __WORequest_Apache_H__
|
||||
|
||||
#include <NGObjWeb/WORequest.h>
|
||||
|
||||
@class ApacheRequest;
|
||||
|
||||
@interface WORequest(Apache)
|
||||
|
||||
- (id)initWithApacheRequest:(ApacheRequest *)_rq;
|
||||
|
||||
@end /* WORequest(Apache) */
|
||||
|
||||
#endif /* __WORequest_Apache_H__ */
|
|
@ -0,0 +1,117 @@
|
|||
// $Id: WORequest+Apache.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "WORequest+Apache.h"
|
||||
#include <ApacheAPI/ApacheRequest.h>
|
||||
#include <ApacheAPI/ApacheTable.h>
|
||||
#include <ApacheAPI/ApacheConnection.h>
|
||||
#include "common.h"
|
||||
|
||||
@interface WORequest(ApachePrivates)
|
||||
|
||||
- (NSData *)readDataFromApacheRequest:(ApacheRequest *)_rq;
|
||||
|
||||
@end
|
||||
|
||||
@implementation WORequest(Apache)
|
||||
|
||||
- (id)initWithApacheRequest:(ApacheRequest *)_rq {
|
||||
NSMutableDictionary *headers;
|
||||
NSAutoreleasePool *pool;
|
||||
NSString *httpVersion = nil;
|
||||
NSData *contentData;
|
||||
NSDictionary *ui;
|
||||
NGHashMap *form;
|
||||
|
||||
if (_rq == nil) {
|
||||
RELEASE(self);
|
||||
return nil;
|
||||
}
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
headers = [[NSMutableDictionary alloc] initWithCapacity:32];
|
||||
|
||||
/* the values need to be parsed ! */
|
||||
{
|
||||
ApacheTable *hin;
|
||||
NSEnumerator *keys;
|
||||
NSString *key;
|
||||
|
||||
hin = [_rq headersIn];
|
||||
keys = [hin keyEnumerator];
|
||||
while ((key = [keys nextObject])) {
|
||||
NSString *value;
|
||||
|
||||
if ((value = [hin objectForKey:key]) == nil) {
|
||||
[self logWithFormat:@"got no value for key '%@' ..", key];
|
||||
continue;
|
||||
}
|
||||
|
||||
/* NGObjWeb expects all keys to be lowercase .. */
|
||||
key = [key lowercaseString];
|
||||
[headers setObject:value forKey:key];
|
||||
}
|
||||
}
|
||||
|
||||
/* setup "special" headers */
|
||||
{
|
||||
ApacheConnection *con = [_rq connection];
|
||||
NSString *tmp;
|
||||
|
||||
if ((tmp = [headers objectForKey:@"host"])) {
|
||||
tmp = [@"http://" stringByAppendingString:tmp];
|
||||
[headers setObject:tmp forKey:@"x-webobjects-server-url"];
|
||||
}
|
||||
if ([(tmp = [con remoteHost]) length] > 0)
|
||||
[headers setObject:tmp forKey:@"x-webobjects-remote-host"];
|
||||
if ([(tmp = [con user]) length] > 0)
|
||||
[headers setObject:tmp forKey:@"x-webobjects-remote-user"];
|
||||
if ([(tmp = [con authorizationType]) length] > 0)
|
||||
[headers setObject:tmp forKey:@"x-webobjects-auth-type"];
|
||||
}
|
||||
|
||||
/* content, this is to be done ... (libapr ?, hm) */
|
||||
contentData = [self readDataFromApacheRequest:_rq];
|
||||
|
||||
/* userinfo */
|
||||
|
||||
ui = [NSDictionary dictionaryWithObject:_rq forKey:@"ApacheRequest"];
|
||||
|
||||
/* form values */
|
||||
|
||||
{
|
||||
const char *cstr = [[_rq unparsedURI] cString];
|
||||
const char *pos = index(cstr, '?');
|
||||
|
||||
if (pos) {
|
||||
pos++;
|
||||
form = NGDecodeUrlFormParameters(pos, strlen(pos));
|
||||
}
|
||||
else
|
||||
form = nil;
|
||||
}
|
||||
|
||||
/* construct */
|
||||
|
||||
self = [self initWithMethod:[_rq method]
|
||||
uri:[_rq uri]
|
||||
httpVersion:httpVersion
|
||||
headers:headers
|
||||
content:contentData
|
||||
userInfo:ui];
|
||||
ASSIGN(self->formContent, form);
|
||||
|
||||
RELEASE(headers);
|
||||
RELEASE(pool);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSData *)readDataFromApacheRequest:(ApacheRequest *)_rq {
|
||||
#warning read request content if available ...
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (ApacheRequest *)apacheRequest {
|
||||
return [[self userInfo] objectForKey:@"ApacheRequest"];
|
||||
}
|
||||
|
||||
@end /* WORequest(Apache) */
|
|
@ -0,0 +1,17 @@
|
|||
// $Id: WORequestHandler+Apache.h,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#ifndef __WORequestHandler_ApacheExt_H__
|
||||
#define __WORequestHandler_ApacheExt_H__
|
||||
|
||||
#include <NGObjWeb/WORequestHandler.h>
|
||||
|
||||
@class NSDictionary;
|
||||
|
||||
@interface WORequestHandler(ApacheExt)
|
||||
|
||||
+ (WORequestHandler *)requestHandlerForConfig:(NSDictionary *)_plist;
|
||||
- (id)initWithConfig:(NSDictionary *)_cfg;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __WORequestHandler_ApacheExt_H__ */
|
|
@ -0,0 +1,28 @@
|
|||
// $Id: WORequestHandler+Apache.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "WORequestHandler+Apache.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation WORequestHandler(ApacheExt)
|
||||
|
||||
- (id)initWithConfig:(NSDictionary *)_cfg {
|
||||
return [self init];
|
||||
}
|
||||
|
||||
+ (WORequestHandler *)requestHandlerForConfig:(NSDictionary *)_plist {
|
||||
NSString *className;
|
||||
Class clazz;
|
||||
|
||||
className = [_plist objectForKey:@"class"];
|
||||
if ([className length] == 0)
|
||||
return nil;
|
||||
|
||||
if ((clazz = NSClassFromString(className)) == Nil) {
|
||||
[self logWithFormat:@"did not find request handler class %@", className];
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [[[clazz alloc] initWithConfig:_plist] autorelease];
|
||||
}
|
||||
|
||||
@end /* WORequestHandler(ApacheExt) */
|
|
@ -0,0 +1,20 @@
|
|||
// $Id: WOResponse+Apache.h,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#ifndef __WOResponse_Apache_H__
|
||||
#define __WOResponse_Apache_H__
|
||||
|
||||
#include <NGObjWeb/WOResponse.h>
|
||||
|
||||
@class ApacheRequest;
|
||||
|
||||
@interface WOResponse(Apache)
|
||||
|
||||
- (int)sendResponseUsingApacheRequest:(ApacheRequest *)_rq;
|
||||
|
||||
@end /* WOResponse(Apache) */
|
||||
|
||||
@interface WOResponse(ApacheInfo)
|
||||
- (void)appendApacheResponseInfo:(ApacheRequest *)_request;
|
||||
@end
|
||||
|
||||
#endif /* __WOResponse_Apache_H__ */
|
|
@ -0,0 +1,146 @@
|
|||
// $Id: WOResponse+Apache.m,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#include "WOResponse+Apache.h"
|
||||
#include <ApacheAPI/ApacheRequest.h>
|
||||
#include <ApacheAPI/ApacheModule.h>
|
||||
#include <ApacheAPI/ApacheTable.h>
|
||||
#include "common.h"
|
||||
|
||||
@implementation WOResponse(Apache)
|
||||
|
||||
- (BOOL)applyHeadersOnApacheRequest:(ApacheRequest *)_rq {
|
||||
static NSMutableSet *ignoredHeaders = nil;
|
||||
ApacheTable *apHeaders;
|
||||
NSString *ctype;
|
||||
NSEnumerator *keys;
|
||||
NSString *key;
|
||||
|
||||
if (_rq == nil)
|
||||
return NO;
|
||||
|
||||
if (ignoredHeaders == nil) {
|
||||
ignoredHeaders = [[NSMutableSet alloc] initWithObjects:
|
||||
@"content-type",
|
||||
nil];
|
||||
}
|
||||
|
||||
if ((ctype = [self headerForKey:@"content-type"]))
|
||||
[_rq setContentType:ctype];
|
||||
|
||||
/* apply all headers ... */
|
||||
|
||||
apHeaders = [_rq headersOut];
|
||||
|
||||
keys = [[self headerKeys] objectEnumerator];
|
||||
while ((key = [keys nextObject])) {
|
||||
NSString *svalue;
|
||||
|
||||
if ([ignoredHeaders containsObject:key])
|
||||
continue;
|
||||
|
||||
svalue = [[self headersForKey:key] componentsJoinedByString:@", "];
|
||||
[apHeaders setObject:svalue forKey:key];
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (int)sendContentUsingApacheRequest:(ApacheRequest *)_rq {
|
||||
return [_rq rwriteData:[self content]];
|
||||
}
|
||||
|
||||
- (int)sendResponseUsingApacheRequest:(ApacheRequest *)_rq {
|
||||
NSAutoreleasePool *pool;
|
||||
int result;
|
||||
|
||||
result = [self status];
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
[_rq setStatus:[self status]];
|
||||
|
||||
if (![self applyHeadersOnApacheRequest:_rq])
|
||||
result = 500;
|
||||
else {
|
||||
#if DONT_SEND_CONTENT_IN_SUBREQUESTS
|
||||
if ([_rq mainRequest]) {
|
||||
[self logWithFormat:@"is subrequest (no content is send) ..."];
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
[_rq sendHttpHeader];
|
||||
|
||||
if (![_rq isHeadRequest])
|
||||
result = [self sendContentUsingApacheRequest:_rq];
|
||||
#if DONT_SEND_CONTENT_IN_SUBREQUESTS
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
RELEASE(pool);
|
||||
return ApacheHandledRequest;
|
||||
}
|
||||
|
||||
@end /* WOResponse(Apache) */
|
||||
|
||||
@implementation WOResponse(ApacheAppend)
|
||||
|
||||
- (void)appendApacheResponseInfo:(ApacheRequest *)_request {
|
||||
[self appendContentString:@"<table border='1' width=\"100%\">"];
|
||||
|
||||
#if 0
|
||||
[self appendContentString:
|
||||
@"<tr><td valign='top' align='right'>Description:</td><td><pre>"];
|
||||
[self appendContentHTMLString:[_request description]];
|
||||
[self appendContentString:@"</pre></td></tr>"];
|
||||
#endif
|
||||
|
||||
[self appendContentString:
|
||||
@"<tr><td width='25%' valign='top' align='right'>Status:</td><td>"];
|
||||
[self appendContentHTMLString:[NSString stringWithFormat:@"%i",[_request status]]];
|
||||
[self appendContentString:@"</td></tr>"];
|
||||
|
||||
[self appendContentString:
|
||||
@"<tr><td width='25%' valign='top' align='right'>unparsed URI:</td><td>"];
|
||||
[self appendContentHTMLString:[_request unparsedURI]];
|
||||
[self appendContentString:@"</td></tr>"];
|
||||
|
||||
[self appendContentString:
|
||||
@"<tr><td valign='top' align='right'>URI:</td><td>"];
|
||||
[self appendContentHTMLString:[_request uri]];
|
||||
[self appendContentString:@"</td></tr>"];
|
||||
|
||||
[self appendContentString:
|
||||
@"<tr><td valign='top' align='right'>filename:</td><td>"];
|
||||
[self appendContentHTMLString:[_request filename]];
|
||||
[self appendContentString:@"</td></tr>"];
|
||||
|
||||
[self appendContentString:
|
||||
@"<tr><td valign='top' align='right'>filetype:</td><td>"];
|
||||
[self appendContentHTMLString:[_request fileType]];
|
||||
[self appendContentString:@"</td></tr>"];
|
||||
|
||||
[self appendContentString:
|
||||
@"<tr><td valign='top' align='right'>content-type:</td><td>"];
|
||||
[self appendContentHTMLString:[_request contentType]];
|
||||
[self appendContentString:@"</td></tr>"];
|
||||
|
||||
[self appendContentString:
|
||||
@"<tr><td valign='top' align='right'>queryargs:</td><td>"];
|
||||
[self appendContentHTMLString:[_request queryArgs]];
|
||||
[self appendContentString:@"</td></tr>"];
|
||||
|
||||
[self appendContentString:
|
||||
@"<tr><td valign='top' align='right'>pathinfo:</td><td>"];
|
||||
[self appendContentHTMLString:[_request pathInfo]];
|
||||
[self appendContentString:@"</td></tr>"];
|
||||
|
||||
[self appendContentString:
|
||||
@"<tr><td valign='top' align='right'>Headers:</td><td><pre>"];
|
||||
[self appendContentHTMLString:
|
||||
[[[_request headersOut] asDictionary] description]];
|
||||
[self appendContentString:@"</pre></td></tr>"];
|
||||
|
||||
[self appendContentString:@"</table>"];
|
||||
}
|
||||
|
||||
@end /* WOResponse(ApacheAppend) */
|
|
@ -0,0 +1,4 @@
|
|||
// $Id: common.h,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#include <NGExtensions/NGExtensions.h>
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<span xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:const="http://www.skyrix.com/od/constant">
|
||||
I'm a reusable component.
|
||||
</span>
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0"?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:const="http://www.skyrix.com/od/constant">
|
||||
<head>
|
||||
<title>Page: <var:string value="context.page.name"/></title>
|
||||
</head>
|
||||
<body bgcolor="#BBBBBB">
|
||||
<b><var:string value="context.page.name"/></b>
|
||||
<hr/>
|
||||
|
||||
<var:component-content/>
|
||||
|
||||
<hr/>
|
||||
|
||||
<a href=".">docs</a> |
|
||||
<a href="test.wox">test</a> |
|
||||
<a href="requests.wox">requests</a> |
|
||||
<a href="Page2.wox">Page2</a> |
|
||||
<a href="Page3.wox">Page3</a> |
|
||||
<a href="WoPage1.wo">WoPage1</a>
|
||||
</body>
|
||||
|
||||
<var:script><![CDATA[
|
||||
var title = "<no title>";
|
||||
]]></var:script>
|
||||
</html>
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0"?>
|
||||
<var:component className="Frame" title="name"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:const="http://www.skyrix.com/od/constant">
|
||||
Seite 2 ...
|
||||
|
||||
Zur Index-Seite: <a href="/docs/">/docs</a><br/>
|
||||
Zu test.wox: <a href="test.wox">test.wox</a><br/>
|
||||
<br/>
|
||||
Embed: |<var:component className="Embed"/>|
|
||||
<br/>
|
||||
<br/>
|
||||
<img src="SlowMarket.gif" alt="bigimg.gif"/>
|
||||
<hr/>
|
||||
<img filename="SlowMarket.gif" alt="bigimg.gif"/>
|
||||
<hr/>
|
||||
<var:component className="imgs/SlowMarket.wox"/>
|
||||
</var:component>
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version='1.0' standalone='yes'?>
|
||||
<var:component className="Frame" title="name"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:js="http://www.skyrix.com/od/javascript"
|
||||
xmlns:const="http://www.skyrix.com/od/constant">
|
||||
|
||||
<form href="Page3.wox/add" method="post">
|
||||
<input type="text" name="a" var:value="a"/><br/>
|
||||
<input type="text" name="b" var:value="b"/><br/>
|
||||
<input type="submit" name="ok" value="ok"/><br/>
|
||||
<var:string value="c"/>
|
||||
</form>
|
||||
|
||||
<var:script><![CDATA[
|
||||
var a = 3;
|
||||
var b = 10;
|
||||
var c = 0;
|
||||
|
||||
function addAction() {
|
||||
c = a + b;
|
||||
return this;
|
||||
}
|
||||
function calcC() {
|
||||
return a + b;
|
||||
}
|
||||
]]></var:script>
|
||||
|
||||
a: <var:string value="a"/><br/>
|
||||
b: <var:string value="b"/><br/>
|
||||
c: <var:string value="calcC"/><br/>
|
||||
</var:component>
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0"?>
|
||||
<span xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:js="http://www.skyrix.com/od/javascript"
|
||||
xmlns:const="http://www.skyrix.com/od/constant">
|
||||
|
||||
<table style="font-size: 10">
|
||||
<tr>
|
||||
<td colspan="6" bgcolor="#CCCCCC">
|
||||
Info on <var:string value="rq.uri"/></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign="top" width="20%">filename</td>
|
||||
<td colspan="5">
|
||||
<var:string value="rq.filename"/>
|
||||
(<var:string value="rq.fileType"/>)
|
||||
<var:if js:condition="rq.pathInfo.length > 0">
|
||||
[<var:string value="rq.pathInfo"/>]
|
||||
</var:if>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">method</td>
|
||||
<td><var:string value="rq.method"/></td>
|
||||
<td valign="top">status</td>
|
||||
<td><var:string value="rq.status"/></td>
|
||||
<td valign="top">content-type</td>
|
||||
<td><var:string value="rq.contentType"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">headers-in</td>
|
||||
<td colspan="5">
|
||||
<table border="0" style="font-size: 8">
|
||||
<var:foreach-key dictionary="rq.headersIn" key="header" item="value">
|
||||
<tr>
|
||||
<td valign="top"><var:string value="header"/></td>
|
||||
<td><var:foreach const:count="3" js:list="value.split(',')" item="valuePart"><var:string value="valuePart"/><br/></var:foreach></td>
|
||||
</tr>
|
||||
</var:foreach-key>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!--
|
||||
<tr>
|
||||
<td valign="top">headers-out</td>
|
||||
<td colspan="3">
|
||||
<var:foreach-key dictionary="rq.headersOut" key="header" item="value">
|
||||
<li><var:string value="header"/>: <var:string value="value"/></li>
|
||||
</var:foreach-key></td>
|
||||
</tr>
|
||||
-->
|
||||
</table>
|
||||
|
||||
<var:script>
|
||||
var rq, value;
|
||||
var value="";
|
||||
</var:script>
|
||||
</span>
|
|
@ -0,0 +1,17 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Server Side Include</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h3>Server Side Include</h3>
|
||||
|
||||
Today is <!--#echo var="DATE_LOCAL" -->
|
||||
<br/>
|
||||
<br/>
|
||||
Inluded .wox page:
|
||||
<table border="1" width="100%"><tr><td>
|
||||
<!--#include virtual="Page2.wox" -->
|
||||
</td></tr></table>
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,42 @@
|
|||
<?xml version='1.0' standalone='yes'?>
|
||||
<var:component className="Frame" title="name"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:const="http://www.skyrix.com/od/constant">
|
||||
|
||||
<var:table maxColumns="maxColumns" col="col" row="row"
|
||||
index="index" item="item"
|
||||
list="listAsArray" horizontal="horizontal"
|
||||
border="border">
|
||||
(<var:string value="row"/>/<var:string value="col"/>)
|
||||
= <var:string value="index"/>
|
||||
<b><var:string value="item"/></b>
|
||||
</var:table>
|
||||
|
||||
<var:table maxColumns="maxColumns" col="col" row="row"
|
||||
index="index" item="item"
|
||||
list="listAsArray" horizontal="horizontal"
|
||||
border="border"
|
||||
const:hasOwnTDs="4" width="100%">
|
||||
<td><var:string value="row"/></td>
|
||||
<td><var:string value="col"/></td>
|
||||
<td><var:string value="index"/></td>
|
||||
<td><b><var:string value="item"/></b></td>
|
||||
</var:table>
|
||||
|
||||
<form var:action="self">
|
||||
<hr/>
|
||||
<table border="0">
|
||||
<tr><td><i>Config Bindings</i></td></tr>
|
||||
<tr>
|
||||
<td>MaxColumns:</td>
|
||||
<td><input type="text" var:value="maxColumns" size="4"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Horizontal:</td>
|
||||
<td><input type="checkbox" var:checked="horizontal"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
<input type="submit" var:action="self" value="apply"/>
|
||||
</form>
|
||||
</var:component>
|
|
@ -0,0 +1,9 @@
|
|||
<WEBOBJECT NAME="Frame">
|
||||
.wo based page
|
||||
|
||||
a: <WEBOBJECT NAME="a"></WEBOBJECT><br />
|
||||
b: <WEBOBJECT NAME="b"></WEBOBJECT><br />
|
||||
c: <WEBOBJECT NAME="AddAB"></WEBOBJECT><br />
|
||||
|
||||
Action Link to Page2: <WEBOBJECT NAME="Page2">Page2</WEBOBJECT>
|
||||
</WEBOBJECT>
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
print("setup WoPage1 ...");
|
||||
|
||||
var a = 3;
|
||||
var b = 5;
|
||||
var c = 0;
|
||||
var txt = "Hello World !"
|
||||
|
||||
function addAB() {
|
||||
c = a + b;
|
||||
return c;
|
||||
}
|
||||
|
||||
function gotoPage2() {
|
||||
print("goto page 2 ...");
|
||||
var page = pageWithName("Page2");
|
||||
print(" page: " + page);
|
||||
return page;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
Frame: Frame {
|
||||
title = name;
|
||||
}
|
||||
|
||||
AddAB: WOString {
|
||||
value = addAB;
|
||||
}
|
||||
|
||||
a: WOString {
|
||||
value = a;
|
||||
}
|
||||
b: WOString {
|
||||
value = b;
|
||||
}
|
||||
|
||||
Page2: WOHyperlink {
|
||||
action = gotoPage2;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<span xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:const="http://www.skyrix.com/od/constant">
|
||||
<img width="220" height="65" filename="../SlowMarket.gif" alt="bigimg.gif"/>
|
||||
</span>
|
|
@ -0,0 +1,25 @@
|
|||
# $Id: .htaccess,v 1.1 2004/06/14 14:59:38 helge Exp $
|
||||
|
||||
Options FollowSymLinks Indexes Includes
|
||||
|
||||
AddIcon /icons/image2.gif .gif
|
||||
AddIcon /icons/image1.gif .wox
|
||||
AddIcon /icons/dir.gif ^^DIRECTORY^^
|
||||
|
||||
AddDescription "SKYRiX XML template" .wox
|
||||
AddDescription "SKYRiX WO template" .wo
|
||||
AddDescription "GIF Image" .gif
|
||||
AddDescription "Server Side Include" .shtml
|
||||
AddDescription "SKYRiX Request Handler" .rqh
|
||||
|
||||
FancyIndexing on
|
||||
IndexOptions FoldersFirst
|
||||
|
||||
#IconHeight 16
|
||||
#IconWidth 16
|
||||
|
||||
SetSxApplication app1
|
||||
|
||||
AddType text/html .shtml
|
||||
AddHandler server-parsed .shtml
|
||||
AddType skyrix/request-handler .rqh
|
|
@ -0,0 +1,84 @@
|
|||
<?xml version="1.0"?>
|
||||
<var:component className="Frame" title="name"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:js="http://www.skyrix.com/od/javascript"
|
||||
xmlns:const="http://www.skyrix.com/od/constant">
|
||||
<h3>Check Apache Internal Subrequests ..</h3>
|
||||
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td valign="top">Filename: </td>
|
||||
<td><var:string value="apacheRequest.filename"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">Pathinfo: </td>
|
||||
<td><var:string value="apacheRequest.pathInfo"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">ApacheRequest:</td>
|
||||
<td><code><var:string value="apacheRequest"/></code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">ApacheConnection:</td>
|
||||
<td><code><var:string value="apacheRequest.connection"/></code></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td valign="top">test.wox:</td>
|
||||
<td><var:component className="RqInfo" rq="testRq"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">test.wox (file):</td>
|
||||
<td><var:component className="RqInfo" rq="testRqFile"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">test.wox/add:</td>
|
||||
<td><var:component className="RqInfo" rq="testRqAdd"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">WoPage1.wo:</td>
|
||||
<td><var:component className="RqInfo" rq="testWO"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">blah.wo/:</td>
|
||||
<td><var:component className="RqInfo" rq="testNo"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">SSIPage.shtml:</td>
|
||||
<td><var:component className="RqInfo" rq="testSSI"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">/docs/:</td>
|
||||
<td><var:component className="RqInfo" rq="docs"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top">/docs/manage:</td>
|
||||
<td>
|
||||
<i>Note:</i> pathInfo doesn't work on directories :-(<br/>
|
||||
<var:component className="RqInfo" rq="docsMg"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<var:script><![CDATA[
|
||||
var rq = this.apacheRequest;
|
||||
|
||||
print("run requests setup ...");
|
||||
var testRq = rq.subRequestLookupURI('test.wox', 'HEAD');
|
||||
var testRqAdd = rq.subRequestLookupURI('test.wox/add', 'HEAD');
|
||||
var testRqFile = rq.subRequestLookupFile('test.wox');
|
||||
var testWO = rq.subRequestLookupURI('WoPage1.wo', 'HEAD');
|
||||
var testNo = rq.subRequestLookupURI('blah.wo/', 'HEAD');
|
||||
var testSSI = rq.subRequestLookupURI('SSIPage.shtml','HEAD');
|
||||
var docs = rq.subRequestLookupURI('/docs/', 'HEAD');
|
||||
var docsMg = rq.subRequestLookupURI('/docs/manage', 'HEAD');
|
||||
|
||||
if (0) {
|
||||
print("run test.wox as subreq ...");
|
||||
var res = testRq.runSubRequest();
|
||||
print(" result: " + res);
|
||||
}
|
||||
]]></var:script>
|
||||
|
||||
</var:component>
|
|
@ -0,0 +1,3 @@
|
|||
# $Id: .htaccess,v 1.1 2004/06/14 14:59:48 helge Exp $
|
||||
|
||||
LogText "configured in docs/subdir/.htaccess"
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0"?>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<body bgcolor="red">
|
||||
|
||||
in subdir ...
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>My HTML Page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>My HTML Page</h1>
|
||||
|
||||
|
||||
|
||||
<hr>
|
||||
<address><a href="mailto:helge.hess@skyrix.com">Helge Hess</a></address>
|
||||
<!-- Created: Mon Jun 17 21:10:15 CEST 2002 -->
|
||||
<!-- hhmts start -->
|
||||
Last modified: Mon Jun 17 21:10:16 CEST 2002
|
||||
<!-- hhmts end -->
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0"?>
|
||||
<var:component className="Frame" title="name"
|
||||
xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:var="http://www.skyrix.com/od/binding"
|
||||
xmlns:js="http://www.skyrix.com/od/javascript"
|
||||
xmlns:const="http://www.skyrix.com/od/constant">
|
||||
<h3>Apache served .wox page</h3>
|
||||
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td>ComponentName: </td>
|
||||
<td><var:string value="name"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Filename: </td>
|
||||
<td><var:string value="context.request.userInfo.ApacheRequest.filename"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pathinfo: </td>
|
||||
<td><var:string value="context.request.userInfo.ApacheRequest.pathInfo"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Context:</td>
|
||||
<td><var:string value="context"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Request:</td>
|
||||
<td><var:string value="context.request"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>FormValues Keys:</td>
|
||||
<td><var:string value="context.request.formValueKeys"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ApacheRequest:</td>
|
||||
<td><var:string value="context.request.userInfo.ApacheRequest"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ApacheConnection:</td>
|
||||
<td><var:string value="context.request.userInfo.ApacheRequest.connection"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- var:script>print('init test');</var:script -->
|
||||
|
||||
</var:component>
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
class = "WODirectActionRequestHandler";
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
class = "XmlRpcRequestHandler";
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
# $Id: httpd.conf,v 1.1 2004/06/08 11:06:00 helge Exp $
|
||||
|
||||
# globals
|
||||
ServerType standalone
|
||||
ServerRoot "/HOME/helge/mdev/SkyrixRoot"
|
||||
PidFile /HOME/helge/mdev/SkyrixRoot/logs/httpd8090.pid
|
||||
ScoreBoardFile /HOME/helge/mdev/SkyrixRoot/logs/httpd8090.scoreboard
|
||||
DocumentRoot "/HOME/helge/mdev/SkyrixRoot/Library/WebServer/Documents"
|
||||
ErrorLog /HOME/helge/mdev/SkyrixRoot/logs/error8090_log
|
||||
AccessFileName .htaccess
|
||||
Timeout 300
|
||||
KeepAlive On
|
||||
MaxKeepAliveRequests 100
|
||||
KeepAliveTimeout 15
|
||||
MinSpareServers 1
|
||||
MaxSpareServers 1
|
||||
StartServers 1
|
||||
MaxClients 150
|
||||
MaxRequestsPerChild 0
|
||||
ExtendedStatus On
|
||||
Port 8090
|
||||
User helge
|
||||
Group dev
|
||||
ServerAdmin helge.hess@skyrix.com
|
||||
HostnameLookups Off
|
||||
ServerSignature On
|
||||
|
||||
# load Objective-C bundle loader ...
|
||||
|
||||
LoadModule gsbundle_module \
|
||||
Libraries/ix86/linux-gnu/apache/mod_gsbundle.so
|
||||
#AddModule mod_gsbundle.c
|
||||
|
||||
# load a bundle
|
||||
|
||||
LoadApacheBundle ApacheWO.apache
|
||||
#LoadSxApplication Test.sxa
|
||||
|
||||
AddType application/x-httpd-wox .wox
|
||||
|
||||
<Directory />
|
||||
Options FollowSymLinks
|
||||
AllowOverride None
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</Directory>
|
||||
|
||||
Alias /docs/ "/HOME/helge/mdev/helge/ApacheWO/docs/"
|
||||
|
||||
<Directory "/HOME/helge/mdev/helge/ApacheWO/docs/">
|
||||
# This may also be "None", "All", or any combination of "Indexes",
|
||||
# "Includes", "FollowSymLinks", "ExecCGI", or "MultiViews".
|
||||
Options FollowSymLinks
|
||||
AllowOverride All
|
||||
</Directory>
|
||||
|
||||
<Files ".htaccess">
|
||||
order allow,deny
|
||||
deny from all
|
||||
</Files>
|
||||
|
||||
<LocationMatch "^.*/CVS/$">
|
||||
order allow,deny
|
||||
deny from all
|
||||
</LocationMatch>
|
||||
|
||||
<LocationMatch "/sx*">
|
||||
SetSxApplication lapp
|
||||
SetSxRequestHandler WODirectActionRequestHandler
|
||||
SetHandler sx-handler
|
||||
</LocationMatch>
|
||||
|
||||
# Directory-Index could help ... ?
|
||||
#<LocationMatch "^.*/[a-z][a-z0-9_]*.wox/$">
|
||||
# ForceType application/x-httpd-wox
|
||||
# SetHandler wox-page
|
||||
#</LocationMatch>
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
rm -f core
|
||||
httpd -X -f $PWD/httpd.conf
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>CFXMLSaxDriver</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string></string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.opengroupware.xml.CFXMLSaxDriver</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string></string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>4.2</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>CFXMLSaxDriver</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright (C) 2000-2003 SKYRIX Software AG
|
||||
|
||||
This file is part of OGo
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
#include <SaxObjC/SaxObjC.h>
|
||||
|
||||
@class NSString, NSMutableDictionary;
|
||||
|
||||
@interface CFXMLSaxDriver : NSObject < SaxXMLReader >
|
||||
{
|
||||
id<NSObject,SaxContentHandler> contentHandler;
|
||||
id<NSObject,SaxErrorHandler> errorHandler;
|
||||
id<NSObject,SaxLexicalHandler> lexicalHandler;
|
||||
id<NSObject,SaxEntityResolver> entityResolver;
|
||||
NSMutableDictionary *pubIdToValue;
|
||||
|
||||
int depth;
|
||||
NSMutableArray *nsStack;
|
||||
BOOL fNamespaces;
|
||||
BOOL fNamespacePrefixes;
|
||||
|
||||
unichar *buffer;
|
||||
unsigned bufSize;
|
||||
|
||||
SaxAttributes *attrs;
|
||||
}
|
||||
|
||||
/* handlers */
|
||||
|
||||
- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler;
|
||||
- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler;
|
||||
- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler;
|
||||
- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler;
|
||||
- (id<NSObject,SaxContentHandler>)contentHandler;
|
||||
- (id<NSObject,SaxDTDHandler>)dtdHandler;
|
||||
- (id<NSObject,SaxErrorHandler>)errorHandler;
|
||||
- (id<NSObject,SaxEntityResolver>)entityResolver;
|
||||
|
||||
/* parsing */
|
||||
|
||||
- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId;
|
||||
|
||||
@end
|
|
@ -0,0 +1,881 @@
|
|||
/*
|
||||
Copyright (C) 2000-2003 SKYRIX Software AG
|
||||
|
||||
This file is part of OGo
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import "CFXMLSaxDriver.h"
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface CFXMLTagHolder : NSObject
|
||||
{
|
||||
@public
|
||||
NSString *localName;
|
||||
NSString *uri;
|
||||
NSString *prefix;
|
||||
NSString *rawName;
|
||||
}
|
||||
@end
|
||||
|
||||
static NSString *SaxDeclHandlerProperty =
|
||||
@"http://xml.org/sax/properties/declaration-handler";
|
||||
static NSString *SaxLexicalHandlerProperty =
|
||||
@"http://xml.org/sax/properties/lexical-handler";
|
||||
|
||||
@interface CFXMLSaxDriver(Privates)
|
||||
- (NSString *)nsUriForPrefix:(NSString *)_prefix;
|
||||
- (NSString *)defaultNamespace;
|
||||
- (void)declarePrefix:(NSString *)_prefix namespaceURI:(NSString *)_uri;
|
||||
@end
|
||||
|
||||
@implementation CFXMLSaxDriver
|
||||
|
||||
static BOOL debugNS = NO;
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
self->pubIdToValue = [[NSMutableDictionary alloc] init];
|
||||
[self->pubIdToValue setObject:@"<" forKey:@"lt"];
|
||||
[self->pubIdToValue setObject:@">" forKey:@"gt"];
|
||||
[self->pubIdToValue setObject:@"\"" forKey:@"quot"];
|
||||
[self->pubIdToValue setObject:@"&" forKey:@"amp"];
|
||||
|
||||
self->nsStack = [[NSMutableArray alloc] init];
|
||||
|
||||
/* feature defaults */
|
||||
self->fNamespaces = YES;
|
||||
self->fNamespacePrefixes = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self->attrs release];
|
||||
[self->nsStack release];
|
||||
|
||||
if (self->buffer) free(self->buffer);
|
||||
|
||||
[self->pubIdToValue release];
|
||||
[self->lexicalHandler release];
|
||||
[self->contentHandler release];
|
||||
[self->errorHandler release];
|
||||
[self->entityResolver release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* properties */
|
||||
|
||||
- (void)setProperty:(NSString *)_name to:(id)_value {
|
||||
if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
|
||||
[self->lexicalHandler autorelease];
|
||||
self->lexicalHandler = [_value retain];
|
||||
return;
|
||||
}
|
||||
if ([_name isEqualToString:SaxDeclHandlerProperty]) {
|
||||
return;
|
||||
}
|
||||
|
||||
[SaxNotRecognizedException raise:@"PropertyException"
|
||||
format:@"don't know property %@", _name];
|
||||
}
|
||||
- (id)property:(NSString *)_name {
|
||||
if ([_name isEqualToString:SaxLexicalHandlerProperty])
|
||||
return self->lexicalHandler;
|
||||
if ([_name isEqualToString:SaxDeclHandlerProperty])
|
||||
return nil;
|
||||
|
||||
[SaxNotRecognizedException raise:@"PropertyException"
|
||||
format:@"don't know property %@", _name];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* features */
|
||||
|
||||
- (void)setFeature:(NSString *)_name to:(BOOL)_value {
|
||||
if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"]) {
|
||||
self->fNamespaces = _value;
|
||||
return;
|
||||
}
|
||||
|
||||
if ([_name isEqualToString:
|
||||
@"http://xml.org/sax/features/namespace-prefixes"]) {
|
||||
self->fNamespacePrefixes = _value;
|
||||
return;
|
||||
}
|
||||
|
||||
[SaxNotRecognizedException raise:@"FeatureException"
|
||||
format:@"don't know feature %@", _name];
|
||||
}
|
||||
- (BOOL)feature:(NSString *)_name {
|
||||
if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"])
|
||||
return self->fNamespaces;
|
||||
|
||||
if ([_name isEqualToString:
|
||||
@"http://xml.org/sax/features/namespace-prefixes"])
|
||||
return self->fNamespacePrefixes;
|
||||
|
||||
if ([_name isEqualToString:
|
||||
@"http://www.skyrix.com/sax/features/predefined-namespaces"])
|
||||
return YES;
|
||||
|
||||
[SaxNotRecognizedException raise:@"FeatureException"
|
||||
format:@"don't know feature %@", _name];
|
||||
return NO;
|
||||
}
|
||||
|
||||
/* handlers */
|
||||
|
||||
- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
|
||||
[self->contentHandler autorelease];
|
||||
self->contentHandler = [_handler retain];
|
||||
}
|
||||
- (id<NSObject,SaxContentHandler>)contentHandler {
|
||||
return self->contentHandler;
|
||||
}
|
||||
|
||||
- (void)setLexicalHandler:(id<NSObject,SaxLexicalHandler>)_handler {
|
||||
[self->lexicalHandler autorelease];
|
||||
self->lexicalHandler = [_handler retain];
|
||||
}
|
||||
- (id<NSObject,SaxLexicalHandler>)lexicalHandler {
|
||||
return self->lexicalHandler;
|
||||
}
|
||||
|
||||
- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
|
||||
}
|
||||
- (id<NSObject,SaxDTDHandler>)dtdHandler {
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
|
||||
[self->errorHandler autorelease];
|
||||
self->errorHandler = [_handler retain];
|
||||
}
|
||||
- (id<NSObject,SaxErrorHandler>)errorHandler {
|
||||
return self->errorHandler;
|
||||
}
|
||||
|
||||
- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
|
||||
[self->entityResolver autorelease];
|
||||
self->entityResolver = [_handler retain];
|
||||
}
|
||||
- (id<NSObject,SaxEntityResolver>)entityResolver {
|
||||
return self->entityResolver;
|
||||
}
|
||||
|
||||
/* method callbacks */
|
||||
|
||||
- (void)beginDocument:(CFXMLNodeRef)_node {
|
||||
const CFXMLDocumentInfo *docInfoPtr;
|
||||
|
||||
docInfoPtr = CFXMLNodeGetInfoPtr(_node);
|
||||
//NSLog(@"begin-doc: url=%@", docInfoPtr->sourceURL);
|
||||
}
|
||||
- (void)endDocument:(id)_node {
|
||||
//NSLog(@"end-doc.");
|
||||
}
|
||||
|
||||
- (id<SaxAttributes>)handleAttributesOfNode:(CFXMLNodeRef)_node
|
||||
nsdecls:(NSDictionary **)_ns
|
||||
defaultPrefix:(NSString *)_defAttrNS
|
||||
{
|
||||
const CFXMLElementInfo *elemInfo;
|
||||
unsigned count, i, nsCount;
|
||||
NSMutableDictionary *ns = nil;
|
||||
|
||||
if ((elemInfo = CFXMLNodeGetInfoPtr(_node)) == NULL)
|
||||
return nil;
|
||||
|
||||
if ((count = [(NSArray *)elemInfo->attributeOrder count]) == 0)
|
||||
return nil;
|
||||
|
||||
/* pass one: collect all namespace declarations */
|
||||
|
||||
for (i = 0, nsCount = 0; i < count; i++) {
|
||||
NSString *attrName, *prefix, *uri;
|
||||
NSRange r;
|
||||
|
||||
attrName = [(NSArray *)elemInfo->attributeOrder objectAtIndex:i];
|
||||
if (![attrName hasPrefix:@"xmlns"]) continue;
|
||||
|
||||
/* ok, found ns decl */
|
||||
if (ns == nil) ns = [[[NSMutableDictionary alloc] init] autorelease];
|
||||
|
||||
nsCount++;
|
||||
r = [attrName rangeOfString:@"xmlns:"];
|
||||
prefix = r.length == 0
|
||||
? nil
|
||||
: [attrName substringFromIndex:(r.location + r.length)];
|
||||
uri = [(NSDictionary *)elemInfo->attributes objectForKey:attrName];
|
||||
|
||||
if (prefix) {
|
||||
/* eg <x xmlns:nl="http://www.w3.org"/> */
|
||||
[ns setObject:uri forKey:prefix];
|
||||
|
||||
if (self->fNamespaces)
|
||||
[self->contentHandler startPrefixMapping:prefix uri:uri];
|
||||
}
|
||||
else {
|
||||
/* eg <x xmlns="http://www.w3.org"/> */
|
||||
[ns setObject:uri forKey:@":"];
|
||||
}
|
||||
}
|
||||
*_ns = (ns != nil) ? [[ns copy] autorelease] : nil;
|
||||
|
||||
if (nsCount == count) /* all attrs were namespace declarations */
|
||||
return nil;
|
||||
|
||||
/* pass two: user attributes */
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
NSString *attrName, *prefix, *localName, *uri;
|
||||
NSString *value;
|
||||
NSRange r;
|
||||
|
||||
attrName = [(NSArray *)elemInfo->attributeOrder objectAtIndex:i];
|
||||
if (nsCount > 0) { /* do not consider namespace decls */
|
||||
if ([attrName hasPrefix:@"xmlns"]) {
|
||||
nsCount--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
r = [attrName rangeOfString:@":"];
|
||||
if (r.length == 0) { /* no prefix, use element namespace */
|
||||
prefix = nil;
|
||||
localName = attrName;
|
||||
|
||||
/* def-namespace for attributes is 1. element, 2. context */
|
||||
if (_defAttrNS) {
|
||||
if ((uri = [ns objectForKey:_defAttrNS]) == nil) {
|
||||
if ((uri = [self nsUriForPrefix:_defAttrNS]) == nil) {
|
||||
NSLog(@"ERROR: did not find namespace for element prefix '%@' !",
|
||||
_defAttrNS);
|
||||
uri = [self defaultNamespace];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
uri = [self defaultNamespace];
|
||||
}
|
||||
else { /* has prefix, lookup namespace */
|
||||
prefix = [attrName substringToIndex:r.location];
|
||||
localName = [attrName substringFromIndex:(r.location + r.length)];
|
||||
if ((uri = [ns objectForKey:prefix]) == nil)
|
||||
uri = [self nsUriForPrefix:prefix];
|
||||
}
|
||||
|
||||
value = [(NSDictionary *)elemInfo->attributes objectForKey:attrName];
|
||||
|
||||
[self->attrs addAttribute:localName uri:uri rawName:attrName
|
||||
type:@"CDATA" value:value];
|
||||
}
|
||||
return self->attrs;
|
||||
}
|
||||
|
||||
- (CFXMLTagHolder *)beginElementNode:(CFXMLNodeRef)_node {
|
||||
CFXMLTagHolder *info;
|
||||
id<SaxAttributes> lattrs;
|
||||
NSDictionary *nsDict = nil;
|
||||
NSRange r;
|
||||
|
||||
info = [[CFXMLTagHolder alloc] init];
|
||||
info->rawName = [(NSString *)CFXMLNodeGetString(_node) copy];
|
||||
|
||||
/* prepare tagname processing */
|
||||
|
||||
r = [info->rawName rangeOfString:@":"];
|
||||
if (r.length == 0) { /* no namespace prefix */
|
||||
info->prefix = nil;
|
||||
info->localName = [info->rawName copy];
|
||||
}
|
||||
else { /* has a namespace prefix */
|
||||
info->prefix =
|
||||
[[info->rawName substringToIndex:r.location] copy];
|
||||
info->localName =
|
||||
[[info->rawName substringFromIndex:(r.location + r.length)] copy];
|
||||
}
|
||||
|
||||
/* process attribute information (first for ns declarations) */
|
||||
|
||||
if (self->attrs == nil)
|
||||
self->attrs = [[SaxAttributes alloc] init];
|
||||
else
|
||||
[self->attrs clear];
|
||||
|
||||
if (debugNS) NSLog(@"PROCESS attributes ...");
|
||||
lattrs = [self handleAttributesOfNode:_node
|
||||
nsdecls:&nsDict
|
||||
defaultPrefix:info->prefix];
|
||||
if (nsDict == nil)
|
||||
nsDict = [NSDictionary dictionary];
|
||||
|
||||
NSCAssert(self->nsStack, @"missing namespace stack");
|
||||
[self->nsStack addObject:nsDict];
|
||||
|
||||
/* do namespace processing */
|
||||
|
||||
info->uri = (info->prefix == nil)
|
||||
? nil /* no namespace prefix */
|
||||
: [[self nsUriForPrefix:info->prefix] copy];
|
||||
if (info->uri == nil) info->uri = [[self defaultNamespace] copy];
|
||||
if (debugNS)
|
||||
NSLog(@"TAG PREFIX: %@ URI: %@", info->prefix, info->uri);
|
||||
|
||||
/* pass on */
|
||||
|
||||
self->depth++;
|
||||
[self->contentHandler startElement:info->localName
|
||||
namespace:info->uri
|
||||
rawName:info->rawName
|
||||
attributes:lattrs /* id<SaxAttributes> */];
|
||||
return info; /* pass back an object */
|
||||
}
|
||||
- (void)endElementNode:(CFXMLTagHolder *)_info {
|
||||
[self->contentHandler endElement:_info->localName
|
||||
namespace:_info->uri
|
||||
rawName:_info->rawName];
|
||||
self->depth--;
|
||||
[_info release];
|
||||
|
||||
/* process namespace stack */
|
||||
|
||||
if (self->fNamespaces) {
|
||||
NSDictionary *ns;
|
||||
NSEnumerator *keys;
|
||||
NSString *key;
|
||||
|
||||
ns = [self->nsStack lastObject];
|
||||
keys = [ns keyEnumerator];
|
||||
while ((key = [keys nextObject])) {
|
||||
if ([key isEqualToString:@":"])
|
||||
continue;
|
||||
[self->contentHandler endPrefixMapping:key];
|
||||
}
|
||||
}
|
||||
[self->nsStack removeLastObject];
|
||||
}
|
||||
|
||||
- (void)piNode:(CFXMLNodeRef)_node {
|
||||
[self->contentHandler processingInstruction:(id)CFXMLNodeGetString(_node)
|
||||
data:nil];
|
||||
}
|
||||
|
||||
- (void)commentNode:(CFXMLNodeRef)_node {
|
||||
NSString *s;
|
||||
unichar *buf;
|
||||
unsigned len;
|
||||
|
||||
s = (NSString *)CFXMLNodeGetString(_node);
|
||||
len = [s length];
|
||||
buf = calloc(len + 4, sizeof(unichar));
|
||||
[s getCharacters:buf];
|
||||
|
||||
[self->lexicalHandler comment:buf length:len];
|
||||
if (buf) free(buf);
|
||||
}
|
||||
|
||||
- (void)_unicharNode:(CFXMLNodeRef)_node selector:(SEL)_sel {
|
||||
NSString *s;
|
||||
unsigned len;
|
||||
unichar *ownBuf = NULL, *useBuf;
|
||||
void (*cb)(id, SEL, unichar *, int);
|
||||
|
||||
if (self->contentHandler == nil)
|
||||
return;
|
||||
if ((s = (NSString *)CFXMLNodeGetString(_node)) == nil)
|
||||
return;
|
||||
if ((len = [s length]) == 0)
|
||||
return;
|
||||
|
||||
if ((cb = (void *)[(id)self->contentHandler methodForSelector:_sel])==NULL) {
|
||||
/* content-handler does not respond to the selector */
|
||||
NSLog(@"ERROR(%s): content handler does not implement %@: %@",
|
||||
__PRETTY_FUNCTION__,
|
||||
NSStringFromSelector(_sel), self->contentHandler);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->buffer == NULL) {
|
||||
self->buffer = calloc(256, sizeof(unichar));
|
||||
self->bufSize = 250;
|
||||
}
|
||||
if (len > 250) { /* use an own buffer for larger bodies */
|
||||
ownBuf = calloc(len + 10, sizeof(unichar));
|
||||
useBuf = ownBuf;
|
||||
}
|
||||
else
|
||||
useBuf = self->buffer;
|
||||
|
||||
[s getCharacters:useBuf];
|
||||
cb(self->contentHandler, _sel, useBuf, len);
|
||||
|
||||
if (ownBuf) free(ownBuf);
|
||||
}
|
||||
|
||||
- (void)textNode:(CFXMLNodeRef)_node {
|
||||
if (self->contentHandler == nil) return;
|
||||
[self _unicharNode:_node selector:@selector(characters:length:)];
|
||||
}
|
||||
- (void)cdataNode:(CFXMLNodeRef)_node {
|
||||
if (self->contentHandler == nil) return;
|
||||
[self _unicharNode:_node selector:@selector(characters:length:)];
|
||||
}
|
||||
- (void)whiteSpaceNode:(CFXMLNodeRef)_node {
|
||||
if (self->contentHandler == nil) return;
|
||||
[self _unicharNode:_node selector:@selector(ignorableWhitespace:length:)];
|
||||
}
|
||||
|
||||
- (void)dtdNode:(CFXMLNodeRef)_node {
|
||||
NSLog(@"DTD: %@", CFXMLNodeGetString(_node));
|
||||
}
|
||||
|
||||
- (void)entityReference:(NSString *)_rid {
|
||||
NSString *value;
|
||||
|
||||
if (self->contentHandler == nil)
|
||||
return;
|
||||
|
||||
if ((value = [self->pubIdToValue objectForKey:_rid]) == nil) {
|
||||
NSLog(@"ERROR(%s): found no value for entity reference %@",
|
||||
__PRETTY_FUNCTION__, _rid);
|
||||
}
|
||||
|
||||
if ([value isKindOfClass:[NSString class]]) {
|
||||
unsigned len;
|
||||
unichar *ownBuf;
|
||||
|
||||
len = [value length];
|
||||
ownBuf = calloc(len + 4, sizeof(unichar));
|
||||
[value getCharacters:ownBuf];
|
||||
[self->contentHandler characters:ownBuf length:len];
|
||||
if (ownBuf) free(ownBuf);
|
||||
}
|
||||
else
|
||||
NSLog(@"unknown value class for entity reference %@", _rid);
|
||||
}
|
||||
|
||||
- (NSData *)resolveEntityWithPublicId:(NSString *)_pubId
|
||||
systemId:(NSURL *)_sysId
|
||||
{
|
||||
NSLog(@"found to value for entity %@/%@", _pubId, _sysId);
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)handleErrorCode:(unsigned int)_code
|
||||
description:(NSString *)_info
|
||||
line:(int)_line position:(int)_pos
|
||||
{
|
||||
NSLog(@"Parse error (%d) %@ on line %d, character %d\n",
|
||||
(int)_code, _info, _line, _pos);
|
||||
return NO;
|
||||
}
|
||||
|
||||
/* callbacks */
|
||||
|
||||
typedef struct {
|
||||
id info;
|
||||
int typeCode;
|
||||
} ResInfo;
|
||||
|
||||
void *createStructure(CFXMLParserRef parser,
|
||||
CFXMLNodeRef node, void *info)
|
||||
{
|
||||
CFXMLSaxDriver *self = info;
|
||||
CFStringRef myTypeStr = NULL;
|
||||
CFStringRef myDataStr = NULL;
|
||||
ResInfo *result = NULL;
|
||||
|
||||
result = malloc(sizeof(ResInfo));
|
||||
result->info = nil;
|
||||
result->typeCode = CFXMLNodeGetTypeCode(node);
|
||||
|
||||
// Use the dataTypeID to determine what to print.
|
||||
switch (CFXMLNodeGetTypeCode(node)) {
|
||||
case kCFXMLNodeTypeDocument:
|
||||
[self beginDocument:node];
|
||||
break;
|
||||
|
||||
case kCFXMLNodeTypeElement:
|
||||
result->info = [self beginElementNode:node];
|
||||
break;
|
||||
|
||||
case kCFXMLNodeTypeProcessingInstruction:
|
||||
[self piNode:node];
|
||||
break;
|
||||
|
||||
case kCFXMLNodeTypeComment:
|
||||
[self commentNode:node];
|
||||
break;
|
||||
|
||||
case kCFXMLNodeTypeText:
|
||||
[self textNode:node];
|
||||
break;
|
||||
|
||||
case kCFXMLNodeTypeCDATASection:
|
||||
[self cdataNode:node];
|
||||
break;
|
||||
|
||||
case kCFXMLNodeTypeEntityReference:
|
||||
[self entityReference:(NSString *)CFXMLNodeGetString(node)];
|
||||
break;
|
||||
|
||||
case kCFXMLNodeTypeDocumentType:
|
||||
[self dtdNode:node];
|
||||
break;
|
||||
|
||||
case kCFXMLNodeTypeWhitespace:
|
||||
[self whiteSpaceNode:node];
|
||||
break;
|
||||
|
||||
default:
|
||||
NSLog(@"%s: unknown node ID %i", result->typeCode);
|
||||
break;
|
||||
}
|
||||
|
||||
// Print the contents.
|
||||
if (myTypeStr) {
|
||||
printf("---Create Structure Called--- \n");
|
||||
NSLog(@"type: %@", myTypeStr);
|
||||
NSLog(@"data: %@", myDataStr);
|
||||
}
|
||||
|
||||
// Release the strings.
|
||||
if (myTypeStr) CFRelease(myTypeStr);
|
||||
|
||||
// Return the data string for use by the addChild and
|
||||
// endStructure callbacks.
|
||||
return result;
|
||||
}
|
||||
|
||||
void addChild(CFXMLParserRef parser, void *p, void *child, void *info) {
|
||||
#if 0 /* a noop */
|
||||
NSLog(@"add child %@ to %@ ...", (id)child, (id)p);
|
||||
#endif
|
||||
}
|
||||
|
||||
void endStructure(CFXMLParserRef parser, void *xmlType, void *info) {
|
||||
CFXMLSaxDriver *self = info;
|
||||
ResInfo *result = xmlType;
|
||||
NSCAssert(self, @"missing self");
|
||||
|
||||
switch (result->typeCode) {
|
||||
case kCFXMLNodeTypeDocument: /* never called ? */
|
||||
[self endDocument:result->info];
|
||||
break;
|
||||
|
||||
case kCFXMLNodeTypeElement:
|
||||
[self endElementNode:result->info];
|
||||
break;
|
||||
|
||||
/* most nodes do not have an "end" event */
|
||||
case kCFXMLNodeTypeProcessingInstruction:
|
||||
case kCFXMLNodeTypeComment:
|
||||
case kCFXMLNodeTypeText:
|
||||
case kCFXMLNodeTypeCDATASection:
|
||||
case kCFXMLNodeTypeEntityReference:
|
||||
case kCFXMLNodeTypeDocumentType:
|
||||
case kCFXMLNodeTypeWhitespace:
|
||||
break;
|
||||
|
||||
default:
|
||||
NSLog(@"%s: unknown node: %i: %@", __PRETTY_FUNCTION__,
|
||||
result->typeCode, result->info);
|
||||
break;
|
||||
}
|
||||
if (result) free(result);
|
||||
}
|
||||
|
||||
CFDataRef resolveEntity(CFXMLParserRef parser, CFXMLExternalID *extID,
|
||||
void *info)
|
||||
{
|
||||
CFXMLSaxDriver *self = info;
|
||||
return (CFDataRef)[self resolveEntityWithPublicId:(NSString *)extID->publicID
|
||||
systemId:(NSURL *)extID->systemID];
|
||||
}
|
||||
|
||||
Boolean handleError(CFXMLParserRef parser, CFXMLParserStatusCode error, void *info) {
|
||||
CFXMLSaxDriver *self = info;
|
||||
NSString *s;
|
||||
BOOL cont;
|
||||
|
||||
s = [(id)CFXMLParserCopyErrorDescription(parser) autorelease];
|
||||
cont = [self handleErrorCode:error description:s
|
||||
line:(int)CFXMLParserGetLineNumber(parser)
|
||||
position:(int)CFXMLParserGetLocation(parser)];
|
||||
return cont ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/* parsing */
|
||||
|
||||
- (NSStringEncoding)encodingForXMLEncodingString:(NSString *)_enc {
|
||||
if ([_enc isEqualToString:@"utf-8"])
|
||||
return NSUTF8StringEncoding;
|
||||
else if ([_enc isEqualToString:@"iso-8859-1"])
|
||||
return NSISOLatin1StringEncoding;
|
||||
else if ([_enc isEqualToString:@"ascii"])
|
||||
return NSASCIIStringEncoding;
|
||||
else {
|
||||
NSLog(@"%s: UNKNOWN XML ENCODING '%@'",
|
||||
__PRETTY_FUNCTION__, _enc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSData *)dataForXMLString:(NSString *)_string {
|
||||
NSData *data;
|
||||
NSRange r;
|
||||
|
||||
data = nil;
|
||||
|
||||
r = [_string rangeOfString:@"?>"];
|
||||
if ([_string hasPrefix:@"<?xml "] && (r.length != 0)) {
|
||||
NSString *xmlDecl;
|
||||
|
||||
xmlDecl = [_string substringToIndex:r.location];
|
||||
|
||||
r = [xmlDecl rangeOfString:@"encoding='"];
|
||||
if (r.length > 0) {
|
||||
xmlDecl = [_string substringFromIndex:(r.location + 10)];
|
||||
r = [xmlDecl rangeOfString:@"'"];
|
||||
xmlDecl = (r.length > 0)
|
||||
? [xmlDecl substringToIndex:r.location]
|
||||
: nil;
|
||||
}
|
||||
else {
|
||||
r = [xmlDecl rangeOfString:@"encoding=\""];
|
||||
if (r.length > 0) {
|
||||
xmlDecl = [_string substringFromIndex:(r.location + 10)];
|
||||
r = [xmlDecl rangeOfString:@"'"];
|
||||
xmlDecl = r.length > 0
|
||||
? [xmlDecl substringToIndex:r.location]
|
||||
: nil;
|
||||
}
|
||||
else
|
||||
xmlDecl = nil;
|
||||
}
|
||||
|
||||
if ([xmlDecl length] > 0) {
|
||||
NSStringEncoding enc;
|
||||
|
||||
if ((enc = [self encodingForXMLEncodingString:xmlDecl]) != 0) {
|
||||
data = [_string dataUsingEncoding:enc];
|
||||
if (data == nil) {
|
||||
NSLog(@"WARNING(%s): couldn't get data for string '%@', "
|
||||
@"encoding %i !", __PRETTY_FUNCTION__, _string, enc);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data == nil)
|
||||
data = [_string dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static const void *retainParser(const void *info) {
|
||||
return [(id)info retain];
|
||||
}
|
||||
static void releaseParser(const void *info) {
|
||||
[(id)info release];
|
||||
}
|
||||
static CFStringRef parserDescription(const void *info) {
|
||||
return (CFStringRef)[(id)info description];
|
||||
}
|
||||
|
||||
- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
|
||||
CFXMLParserCallBacks callbacks = {
|
||||
0,
|
||||
createStructure,
|
||||
addChild,
|
||||
endStructure,
|
||||
resolveEntity,
|
||||
handleError
|
||||
};
|
||||
CFXMLParserContext ctx = {
|
||||
0 /* version */,
|
||||
self /* info */,
|
||||
retainParser,
|
||||
releaseParser,
|
||||
parserDescription /* copyDescription */
|
||||
};
|
||||
CFXMLParserRef parser;
|
||||
NSData *content;
|
||||
NSURL *url = nil;
|
||||
|
||||
if (_source == nil) {
|
||||
/* no source ??? */
|
||||
return;
|
||||
}
|
||||
|
||||
if ([_source isKindOfClass:[NSString class]]) {
|
||||
/* convert strings to UTF8 data */
|
||||
if (_sysId == nil) _sysId = @"<string>";
|
||||
_source = [self dataForXMLString:_source];
|
||||
}
|
||||
else if ([_source isKindOfClass:[NSURL class]]) {
|
||||
if (_sysId == nil) _sysId = [_source absoluteString];
|
||||
_source = [_source resourceDataUsingCache:NO];
|
||||
}
|
||||
else if ([_source isKindOfClass:[NSData class]]) {
|
||||
if (_sysId == nil) _sysId = @"<data>";
|
||||
}
|
||||
else {
|
||||
SaxParseException *e;
|
||||
NSDictionary *ui;
|
||||
|
||||
ui = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
_source ? _source : @"<nil>", @"source",
|
||||
self, @"parser",
|
||||
nil];
|
||||
|
||||
e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
|
||||
reason:@"can't handle data-source"
|
||||
userInfo:ui];
|
||||
|
||||
[self->errorHandler fatalError:e];
|
||||
return;
|
||||
}
|
||||
|
||||
/* get data from source */
|
||||
|
||||
content = _source;
|
||||
|
||||
if (url == nil) {
|
||||
url = _sysId
|
||||
? [NSURL URLWithString:_sysId]
|
||||
: [NSURL URLWithString:@"object://unknown"];
|
||||
}
|
||||
|
||||
/* create parser */
|
||||
|
||||
parser = CFXMLParserCreate(kCFAllocatorDefault,
|
||||
(CFDataRef)content,
|
||||
(CFURLRef)url,
|
||||
kCFXMLParserSkipWhitespace,
|
||||
kCFXMLNodeCurrentVersion,
|
||||
&callbacks,
|
||||
&ctx);
|
||||
if (parser == nil) {
|
||||
NSLog(@"got no parser ...");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* invoke the parser */
|
||||
|
||||
[self->contentHandler startDocument];
|
||||
|
||||
if (!CFXMLParserParse(parser))
|
||||
printf("parse failed\n");
|
||||
|
||||
[self->contentHandler endDocument];
|
||||
|
||||
/* cleanup */
|
||||
if (parser) CFRelease(parser);
|
||||
}
|
||||
|
||||
- (void)parseFromSource:(id)_source {
|
||||
[self parseFromSource:_source systemId:nil];
|
||||
}
|
||||
- (void)parseFromSystemId:(NSString *)_sysId {
|
||||
NSURL *url;
|
||||
|
||||
if ([_sysId rangeOfString:@"://"].length == 0) {
|
||||
/* not a URL */
|
||||
if (![_sysId isAbsolutePath])
|
||||
_sysId = [[NSFileManager defaultManager] currentDirectoryPath];
|
||||
url = [NSURL fileURLWithPath:_sysId];
|
||||
}
|
||||
else
|
||||
url = [NSURL URLWithString:_sysId];
|
||||
|
||||
[self parseFromSource:url systemId:_sysId];
|
||||
}
|
||||
|
||||
/* namespace support */
|
||||
|
||||
- (NSString *)nsUriForPrefix:(NSString *)_prefix {
|
||||
NSEnumerator *e;
|
||||
NSDictionary *ns;
|
||||
|
||||
if (debugNS)
|
||||
NSLog(@"lookup prefix: '%@'", _prefix);
|
||||
|
||||
e = [self->nsStack reverseObjectEnumerator];
|
||||
while ((ns = [e nextObject])) {
|
||||
NSString *uri;
|
||||
|
||||
if ((uri = [ns objectForKey:_prefix])) {
|
||||
if (debugNS)
|
||||
NSLog(@"prefix %@ -> uri '%@'", _prefix, uri);
|
||||
return uri;
|
||||
}
|
||||
}
|
||||
if (debugNS)
|
||||
NSLog(@"prefix %@ -> NO uri", _prefix);
|
||||
//return nil;
|
||||
return @"";
|
||||
}
|
||||
|
||||
- (NSString *)defaultNamespace {
|
||||
return [self nsUriForPrefix:@":"];
|
||||
}
|
||||
|
||||
- (void)declarePrefix:(NSString *)_prefix namespaceURI:(NSString *)_uri {
|
||||
NSMutableDictionary *ns = nil;
|
||||
NSDictionary *newns;
|
||||
unsigned count;
|
||||
|
||||
NSCAssert(self->nsStack, @"missing namespace stack");
|
||||
|
||||
if ((count = [self->nsStack count]) == 0)
|
||||
ns = [[NSMutableDictionary alloc] initWithCapacity:2];
|
||||
else
|
||||
ns = [[self->nsStack lastObject] mutableCopy];
|
||||
|
||||
if ([_prefix length] == 0)
|
||||
_prefix = @":";
|
||||
|
||||
[ns setObject:_uri forKey:_prefix];
|
||||
|
||||
newns = [ns copy];
|
||||
[ns release];
|
||||
|
||||
if (count == 0)
|
||||
[self->nsStack addObject:newns];
|
||||
else
|
||||
[self->nsStack replaceObjectAtIndex:(count - 1) withObject:newns];
|
||||
|
||||
[newns release];
|
||||
}
|
||||
|
||||
@end /* CFXMLSaxDriver */
|
||||
|
||||
@implementation CFXMLTagHolder
|
||||
|
||||
- (void)dealloc {
|
||||
[self->localName release];
|
||||
[self->uri release];
|
||||
[self->prefix release];
|
||||
[self->rawName release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end /* CFXMLTagHolder */
|
|
@ -0,0 +1,482 @@
|
|||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
|
@ -0,0 +1,24 @@
|
|||
2004-04-13 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* CFXMLSaxDriver.m: do not dump core if the contentHandler callback
|
||||
doesn't implement a proper character selector or if no contentHandler
|
||||
is set
|
||||
|
||||
2004-02-27 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* CFXMLSaxDriver.m: major fix to namespace processing (was not able to
|
||||
properly parse .wox templates before)
|
||||
|
||||
2003-09-06 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* CFXMLSaxDriver.m: fixed warnings on invalid prototypes for error
|
||||
reporting and entity resolution CFXML callbacks (at least the entity
|
||||
callback was completely wrong)
|
||||
|
||||
2003-05-29 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* CFXMLSaxDriver.m (-handleAttributesOfNode:nsdecls:defaultPrefix:):
|
||||
fixed a namespace processing bug, attributes did not inherit the
|
||||
namespace of their element as their default namespace
|
||||
|
||||
* created ChangeLog
|
|
@ -0,0 +1,10 @@
|
|||
# $Id$
|
||||
|
||||
CFXMLSaxDriver
|
||||
==============
|
||||
|
||||
This directory contains the sources for a SAX driver bundle which is based
|
||||
on the MacOSX CoreFoundation XML parser.
|
||||
|
||||
Requirements:
|
||||
- MacOSX
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"__cvs__" = "$Id$";
|
||||
|
||||
requires = {
|
||||
bundleManagerVersion = 1;
|
||||
classes = (
|
||||
{ name = NSObject; }
|
||||
);
|
||||
};
|
||||
|
||||
provides = {
|
||||
SAXDrivers = (
|
||||
{
|
||||
name = CFXMLSaxDriver;
|
||||
sourceTypes = ( "text/xml" );
|
||||
}
|
||||
);
|
||||
classes = ( { name = CFXMLSaxDriver; } );
|
||||
};
|
||||
}
|
|
@ -0,0 +1,482 @@
|
|||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>ExpatSaxDriver</string>
|
||||
<key>CFBundleGetInfoString</key>
|
||||
<string></string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.OpenGroupware.sope-xml.ExpatSaxDriver</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>BNDL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string></string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>4.5.0</string>
|
||||
</dict>
|
||||
</plist>
|
|
@ -0,0 +1,739 @@
|
|||
/*
|
||||
Copyright (C) 2000-2003 SKYRIX Software AG
|
||||
|
||||
This file is part of OGo
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
// $Id: ExpatSaxDriver.m 1 2004-08-20 10:08:27Z znek $
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
#include <SaxObjC/SaxXMLReader.h>
|
||||
#include <SaxObjC/SaxContentHandler.h>
|
||||
#include <SaxObjC/SaxDTDHandler.h>
|
||||
#include <SaxObjC/SaxErrorHandler.h>
|
||||
#include <SaxObjC/SaxEntityResolver.h>
|
||||
#include <SaxObjC/SaxLexicalHandler.h>
|
||||
#include <SaxObjC/SaxLocator.h>
|
||||
#include <SaxObjC/SaxDeclHandler.h>
|
||||
#include <expat.h>
|
||||
#include <NGExtensions/NGExtensions.h>
|
||||
|
||||
@class NSMutableArray, NSMutableDictionary;
|
||||
@class SaxAttributes;
|
||||
|
||||
@interface ExpatSaxDriver : NSObject < SaxXMLReader >
|
||||
{
|
||||
@private
|
||||
id<NSObject,SaxContentHandler> contentHandler;
|
||||
id<NSObject,SaxDTDHandler> dtdHandler;
|
||||
id<NSObject,SaxErrorHandler> errorHandler;
|
||||
id<NSObject,SaxEntityResolver> entityResolver;
|
||||
|
||||
id<NSObject,SaxLexicalHandler> lexicalHandler;
|
||||
id<NSObject,SaxDeclHandler> declHandler;
|
||||
|
||||
/* expat */
|
||||
XML_Parser expat;
|
||||
|
||||
/* features */
|
||||
BOOL fNamespaces;
|
||||
BOOL fNamespacePrefixes;
|
||||
NSMutableDictionary *declNS;
|
||||
|
||||
/* cached buffers */
|
||||
char *nameBuf;
|
||||
unsigned nameBufLen;
|
||||
SaxAttributes *attrs;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#include <SaxObjC/SaxException.h>
|
||||
#include "common.h"
|
||||
|
||||
static NSString *SaxDeclHandlerProperty =
|
||||
@"http://xml.org/sax/properties/declaration-handler";
|
||||
static NSString *SaxLexicalHandlerProperty =
|
||||
@"http://xml.org/sax/properties/lexical-handler";
|
||||
#if 0
|
||||
static NSString *SaxDOMNodeProperty =
|
||||
@"http://xml.org/sax/properties/dom-node";
|
||||
static NSString *SaxXMLStringProperty =
|
||||
@"http://xml.org/sax/properties/xml-string";
|
||||
#endif
|
||||
|
||||
@interface ExpatSaxDriver(Privates)
|
||||
- (BOOL)_setupParser;
|
||||
- (void)_tearDownParser;
|
||||
@end
|
||||
|
||||
static int _UTF8ToUTF16(unsigned char **sourceStart, unsigned char *sourceEnd,
|
||||
unichar **targetStart, const unichar *targetEnd);
|
||||
|
||||
typedef struct {
|
||||
NSString *raw;
|
||||
NSString *tag;
|
||||
NSString *uri;
|
||||
} TagTriple;
|
||||
|
||||
@implementation ExpatSaxDriver
|
||||
|
||||
static NSMapTable *uniqueStrings = NULL; // THREAD
|
||||
static Class NSStringClass = Nil;
|
||||
|
||||
// ZNeK: bad idea, no?
|
||||
#define NSNonOwnedCStringMapKeyCallBacks NSNonOwnedPointerMapKeyCallBacks
|
||||
|
||||
static inline NSString *uniqueStringUTF8(const char *utf8) {
|
||||
NSString *s;
|
||||
char *newkey;
|
||||
|
||||
if (utf8 == NULL) return nil;
|
||||
|
||||
if (uniqueStrings == NULL) {
|
||||
uniqueStrings = NSCreateMapTable(NSNonOwnedCStringMapKeyCallBacks,
|
||||
NSObjectMapValueCallBacks,
|
||||
128);
|
||||
}
|
||||
else if ((s = NSMapGet(uniqueStrings, utf8))) {
|
||||
/* found a string in cache ... */
|
||||
return RETAIN(s);
|
||||
}
|
||||
|
||||
newkey = malloc(strlen(utf8) + 1);
|
||||
strcpy(newkey, utf8);
|
||||
|
||||
if (NSStringClass == Nil)
|
||||
NSStringClass = [NSString class];
|
||||
|
||||
s = [[NSStringClass alloc] initWithUTF8String:newkey];
|
||||
NSMapInsert(uniqueStrings, newkey, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
/* feature defaults */
|
||||
self->fNamespaces = YES;
|
||||
self->fNamespacePrefixes = NO;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self _tearDownParser];
|
||||
RELEASE(self->attrs);
|
||||
RELEASE(self->declNS);
|
||||
RELEASE(self->declHandler);
|
||||
RELEASE(self->lexicalHandler);
|
||||
RELEASE(self->contentHandler);
|
||||
RELEASE(self->dtdHandler);
|
||||
RELEASE(self->errorHandler);
|
||||
RELEASE(self->entityResolver);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* properties */
|
||||
|
||||
- (void)setProperty:(NSString *)_name to:(id)_value {
|
||||
if ([_name isEqualToString:SaxLexicalHandlerProperty]) {
|
||||
ASSIGN(self->lexicalHandler, _value);
|
||||
return;
|
||||
}
|
||||
if ([_name isEqualToString:SaxDeclHandlerProperty]) {
|
||||
ASSIGN(self->declHandler, _value);
|
||||
return;
|
||||
}
|
||||
|
||||
[SaxNotRecognizedException raise:@"PropertyException"
|
||||
format:@"don't know property %@", _name];
|
||||
}
|
||||
- (id)property:(NSString *)_name {
|
||||
if ([_name isEqualToString:SaxLexicalHandlerProperty])
|
||||
return self->lexicalHandler;
|
||||
if ([_name isEqualToString:SaxDeclHandlerProperty])
|
||||
return self->declHandler;
|
||||
|
||||
[SaxNotRecognizedException raise:@"PropertyException"
|
||||
format:@"don't know property %@", _name];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* features */
|
||||
|
||||
- (void)setFeature:(NSString *)_name to:(BOOL)_value {
|
||||
if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"]) {
|
||||
self->fNamespaces = _value;
|
||||
return;
|
||||
}
|
||||
|
||||
if ([_name isEqualToString:
|
||||
@"http://xml.org/sax/features/namespace-prefixes"]) {
|
||||
self->fNamespacePrefixes = _value;
|
||||
return;
|
||||
}
|
||||
|
||||
[SaxNotRecognizedException raise:@"FeatureException"
|
||||
format:@"don't know feature %@", _name];
|
||||
}
|
||||
- (BOOL)feature:(NSString *)_name {
|
||||
if ([_name isEqualToString:@"http://xml.org/sax/features/namespaces"])
|
||||
return self->fNamespaces;
|
||||
|
||||
if ([_name isEqualToString:
|
||||
@"http://xml.org/sax/features/namespace-prefixes"])
|
||||
return self->fNamespacePrefixes;
|
||||
|
||||
if ([_name isEqualToString:
|
||||
@"http://www.skyrix.com/sax/features/predefined-namespaces"])
|
||||
return YES;
|
||||
|
||||
[SaxNotRecognizedException raise:@"FeatureException"
|
||||
format:@"don't know feature %@", _name];
|
||||
return NO;
|
||||
}
|
||||
|
||||
/* pre-defining namespaces */
|
||||
|
||||
- (void)declarePrefix:(NSString *)_prefix namespaceURI:(NSString *)_uri {
|
||||
NSAssert(_prefix, @"invalid prefix ...");
|
||||
NSAssert(_uri, @"invalid uri ...");
|
||||
|
||||
if (self->declNS == nil) {
|
||||
self->declNS = [[NSMutableDictionary alloc] initWithCapacity:8];
|
||||
|
||||
[self->declNS
|
||||
setObject:@"http://www.w3.org/XML/1998/namespace"
|
||||
forKey:@"xml"];
|
||||
[self->declNS setObject:@"" forKey:@":"];
|
||||
}
|
||||
|
||||
[self->declNS setObject:_uri forKey:_prefix];
|
||||
}
|
||||
|
||||
/* handlers */
|
||||
|
||||
#if 0
|
||||
- (void)setDocumentHandler:(id<NSObject,SaxDocumentHandler>)_handler {
|
||||
SaxDocumentHandlerAdaptor *a;
|
||||
|
||||
a = [[SaxDocumentHandlerAdaptor alloc] initWithDocumentHandler:_handler];
|
||||
[self setContentHandler:a];
|
||||
RELEASE(a);
|
||||
}
|
||||
#endif
|
||||
|
||||
- (void)setDTDHandler:(id<NSObject,SaxDTDHandler>)_handler {
|
||||
ASSIGN(self->dtdHandler, _handler);
|
||||
}
|
||||
- (id<NSObject,SaxDTDHandler>)dtdHandler {
|
||||
return self->dtdHandler;
|
||||
}
|
||||
|
||||
- (void)setErrorHandler:(id<NSObject,SaxErrorHandler>)_handler {
|
||||
ASSIGN(self->errorHandler, _handler);
|
||||
}
|
||||
- (id<NSObject,SaxErrorHandler>)errorHandler {
|
||||
return self->errorHandler;
|
||||
}
|
||||
|
||||
- (void)setEntityResolver:(id<NSObject,SaxEntityResolver>)_handler {
|
||||
ASSIGN(self->entityResolver, _handler);
|
||||
}
|
||||
- (id<NSObject,SaxEntityResolver>)entityResolver {
|
||||
return self->entityResolver;
|
||||
}
|
||||
|
||||
- (void)setContentHandler:(id<NSObject,SaxContentHandler>)_handler {
|
||||
ASSIGN(self->contentHandler, _handler);
|
||||
}
|
||||
- (id<NSObject,SaxContentHandler>)contentHandler {
|
||||
return self->contentHandler;
|
||||
}
|
||||
|
||||
/* parsing */
|
||||
|
||||
- (void)_reportParseError:(enum XML_Error)_error systemId:(NSString *)_sysId {
|
||||
NSMutableDictionary *ui;
|
||||
NSException *e;
|
||||
NSString *ename;
|
||||
NSString *ereason;
|
||||
SEL sel;
|
||||
|
||||
ename = @"SaxException";
|
||||
ereason = @"XML parse error";
|
||||
sel = @selector(fatalError:);
|
||||
|
||||
switch (_error) {
|
||||
case XML_ERROR_NONE: /* no error ... */
|
||||
return;
|
||||
case XML_ERROR_SYNTAX:
|
||||
sel = @selector(error:);
|
||||
ereason = @"XML syntax error";
|
||||
break;
|
||||
case XML_ERROR_NO_MEMORY:
|
||||
sel = @selector(fatalError:);
|
||||
ereason = @"out of memory";
|
||||
break;
|
||||
case XML_ERROR_NO_ELEMENTS:
|
||||
sel = @selector(error:);
|
||||
ereason = @"no elements";
|
||||
break;
|
||||
case XML_ERROR_INVALID_TOKEN:
|
||||
sel = @selector(error:);
|
||||
ereason = @"invalid token";
|
||||
break;
|
||||
case XML_ERROR_UNCLOSED_TOKEN:
|
||||
sel = @selector(error:);
|
||||
ereason = @"unclosed token";
|
||||
break;
|
||||
case XML_ERROR_PARTIAL_CHAR:
|
||||
sel = @selector(error:);
|
||||
ereason = @"partial character";
|
||||
break;
|
||||
case XML_ERROR_TAG_MISMATCH:
|
||||
sel = @selector(error:);
|
||||
ereason = @"tag mismatch";
|
||||
break;
|
||||
case XML_ERROR_DUPLICATE_ATTRIBUTE:
|
||||
sel = @selector(error:);
|
||||
ereason = @"duplicate attribute";
|
||||
break;
|
||||
case XML_ERROR_JUNK_AFTER_DOC_ELEMENT:
|
||||
sel = @selector(warning:);
|
||||
ereason = @"junk after document element";
|
||||
break;
|
||||
case XML_ERROR_PARAM_ENTITY_REF:
|
||||
sel = @selector(error:);
|
||||
ereason = @"parameter entity reference";
|
||||
break;
|
||||
case XML_ERROR_UNDEFINED_ENTITY:
|
||||
sel = @selector(error:);
|
||||
ereason = @"undefined entity";
|
||||
break;
|
||||
case XML_ERROR_RECURSIVE_ENTITY_REF:
|
||||
sel = @selector(error:);
|
||||
ereason = @"recursive entity reference";
|
||||
break;
|
||||
case XML_ERROR_ASYNC_ENTITY:
|
||||
sel = @selector(error:);
|
||||
ereason = @"async entity";
|
||||
break;
|
||||
case XML_ERROR_BAD_CHAR_REF:
|
||||
sel = @selector(error:);
|
||||
ereason = @"bad character reference";
|
||||
break;
|
||||
case XML_ERROR_BINARY_ENTITY_REF:
|
||||
sel = @selector(error:);
|
||||
ereason = @"binary entity reference";
|
||||
break;
|
||||
case XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF:
|
||||
sel = @selector(error:);
|
||||
ereason = @"attibute external entity reference";
|
||||
break;
|
||||
case XML_ERROR_MISPLACED_XML_PI:
|
||||
sel = @selector(error:);
|
||||
ereason = @"misplaced processing instruction";
|
||||
break;
|
||||
case XML_ERROR_UNKNOWN_ENCODING:
|
||||
sel = @selector(error:);
|
||||
ereason = @"unknown encoding";
|
||||
break;
|
||||
case XML_ERROR_INCORRECT_ENCODING:
|
||||
sel = @selector(error:);
|
||||
ereason = @"incorrect encoding";
|
||||
break;
|
||||
case XML_ERROR_UNCLOSED_CDATA_SECTION:
|
||||
sel = @selector(error:);
|
||||
ereason = @"unclosed CDATA section";
|
||||
break;
|
||||
case XML_ERROR_EXTERNAL_ENTITY_HANDLING:
|
||||
sel = @selector(error:);
|
||||
ereason = @"external entity handling";
|
||||
break;
|
||||
case XML_ERROR_NOT_STANDALONE:
|
||||
sel = @selector(error:);
|
||||
ereason = @"XML is not standalone";
|
||||
break;
|
||||
case XML_ERROR_UNEXPECTED_STATE:
|
||||
sel = @selector(fatalError:);
|
||||
ereason = @"unexpected status";
|
||||
break;
|
||||
}
|
||||
|
||||
ui = [NSMutableDictionary dictionaryWithCapacity:4];
|
||||
|
||||
if (_sysId) [ui setObject:_sysId forKey:@"systemId"];
|
||||
[ui setObject:self forKey:@"parser"];
|
||||
if (self->expat) {
|
||||
int line;
|
||||
|
||||
if ((line = XML_GetCurrentLineNumber(self->expat)) > 0)
|
||||
[ui setObject:[NSNumber numberWithInt:line] forKey:@"line"];
|
||||
}
|
||||
[ui setObject:[NSNumber numberWithUnsignedInt:_error]
|
||||
forKey:@"expatErrorCode"];
|
||||
|
||||
e = (id)[SaxParseException exceptionWithName:ename
|
||||
reason:ereason
|
||||
userInfo:ui];
|
||||
|
||||
[self->errorHandler performSelector:sel withObject:e];
|
||||
}
|
||||
|
||||
- (void)parseFromSource:(id)_source systemId:(NSString *)_sysId {
|
||||
if (_source == nil) {
|
||||
/* no source ??? */
|
||||
return;
|
||||
}
|
||||
|
||||
if ([_source isKindOfClass:[NSData class]]) {
|
||||
if ([self _setupParser]) {
|
||||
NSAutoreleasePool *pool;
|
||||
|
||||
pool = [[NSAutoreleasePool alloc] init];
|
||||
{
|
||||
int res;
|
||||
|
||||
[self->contentHandler startDocument];
|
||||
res = XML_Parse(self->expat, [_source bytes], [_source length], 1);
|
||||
|
||||
if (res == 0) {
|
||||
[self _reportParseError:XML_GetErrorCode(self->expat)
|
||||
systemId:_sysId];
|
||||
}
|
||||
[self->contentHandler endDocument];
|
||||
}
|
||||
RELEASE(pool);
|
||||
[self _tearDownParser];
|
||||
}
|
||||
}
|
||||
else if ([_source isKindOfClass:[NSString class]]) {
|
||||
[self parseFromSource:
|
||||
[_source dataUsingEncoding:NSUTF8StringEncoding]
|
||||
systemId:_sysId];
|
||||
}
|
||||
else if ([_source isKindOfClass:[NSURL class]]) {
|
||||
if (_sysId == nil)
|
||||
_sysId = [_source absoluteString];
|
||||
|
||||
[self parseFromSource:[_source resourceDataUsingCache:NO]
|
||||
systemId:_sysId];
|
||||
}
|
||||
else
|
||||
[self parseFromSource:[_source stringValue] systemId:_sysId];
|
||||
}
|
||||
|
||||
- (void)parseFromSource:(id)_source {
|
||||
[self parseFromSource:_source systemId:nil];
|
||||
}
|
||||
|
||||
- (void)parseFromSystemId:(NSString *)_sysId {
|
||||
if (![_sysId hasPrefix:@"file:"]) {
|
||||
SaxParseException *e;
|
||||
NSDictionary *ui;
|
||||
NSURL *url;
|
||||
|
||||
if ((url = [NSURL URLWithString:_sysId]))
|
||||
return [self parseFromSource:url systemId:_sysId];
|
||||
|
||||
ui = [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
_sysId ? _sysId : @"<nil>", @"systemID",
|
||||
self, @"parser",
|
||||
nil];
|
||||
|
||||
e = (id)[SaxParseException exceptionWithName:@"SaxIOException"
|
||||
reason:@"can't handle system-id"
|
||||
userInfo:ui];
|
||||
|
||||
[self->errorHandler fatalError:e];
|
||||
return;
|
||||
}
|
||||
else {
|
||||
NSData *data;
|
||||
|
||||
_sysId = [_sysId substringFromIndex:7];
|
||||
|
||||
if ((data = [NSData dataWithContentsOfMappedFile:_sysId]) == nil) {
|
||||
NSLog(@"couldn't load file '%@'", _sysId);
|
||||
return;
|
||||
}
|
||||
|
||||
return [self parseFromSource:data systemId:_sysId];
|
||||
}
|
||||
}
|
||||
|
||||
/* expat */
|
||||
|
||||
static TagTriple splitName(ExpatSaxDriver *self, const char *el) {
|
||||
TagTriple t;
|
||||
char *el_tag;
|
||||
char *buf;
|
||||
unsigned len;
|
||||
|
||||
if ((len = strlen(el)) == 0) {
|
||||
t.raw = @"";
|
||||
t.tag = @"";
|
||||
t.uri = nil;
|
||||
return t;
|
||||
}
|
||||
|
||||
if (len >= self->nameBufLen) {
|
||||
if (self->nameBuf) free(self->nameBuf);
|
||||
self->nameBuf = malloc(len + 8);
|
||||
self->nameBufLen = len + 6;
|
||||
}
|
||||
buf = self->nameBuf;
|
||||
|
||||
strcpy(buf, el);
|
||||
buf[len] = '\0';
|
||||
|
||||
t.raw = uniqueStringUTF8(el);
|
||||
|
||||
if ((el_tag = index(buf, '\t'))) {
|
||||
unsigned idx;
|
||||
|
||||
t.tag = uniqueStringUTF8(el_tag + 1);
|
||||
|
||||
idx = [t.raw rangeOfString:@"\t"].location;
|
||||
t.uri = [[t.raw substringToIndex:idx] copy];
|
||||
}
|
||||
else if ((self->declNS != nil) && ((el_tag = index(buf, ':')) != NULL)) {
|
||||
/* check predefined namespaces ... */
|
||||
NSString *prefix;
|
||||
|
||||
*el_tag = '\0';
|
||||
prefix = uniqueStringUTF8(buf);
|
||||
|
||||
if ((t.uri = [self->declNS objectForKey:prefix])) {
|
||||
t.tag = uniqueStringUTF8(el_tag + 1);
|
||||
t.uri = [t.uri copy];
|
||||
}
|
||||
else {
|
||||
t.uri = nil;
|
||||
t.tag = [t.raw copy];
|
||||
}
|
||||
|
||||
RELEASE(prefix);
|
||||
}
|
||||
else {
|
||||
t.uri = nil;
|
||||
t.tag = [t.raw copy];
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
static void releaseTag(TagTriple t) {
|
||||
RELEASE(t.raw);
|
||||
RELEASE(t.tag);
|
||||
RELEASE(t.uri);
|
||||
}
|
||||
|
||||
static void _startElem(void *data, const char *el, const char **attr) {
|
||||
ExpatSaxDriver *self = (ExpatSaxDriver *)data;
|
||||
TagTriple t;
|
||||
unsigned i;
|
||||
|
||||
t = splitName(self, el);
|
||||
|
||||
/* process attributes */
|
||||
|
||||
if (self->attrs == nil)
|
||||
self->attrs = [[SaxAttributes alloc] init];
|
||||
else
|
||||
[self->attrs clear];
|
||||
if (NSStringClass == Nil) NSStringClass = [NSString class];
|
||||
|
||||
for (i = 0; attr[i] != NULL; i += 2) {
|
||||
TagTriple at;
|
||||
NSString *value;
|
||||
|
||||
at = splitName(self, attr[i]);
|
||||
value = [[NSStringClass alloc] initWithUTF8String:attr[i + 1]];
|
||||
|
||||
[self->attrs
|
||||
addAttribute:at.tag
|
||||
uri:at.uri ? at.uri : t.uri
|
||||
rawName:at.raw
|
||||
type:@"CDATA" value:value];
|
||||
|
||||
releaseTag(at);
|
||||
RELEASE(value);
|
||||
}
|
||||
|
||||
/* notify handler ... */
|
||||
|
||||
[self->contentHandler
|
||||
startElement:t.tag namespace:t.uri rawName:t.raw
|
||||
attributes:self->attrs];
|
||||
|
||||
releaseTag(t);
|
||||
[self->attrs clear];
|
||||
}
|
||||
static void _endElem(void *data, const char *el) {
|
||||
ExpatSaxDriver *self = (ExpatSaxDriver *)data;
|
||||
TagTriple t;
|
||||
|
||||
t = splitName(self, el);
|
||||
|
||||
[self->contentHandler endElement:t.tag namespace:t.uri rawName:t.raw];
|
||||
|
||||
releaseTag(t);
|
||||
}
|
||||
|
||||
static void _startNS(void *data, const char *_prefix, const char *_uri) {
|
||||
ExpatSaxDriver *self = (ExpatSaxDriver *)data;
|
||||
NSString *spre, *suri;
|
||||
|
||||
spre = _prefix ? uniqueStringUTF8(_prefix) : @"";
|
||||
suri = _uri ? uniqueStringUTF8(_uri) : @"";
|
||||
[self->contentHandler startPrefixMapping:spre uri:suri];
|
||||
RELEASE(suri);
|
||||
RELEASE(spre);
|
||||
}
|
||||
static void _endNS(void *data, const char *_prefix) {
|
||||
ExpatSaxDriver *self = (ExpatSaxDriver *)data;
|
||||
NSString *spre;
|
||||
|
||||
spre = _prefix ? uniqueStringUTF8(_prefix) : @"";
|
||||
[self->contentHandler endPrefixMapping:spre];
|
||||
RELEASE(spre);
|
||||
}
|
||||
|
||||
static void _characters(void *_data, const char *chars, int len) {
|
||||
ExpatSaxDriver *self = (ExpatSaxDriver *)_data;
|
||||
void *data, *ts;
|
||||
|
||||
if (len == 0) {
|
||||
unichar c = 0;
|
||||
data = &c;
|
||||
[self->contentHandler characters:data length:len];
|
||||
return;
|
||||
}
|
||||
if (chars == NULL) {
|
||||
[self->contentHandler characters:NULL length:0];
|
||||
return;
|
||||
}
|
||||
|
||||
data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
|
||||
|
||||
if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
|
||||
(void *)&ts, ts + (len * sizeof(unichar)))) {
|
||||
free(data);
|
||||
NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
else {
|
||||
[self->contentHandler characters:data length:(unsigned)(ts - data)];
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
static void _pi(void *_udata, const char *_target, const char *_data) {
|
||||
ExpatSaxDriver *self = (ExpatSaxDriver *)_udata;
|
||||
NSString *target, *data;
|
||||
|
||||
target = uniqueStringUTF8(_target);
|
||||
data = uniqueStringUTF8(_data);
|
||||
[self->contentHandler processingInstruction:target data:data];
|
||||
RELEASE(target);
|
||||
RELEASE(data);
|
||||
}
|
||||
|
||||
static void _comment(void *_data, const char *chars) {
|
||||
ExpatSaxDriver *self = (ExpatSaxDriver *)_data;
|
||||
void *data, *ts;
|
||||
unsigned len;
|
||||
|
||||
len = strlen(chars);
|
||||
|
||||
if (len == 0) {
|
||||
unichar c = 0;
|
||||
data = &c;
|
||||
[self->lexicalHandler comment:data length:0];
|
||||
return;
|
||||
}
|
||||
if (chars == NULL) {
|
||||
[self->lexicalHandler comment:NULL length:0];
|
||||
return;
|
||||
}
|
||||
|
||||
data = ts = calloc(len + 1, sizeof(unichar)); /* GC ?! */
|
||||
|
||||
if (_UTF8ToUTF16((void *)&chars, (void *)(chars + len),
|
||||
(void *)&ts, ts + (len * sizeof(unichar)))) {
|
||||
free(data);
|
||||
NSLog(@"ERROR(%s:%i): couldn't convert UTF8 to UTF16 !",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
else {
|
||||
[self->lexicalHandler comment:data length:(ts - data)];
|
||||
free(data);
|
||||
}
|
||||
}
|
||||
|
||||
static void _startCDATA(void *data) {
|
||||
}
|
||||
static void _endCDATA(void *data) {
|
||||
}
|
||||
|
||||
- (BOOL)_setupParser {
|
||||
[self _tearDownParser];
|
||||
|
||||
if ((self->expat = XML_ParserCreateNS(NULL, '\t')) == NULL) {
|
||||
#if DEBUG
|
||||
NSLog(@"%s: couldn't create expat parser ..", __PRETTY_FUNCTION__);
|
||||
#endif
|
||||
return NO;
|
||||
}
|
||||
|
||||
XML_SetUserData(self->expat, self);
|
||||
XML_SetReturnNSTriplet(self->expat, 1); /* also return NS prefix */
|
||||
|
||||
if (self->contentHandler) {
|
||||
XML_SetElementHandler(self->expat, _startElem, _endElem);
|
||||
XML_SetNamespaceDeclHandler(self->expat, _startNS, _endNS);
|
||||
|
||||
XML_SetCharacterDataHandler(self->expat, _characters);
|
||||
XML_SetProcessingInstructionHandler(self->expat, _pi);
|
||||
|
||||
XML_SetCdataSectionHandler(self->expat, _startCDATA, _endCDATA);
|
||||
}
|
||||
|
||||
if (self->lexicalHandler) {
|
||||
XML_SetCommentHandler(self->expat, _comment);
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)_tearDownParser {
|
||||
if (self->expat) {
|
||||
XML_ParserFree(self->expat);
|
||||
self->expat = NULL;
|
||||
}
|
||||
if (self->nameBuf) {
|
||||
free(self->nameBuf);
|
||||
self->nameBuf = NULL;
|
||||
self->nameBufLen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@end /* ExpatSaxDriver */
|
||||
|
||||
#include "unicode.h"
|
|
@ -0,0 +1,328 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 42;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
ADABC8820700497D00B582C7 /* ExpatSaxDriver.sax in CopyFiles */ = {isa = PBXBuildFile; fileRef = ADDF535406DE6CC800C4E7F8 /* ExpatSaxDriver.sax */; };
|
||||
ADDB0CEE0A792F5100043618 /* libexpat.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = ADDB0CED0A792F5100043618 /* libexpat.dylib */; };
|
||||
ADDF539906DE6EA300C4E7F8 /* bundle-info.plist in Resources */ = {isa = PBXBuildFile; fileRef = ADDF538506DE6EA300C4E7F8 /* bundle-info.plist */; };
|
||||
ADDF539C06DE6EA300C4E7F8 /* COPYING in Resources */ = {isa = PBXBuildFile; fileRef = ADDF538806DE6EA300C4E7F8 /* COPYING */; };
|
||||
ADDF53A506DE6EA300C4E7F8 /* ExpatSaxDriver.m in Sources */ = {isa = PBXBuildFile; fileRef = ADDF539106DE6EA300C4E7F8 /* ExpatSaxDriver.m */; };
|
||||
ADDF53A806DE6EA300C4E7F8 /* README in Resources */ = {isa = PBXBuildFile; fileRef = ADDF539406DE6EA300C4E7F8 /* README */; };
|
||||
ADDF541E06DE710900C4E7F8 /* SaxObjC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADDF541D06DE710900C4E7F8 /* SaxObjC.framework */; };
|
||||
ADDF549306DE714700C4E7F8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = ADDF549206DE714700C4E7F8 /* Foundation.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
ADABC87D0700496800B582C7 /* CopyFiles */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = /tmp/SaxObjCBundledSAXDrivers;
|
||||
dstSubfolderSpec = 0;
|
||||
files = (
|
||||
ADABC8820700497D00B582C7 /* ExpatSaxDriver.sax in CopyFiles */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
ADDB0CED0A792F5100043618 /* libexpat.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libexpat.dylib; path = /usr/local/lib/libexpat.dylib; sourceTree = "<absolute>"; };
|
||||
ADDF535406DE6CC800C4E7F8 /* ExpatSaxDriver.sax */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExpatSaxDriver.sax; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
ADDF535606DE6CC800C4E7F8 /* ExpatSaxDriver-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = "ExpatSaxDriver-Info.plist"; sourceTree = "<group>"; };
|
||||
ADDF538506DE6EA300C4E7F8 /* bundle-info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = "bundle-info.plist"; sourceTree = "<group>"; };
|
||||
ADDF538706DE6EA300C4E7F8 /* common.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = common.h; sourceTree = "<group>"; };
|
||||
ADDF538806DE6EA300C4E7F8 /* COPYING */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = COPYING; sourceTree = "<group>"; };
|
||||
ADDF538A06DE6EA300C4E7F8 /* GNUmakefile */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; indentWidth = 8; path = GNUmakefile; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
|
||||
ADDF538B06DE6EA300C4E7F8 /* GNUmakefile.preamble */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; indentWidth = 8; path = GNUmakefile.preamble; sourceTree = "<group>"; tabWidth = 8; usesTabs = 1; };
|
||||
ADDF539106DE6EA300C4E7F8 /* ExpatSaxDriver.m */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.objc; path = ExpatSaxDriver.m; sourceTree = "<group>"; };
|
||||
ADDF539406DE6EA300C4E7F8 /* README */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = README; sourceTree = "<group>"; };
|
||||
ADDF539706DE6EA300C4E7F8 /* unicode.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 2; lastKnownFileType = sourcecode.c.h; path = unicode.h; sourceTree = "<group>"; };
|
||||
ADDF541D06DE710900C4E7F8 /* SaxObjC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SaxObjC.framework; path = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks/Wrapper/SaxObjC.framework"; sourceTree = "<absolute>"; };
|
||||
ADDF549206DE714700C4E7F8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
|
||||
ADECEE4F078A4DB900B7221D /* fhs.make */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 5; indentWidth = 8; path = fhs.make; sourceTree = "<group>"; tabWidth = 8; };
|
||||
ADECEE50078A4DB900B7221D /* GNUmakefile.postamble */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 5; indentWidth = 8; path = GNUmakefile.postamble; sourceTree = "<group>"; tabWidth = 8; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
ADDF535206DE6CC800C4E7F8 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
ADDF541E06DE710900C4E7F8 /* SaxObjC.framework in Frameworks */,
|
||||
ADDF549306DE714700C4E7F8 /* Foundation.framework in Frameworks */,
|
||||
ADDB0CEE0A792F5100043618 /* libexpat.dylib in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
ADDF534406DE6C5300C4E7F8 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ADDB0CED0A792F5100043618 /* libexpat.dylib */,
|
||||
ADDF539406DE6EA300C4E7F8 /* README */,
|
||||
ADDF538806DE6EA300C4E7F8 /* COPYING */,
|
||||
ADDF538506DE6EA300C4E7F8 /* bundle-info.plist */,
|
||||
ADDF53AF06DE6EBD00C4E7F8 /* Makefiles */,
|
||||
ADDF53B206DE6ECF00C4E7F8 /* Headers */,
|
||||
ADDF53B506DE6ED700C4E7F8 /* Classes */,
|
||||
ADDF53C606DE6EE300C4E7F8 /* Resources */,
|
||||
ADDF535506DE6CC800C4E7F8 /* Products */,
|
||||
ADDF53CE06DE6FC500C4E7F8 /* Linked Frameworks */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ADDF535506DE6CC800C4E7F8 /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ADDF535406DE6CC800C4E7F8 /* ExpatSaxDriver.sax */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ADDF53AF06DE6EBD00C4E7F8 /* Makefiles */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ADDF538A06DE6EA300C4E7F8 /* GNUmakefile */,
|
||||
ADDF538B06DE6EA300C4E7F8 /* GNUmakefile.preamble */,
|
||||
ADECEE50078A4DB900B7221D /* GNUmakefile.postamble */,
|
||||
ADECEE4F078A4DB900B7221D /* fhs.make */,
|
||||
);
|
||||
name = Makefiles;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ADDF53B206DE6ECF00C4E7F8 /* Headers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ADDF539706DE6EA300C4E7F8 /* unicode.h */,
|
||||
);
|
||||
name = Headers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ADDF53B506DE6ED700C4E7F8 /* Classes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ADDF538706DE6EA300C4E7F8 /* common.h */,
|
||||
ADDF539106DE6EA300C4E7F8 /* ExpatSaxDriver.m */,
|
||||
);
|
||||
name = Classes;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ADDF53C606DE6EE300C4E7F8 /* Resources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ADDF535606DE6CC800C4E7F8 /* ExpatSaxDriver-Info.plist */,
|
||||
);
|
||||
name = Resources;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
ADDF53CE06DE6FC500C4E7F8 /* Linked Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
ADDF549206DE714700C4E7F8 /* Foundation.framework */,
|
||||
ADDF541D06DE710900C4E7F8 /* SaxObjC.framework */,
|
||||
);
|
||||
name = "Linked Frameworks";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
ADDF535306DE6CC800C4E7F8 /* ExpatSaxDriver */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = ADA0769B0857286600993825 /* Build configuration list for PBXNativeTarget "ExpatSaxDriver" */;
|
||||
buildPhases = (
|
||||
ADDF535006DE6CC800C4E7F8 /* Resources */,
|
||||
ADDF535106DE6CC800C4E7F8 /* Sources */,
|
||||
ADDF535206DE6CC800C4E7F8 /* Frameworks */,
|
||||
ADABC87D0700496800B582C7 /* CopyFiles */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = ExpatSaxDriver;
|
||||
productName = ExpatSaxDriver;
|
||||
productReference = ADDF535406DE6CC800C4E7F8 /* ExpatSaxDriver.sax */;
|
||||
productType = "com.apple.product-type.bundle";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
ADDF534806DE6C5400C4E7F8 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
buildConfigurationList = ADA0769F0857286600993825 /* Build configuration list for PBXProject "ExpatSaxDriver" */;
|
||||
hasScannedForEncodings = 0;
|
||||
mainGroup = ADDF534406DE6C5300C4E7F8;
|
||||
productRefGroup = ADDF535506DE6CC800C4E7F8 /* Products */;
|
||||
projectDirPath = "";
|
||||
targets = (
|
||||
ADDF535306DE6CC800C4E7F8 /* ExpatSaxDriver */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
ADDF535006DE6CC800C4E7F8 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
ADDF539906DE6EA300C4E7F8 /* bundle-info.plist in Resources */,
|
||||
ADDF539C06DE6EA300C4E7F8 /* COPYING in Resources */,
|
||||
ADDF53A806DE6EA300C4E7F8 /* README in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
ADDF535106DE6CC800C4E7F8 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
ADDF53A506DE6EA300C4E7F8 /* ExpatSaxDriver.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
ADA0769C0857286600993825 /* Development */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
COPY_PHASE_STRIP = NO;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = common.h;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"APPLE_RUNTIME=1",
|
||||
"NeXT_Foundation_LIBRARY=1",
|
||||
"COCOA_Foundation_LIBRARY=1",
|
||||
"NeXT_RUNTIME=1",
|
||||
"COMPILE_AS_FRAMEWORK=1",
|
||||
"DEBUG=1",
|
||||
);
|
||||
INFOPLIST_FILE = "ExpatSaxDriver-Info.plist";
|
||||
INSTALL_PATH = "$(USER_LIBRARY_DIR)/SaxDrivers";
|
||||
OTHER_CFLAGS = "-I/usr/include/libxml2";
|
||||
OTHER_LDFLAGS = "-lxml2";
|
||||
PRODUCT_NAME = ExpatSaxDriver;
|
||||
WARNING_CFLAGS = "-Wmost";
|
||||
WRAPPER_EXTENSION = sax;
|
||||
ZERO_LINK = YES;
|
||||
};
|
||||
name = Development;
|
||||
};
|
||||
ADA0769D0857286600993825 /* Wrapper */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEPLOYMENT_LOCATION = NO;
|
||||
DEPLOYMENT_POSTPROCESSING = YES;
|
||||
DSTROOT = /;
|
||||
FRAMEWORK_SEARCH_PATHS = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = 3;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = common.h;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"APPLE_RUNTIME=1",
|
||||
"NeXT_Foundation_LIBRARY=1",
|
||||
"COCOA_Foundation_LIBRARY=1",
|
||||
"NeXT_RUNTIME=1",
|
||||
"COMPILE_AS_FRAMEWORK=1",
|
||||
);
|
||||
INFOPLIST_FILE = "ExpatSaxDriver-Info.plist";
|
||||
INSTALL_PATH = "$(USER_LIBRARY_DIR)/SaxDrivers";
|
||||
OTHER_CFLAGS = "-I/usr/include/libxml2";
|
||||
OTHER_LDFLAGS = "-lxml2";
|
||||
PRODUCT_NAME = ExpatSaxDriver;
|
||||
SKIP_INSTALL = YES;
|
||||
SYMROOT = "$(USER_LIBRARY_DIR)/EmbeddedFrameworks";
|
||||
TEMP_DIR = "$(SYMROOT)/$(PROJECT_NAME).build";
|
||||
UNSTRIPPED_PRODUCT = NO;
|
||||
WARNING_CFLAGS = "-Wmost";
|
||||
WRAPPER_EXTENSION = sax;
|
||||
ZERO_LINK = NO;
|
||||
};
|
||||
name = Wrapper;
|
||||
};
|
||||
ADA0769E0857286600993825 /* Default */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
FRAMEWORK_SEARCH_PATHS = "$(LOCAL_LIBRARY_DIR)/Frameworks";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||
GCC_PREFIX_HEADER = common.h;
|
||||
INFOPLIST_FILE = "ExpatSaxDriver-Info.plist";
|
||||
INSTALL_PATH = "$(USER_LIBRARY_DIR)/SaxDrivers";
|
||||
OTHER_CFLAGS = "-I/usr/include/libxml2";
|
||||
OTHER_LDFLAGS = "-lxml2";
|
||||
PRODUCT_NAME = ExpatSaxDriver;
|
||||
WARNING_CFLAGS = "-Wmost";
|
||||
WRAPPER_EXTENSION = sax;
|
||||
};
|
||||
name = Default;
|
||||
};
|
||||
ADA076A00857286600993825 /* Development */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
};
|
||||
name = Development;
|
||||
};
|
||||
ADA076A10857286600993825 /* Wrapper */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = (
|
||||
ppc,
|
||||
i386,
|
||||
);
|
||||
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
|
||||
};
|
||||
name = Wrapper;
|
||||
};
|
||||
ADA076A20857286600993825 /* Default */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
};
|
||||
name = Default;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
ADA0769B0857286600993825 /* Build configuration list for PBXNativeTarget "ExpatSaxDriver" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
ADA0769C0857286600993825 /* Development */,
|
||||
ADA0769D0857286600993825 /* Wrapper */,
|
||||
ADA0769E0857286600993825 /* Default */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Default;
|
||||
};
|
||||
ADA0769F0857286600993825 /* Build configuration list for PBXProject "ExpatSaxDriver" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
ADA076A00857286600993825 /* Development */,
|
||||
ADA076A10857286600993825 /* Wrapper */,
|
||||
ADA076A20857286600993825 /* Default */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Default;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = ADDF534806DE6C5400C4E7F8 /* Project object */;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,42 @@
|
|||
# GNUstep makefile
|
||||
|
||||
-include ../../config.make
|
||||
include $(GNUSTEP_MAKEFILES)/common.make
|
||||
-include ../../Version
|
||||
-include ./Version
|
||||
|
||||
BUNDLE_NAME = ExpatSaxDriver
|
||||
BUNDLE_EXTENSION = .sax
|
||||
BUNDLE_INSTALL_DIR = $(GNUSTEP_INSTALLATION_DIR)/Library/SaxDrivers-$(MAJOR_VERSION).$(MINOR_VERSION)/
|
||||
|
||||
ExpatSaxDriver_OBJC_FILES = \
|
||||
ExpatSaxDriver.m \
|
||||
|
||||
ExpatSaxDriver_BUNDLE_LIBS += -lSaxObjC -lexpat
|
||||
|
||||
ExpatSaxDriver_RESOURCE_FILES = bundle-info.plist
|
||||
|
||||
ADDITIONAL_INCLUDE_DIRS += -I/usr/local/include
|
||||
|
||||
ifneq ($(GNUSTEP_BUILD_DIR),)
|
||||
ADDITIONAL_LIB_DIRS += \
|
||||
-L$(GNUSTEP_BUILD_DIR)/../SaxObjC/$(GNUSTEP_OBJ_DIR_NAME)
|
||||
else
|
||||
ADDITIONAL_LIB_DIRS += -L../SaxObjC/$(GNUSTEP_OBJ_DIR)
|
||||
endif
|
||||
|
||||
-include GNUmakefile.preamble
|
||||
include $(GNUSTEP_MAKEFILES)/bundle.make
|
||||
-include GNUmakefile.postamble
|
||||
|
||||
ifneq ($(GNUSTEP_BUILD_DIR),)
|
||||
after-all ::
|
||||
@(cp bundle-info.plist \
|
||||
$(GNUSTEP_BUILD_DIR)/$(BUNDLE_NAME)$(BUNDLE_EXTENSION))
|
||||
else
|
||||
after-all ::
|
||||
@(cd $(BUNDLE_NAME)$(BUNDLE_EXTENSION);\
|
||||
cp ../bundle-info.plist .)
|
||||
endif
|
||||
|
||||
SYSTEM_LIB_DIR += -L/usr/local/lib -L/usr/lib
|
|
@ -0,0 +1,11 @@
|
|||
ExpatSaxDriver
|
||||
==============
|
||||
|
||||
This directory contains the sources for a SAX driver bundle which works on top
|
||||
of the Expat XML processing library.
|
||||
|
||||
NOTE: this driver is outdated now, hence it's in the recycler. I
|
||||
revived it for some test against the libxmlSAXDriver which nevertheless
|
||||
showed that expat consumes way less memory and seems to be much faster
|
||||
when parsing "large" (in my case a 9MB XML plist) XML files than
|
||||
libxml2.
|
|
@ -0,0 +1,3 @@
|
|||
# version
|
||||
|
||||
SUBMINOR_VERSION:=0
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
CVS = "$Id: bundle-info.plist 4 2004-08-20 17:04:31Z helge $";
|
||||
//bundleHandler = NSObject;
|
||||
|
||||
requires = {
|
||||
bundleManagerVersion = 1;
|
||||
classes = (
|
||||
{ name = NSObject; }
|
||||
);
|
||||
};
|
||||
|
||||
provides = {
|
||||
SAXDrivers = (
|
||||
{
|
||||
name = ExpatSaxDriver;
|
||||
sourceTypes = ( "text/xml" );
|
||||
},
|
||||
);
|
||||
classes = (
|
||||
{ name = ExpatSaxDriver; },
|
||||
);
|
||||
};
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
Copyright (C) 2000-2003 SKYRIX Software AG
|
||||
|
||||
This file is part of OGo
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
// $Id: common.h 1 2004-08-20 10:08:27Z znek $
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
Copyright (C) 2000-2003 SKYRIX Software AG
|
||||
|
||||
This file is part of OGo
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
/* Unicode support */
|
||||
|
||||
typedef unsigned long UCS4;
|
||||
typedef unsigned short UCS2;
|
||||
typedef unsigned short UTF16;
|
||||
typedef unsigned char UTF8;
|
||||
#define unichar UTF16
|
||||
|
||||
static const int halfShift = 10;
|
||||
static const UCS4 halfBase = 0x0010000UL;
|
||||
static const UCS4 halfMask = 0x3FFUL;
|
||||
static const UCS4 kSurrogateHighStart = 0xD800UL;
|
||||
static const UCS4 kSurrogateHighEnd = 0xDBFFUL;
|
||||
static const UCS4 kSurrogateLowStart = 0xDC00UL;
|
||||
static const UCS4 kSurrogateLowEnd = 0xDFFFUL;
|
||||
|
||||
static const UCS4 kReplacementCharacter = 0x0000FFFDUL;
|
||||
static const UCS4 kMaximumUCS2 = 0x0000FFFFUL;
|
||||
static const UCS4 kMaximumUTF16 = 0x0010FFFFUL;
|
||||
static const UCS4 kMaximumUCS4 = 0x7FFFFFFFUL;
|
||||
|
||||
static UCS4 offsetsFromUTF8[6] = {
|
||||
0x00000000UL, 0x00003080UL, 0x000E2080UL,
|
||||
0x03C82080UL, 0xFA082080UL, 0x82082080UL
|
||||
};
|
||||
static char bytesFromUTF8[256] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||
};
|
||||
|
||||
static int
|
||||
_UTF8ToUTF16(unsigned char **sourceStart, unsigned char *sourceEnd,
|
||||
unichar **targetStart, const unichar *targetEnd)
|
||||
{
|
||||
int result = 0;
|
||||
register UTF8 *source = *sourceStart;
|
||||
register UTF16 *target = *targetStart;
|
||||
|
||||
while (source < sourceEnd) {
|
||||
register UCS4 ch = 0;
|
||||
register unsigned short extraBytesToWrite = bytesFromUTF8[*source];
|
||||
|
||||
if (source + extraBytesToWrite > sourceEnd) {
|
||||
result = 1; break;
|
||||
};
|
||||
switch(extraBytesToWrite) { /* note: code falls through cases! */
|
||||
case 5: ch += *source++; ch <<= 6;
|
||||
case 4: ch += *source++; ch <<= 6;
|
||||
case 3: ch += *source++; ch <<= 6;
|
||||
case 2: ch += *source++; ch <<= 6;
|
||||
case 1: ch += *source++; ch <<= 6;
|
||||
case 0: ch += *source++;
|
||||
};
|
||||
ch -= offsetsFromUTF8[extraBytesToWrite];
|
||||
|
||||
if (target >= targetEnd) {
|
||||
result = 2; break;
|
||||
};
|
||||
if (ch <= kMaximumUCS2) {
|
||||
*target++ = ch;
|
||||
} else if (ch > kMaximumUTF16) {
|
||||
*target++ = kReplacementCharacter;
|
||||
} else {
|
||||
if (target + 1 >= targetEnd) {
|
||||
result = 2; break;
|
||||
};
|
||||
ch -= halfBase;
|
||||
*target++ = (ch >> halfShift) + kSurrogateHighStart;
|
||||
*target++ = (ch & halfMask) + kSurrogateLowStart;
|
||||
};
|
||||
};
|
||||
*sourceStart = source;
|
||||
*targetStart = target;
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,482 @@
|
|||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
[This is the first released version of the library GPL. It is
|
||||
numbered 2 because it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
Licenses are intended to guarantee your freedom to share and change
|
||||
free software--to make sure the software is free for all its users.
|
||||
|
||||
This license, the Library General Public License, applies to some
|
||||
specially designated Free Software Foundation software, and to any
|
||||
other libraries whose authors decide to use it. You can use it for
|
||||
your libraries, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if
|
||||
you distribute copies of the library, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of the library, whether gratis
|
||||
or for a fee, you must give the recipients all the rights that we gave
|
||||
you. You must make sure that they, too, receive or can get the source
|
||||
code. If you link a program with the library, you must provide
|
||||
complete object files to the recipients so that they can relink them
|
||||
with the library, after making changes to the library and recompiling
|
||||
it. And you must show them these terms so they know their rights.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright
|
||||
the library, and (2) offer you this license which gives you legal
|
||||
permission to copy, distribute and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
library. If the library is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original
|
||||
version, so that any problems introduced by others will not reflect on
|
||||
the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that companies distributing free
|
||||
software will individually obtain patent licenses, thus in effect
|
||||
transforming the program into proprietary software. To prevent this,
|
||||
we have made it clear that any patent must be licensed for everyone's
|
||||
free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary
|
||||
GNU General Public License, which was designed for utility programs. This
|
||||
license, the GNU Library General Public License, applies to certain
|
||||
designated libraries. This license is quite different from the ordinary
|
||||
one; be sure to read it in full, and don't assume that anything in it is
|
||||
the same as in the ordinary license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that
|
||||
they blur the distinction we usually make between modifying or adding to a
|
||||
program and simply using it. Linking a program with a library, without
|
||||
changing the library, is in some sense simply using the library, and is
|
||||
analogous to running a utility program or application program. However, in
|
||||
a textual and legal sense, the linked executable is a combined work, a
|
||||
derivative of the original library, and the ordinary General Public License
|
||||
treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General
|
||||
Public License for libraries did not effectively promote software
|
||||
sharing, because most developers did not use the libraries. We
|
||||
concluded that weaker conditions might promote sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the
|
||||
users of those programs of all benefit from the free status of the
|
||||
libraries themselves. This Library General Public License is intended to
|
||||
permit developers of non-free programs to use free libraries, while
|
||||
preserving your freedom as a user of such programs to change the free
|
||||
libraries that are incorporated in them. (We have not seen how to achieve
|
||||
this as regards changes in header files, but we have achieved it as regards
|
||||
changes in the actual functions of the Library.) The hope is that this
|
||||
will lead to faster development of free libraries.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow. Pay close attention to the difference between a
|
||||
"work based on the library" and a "work that uses the library". The
|
||||
former contains code derived from the library, while the latter only
|
||||
works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary
|
||||
General Public License rather than by this special one.
|
||||
|
||||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which
|
||||
contains a notice placed by the copyright holder or other authorized
|
||||
party saying it may be distributed under the terms of this Library
|
||||
General Public License (also called "this License"). Each licensee is
|
||||
addressed as "you".
|
||||
|
||||
A "library" means a collection of software functions and/or data
|
||||
prepared so as to be conveniently linked with application programs
|
||||
(which use some of those functions and data) to form executables.
|
||||
|
||||
The "Library", below, refers to any such software library or work
|
||||
which has been distributed under these terms. A "work based on the
|
||||
Library" means either the Library or any derivative work under
|
||||
copyright law: that is to say, a work containing the Library or a
|
||||
portion of it, either verbatim or with modifications and/or translated
|
||||
straightforwardly into another language. (Hereinafter, translation is
|
||||
included without limitation in the term "modification".)
|
||||
|
||||
"Source code" for a work means the preferred form of the work for
|
||||
making modifications to it. For a library, complete source code means
|
||||
all the source code for all modules it contains, plus any associated
|
||||
interface definition files, plus the scripts used to control compilation
|
||||
and installation of the library.
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running a program using the Library is not restricted, and output from
|
||||
such a program is covered only if its contents constitute a work based
|
||||
on the Library (independent of the use of the Library in a tool for
|
||||
writing it). Whether that is true depends on what the Library does
|
||||
and what the program that uses the Library does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's
|
||||
complete source code as you receive it, in any medium, provided that
|
||||
you conspicuously and appropriately publish on each copy an
|
||||
appropriate copyright notice and disclaimer of warranty; keep intact
|
||||
all the notices that refer to this License and to the absence of any
|
||||
warranty; and distribute a copy of this License along with the
|
||||
Library.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy,
|
||||
and you may at your option offer warranty protection in exchange for a
|
||||
fee.
|
||||
|
||||
2. You may modify your copy or copies of the Library or any portion
|
||||
of it, thus forming a work based on the Library, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) The modified work must itself be a software library.
|
||||
|
||||
b) You must cause the files modified to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
c) You must cause the whole of the work to be licensed at no
|
||||
charge to all third parties under the terms of this License.
|
||||
|
||||
d) If a facility in the modified Library refers to a function or a
|
||||
table of data to be supplied by an application program that uses
|
||||
the facility, other than as an argument passed when the facility
|
||||
is invoked, then you must make a good faith effort to ensure that,
|
||||
in the event an application does not supply such function or
|
||||
table, the facility still operates, and performs whatever part of
|
||||
its purpose remains meaningful.
|
||||
|
||||
(For example, a function in a library to compute square roots has
|
||||
a purpose that is entirely well-defined independent of the
|
||||
application. Therefore, Subsection 2d requires that any
|
||||
application-supplied function or table used by this function must
|
||||
be optional: if the application does not supply it, the square
|
||||
root function must still compute square roots.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Library,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Library, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote
|
||||
it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Library.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Library
|
||||
with the Library (or with a work based on the Library) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public
|
||||
License instead of this License to a given copy of the Library. To do
|
||||
this, you must alter all the notices that refer to this License, so
|
||||
that they refer to the ordinary GNU General Public License, version 2,
|
||||
instead of to this License. (If a newer version than version 2 of the
|
||||
ordinary GNU General Public License has appeared, then you can specify
|
||||
that version instead if you wish.) Do not make any other change in
|
||||
these notices.
|
||||
|
||||
Once this change is made in a given copy, it is irreversible for
|
||||
that copy, so the ordinary GNU General Public License applies to all
|
||||
subsequent copies and derivative works made from that copy.
|
||||
|
||||
This option is useful when you wish to copy part of the code of
|
||||
the Library into a program that is not a library.
|
||||
|
||||
4. You may copy and distribute the Library (or a portion or
|
||||
derivative of it, under Section 2) in object code or executable form
|
||||
under the terms of Sections 1 and 2 above provided that you accompany
|
||||
it with the complete corresponding machine-readable source code, which
|
||||
must be distributed under the terms of Sections 1 and 2 above on a
|
||||
medium customarily used for software interchange.
|
||||
|
||||
If distribution of object code is made by offering access to copy
|
||||
from a designated place, then offering equivalent access to copy the
|
||||
source code from the same place satisfies the requirement to
|
||||
distribute the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
5. A program that contains no derivative of any portion of the
|
||||
Library, but is designed to work with the Library by being compiled or
|
||||
linked with it, is called a "work that uses the Library". Such a
|
||||
work, in isolation, is not a derivative work of the Library, and
|
||||
therefore falls outside the scope of this License.
|
||||
|
||||
However, linking a "work that uses the Library" with the Library
|
||||
creates an executable that is a derivative of the Library (because it
|
||||
contains portions of the Library), rather than a "work that uses the
|
||||
library". The executable is therefore covered by this License.
|
||||
Section 6 states terms for distribution of such executables.
|
||||
|
||||
When a "work that uses the Library" uses material from a header file
|
||||
that is part of the Library, the object code for the work may be a
|
||||
derivative work of the Library even though the source code is not.
|
||||
Whether this is true is especially significant if the work can be
|
||||
linked without the Library, or if the work is itself a library. The
|
||||
threshold for this to be true is not precisely defined by law.
|
||||
|
||||
If such an object file uses only numerical parameters, data
|
||||
structure layouts and accessors, and small macros and small inline
|
||||
functions (ten lines or less in length), then the use of the object
|
||||
file is unrestricted, regardless of whether it is legally a derivative
|
||||
work. (Executables containing this object code plus portions of the
|
||||
Library will still fall under Section 6.)
|
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may
|
||||
distribute the object code for the work under the terms of Section 6.
|
||||
Any executables containing that work also fall under Section 6,
|
||||
whether or not they are linked directly with the Library itself.
|
||||
|
||||
6. As an exception to the Sections above, you may also compile or
|
||||
link a "work that uses the Library" with the Library to produce a
|
||||
work containing portions of the Library, and distribute that work
|
||||
under terms of your choice, provided that the terms permit
|
||||
modification of the work for the customer's own use and reverse
|
||||
engineering for debugging such modifications.
|
||||
|
||||
You must give prominent notice with each copy of the work that the
|
||||
Library is used in it and that the Library and its use are covered by
|
||||
this License. You must supply a copy of this License. If the work
|
||||
during execution displays copyright notices, you must include the
|
||||
copyright notice for the Library among them, as well as a reference
|
||||
directing the user to the copy of this License. Also, you must do one
|
||||
of these things:
|
||||
|
||||
a) Accompany the work with the complete corresponding
|
||||
machine-readable source code for the Library including whatever
|
||||
changes were used in the work (which must be distributed under
|
||||
Sections 1 and 2 above); and, if the work is an executable linked
|
||||
with the Library, with the complete machine-readable "work that
|
||||
uses the Library", as object code and/or source code, so that the
|
||||
user can modify the Library and then relink to produce a modified
|
||||
executable containing the modified Library. (It is understood
|
||||
that the user who changes the contents of definitions files in the
|
||||
Library will not necessarily be able to recompile the application
|
||||
to use the modified definitions.)
|
||||
|
||||
b) Accompany the work with a written offer, valid for at
|
||||
least three years, to give the same user the materials
|
||||
specified in Subsection 6a, above, for a charge no more
|
||||
than the cost of performing this distribution.
|
||||
|
||||
c) If distribution of the work is made by offering access to copy
|
||||
from a designated place, offer equivalent access to copy the above
|
||||
specified materials from the same place.
|
||||
|
||||
d) Verify that the user has already received a copy of these
|
||||
materials or that you have already sent this user a copy.
|
||||
|
||||
For an executable, the required form of the "work that uses the
|
||||
Library" must include any data and utility programs needed for
|
||||
reproducing the executable from it. However, as a special exception,
|
||||
the source code distributed need not include anything that is normally
|
||||
distributed (in either source or binary form) with the major
|
||||
components (compiler, kernel, and so on) of the operating system on
|
||||
which the executable runs, unless that component itself accompanies
|
||||
the executable.
|
||||
|
||||
It may happen that this requirement contradicts the license
|
||||
restrictions of other proprietary libraries that do not normally
|
||||
accompany the operating system. Such a contradiction means you cannot
|
||||
use both them and the Library together in an executable that you
|
||||
distribute.
|
||||
|
||||
7. You may place library facilities that are a work based on the
|
||||
Library side-by-side in a single library together with other library
|
||||
facilities not covered by this License, and distribute such a combined
|
||||
library, provided that the separate distribution of the work based on
|
||||
the Library and of the other library facilities is otherwise
|
||||
permitted, and provided that you do these two things:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work
|
||||
based on the Library, uncombined with any other library
|
||||
facilities. This must be distributed under the terms of the
|
||||
Sections above.
|
||||
|
||||
b) Give prominent notice with the combined library of the fact
|
||||
that part of it is a work based on the Library, and explaining
|
||||
where to find the accompanying uncombined form of the same work.
|
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute
|
||||
the Library except as expressly provided under this License. Any
|
||||
attempt otherwise to copy, modify, sublicense, link with, or
|
||||
distribute the Library is void, and will automatically terminate your
|
||||
rights under this License. However, parties who have received copies,
|
||||
or rights, from you under this License will not have their licenses
|
||||
terminated so long as such parties remain in full compliance.
|
||||
|
||||
9. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Library or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Library (or any work based on the
|
||||
Library), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Library or works based on it.
|
||||
|
||||
10. Each time you redistribute the Library (or any work based on the
|
||||
Library), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute, link with or modify the Library
|
||||
subject to these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Library at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Library by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Library.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under any
|
||||
particular circumstance, the balance of the section is intended to apply,
|
||||
and the section as a whole is intended to apply in other circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
12. If the distribution and/or use of the Library is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Library under this License may add
|
||||
an explicit geographical distribution limitation excluding those countries,
|
||||
so that distribution is permitted only in or among countries not thus
|
||||
excluded. In such case, this License incorporates the limitation as if
|
||||
written in the body of this License.
|
||||
|
||||
13. The Free Software Foundation may publish revised and/or new
|
||||
versions of the Library General Public License from time to time.
|
||||
Such new versions will be similar in spirit to the present version,
|
||||
but may differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Library
|
||||
specifies a version number of this License which applies to it and
|
||||
"any later version", you have the option of following the terms and
|
||||
conditions either of that version or of any later version published by
|
||||
the Free Software Foundation. If the Library does not specify a
|
||||
license version number, you may choose any version ever published by
|
||||
the Free Software Foundation.
|
||||
|
||||
14. If you wish to incorporate parts of the Library into other free
|
||||
programs whose distribution conditions are incompatible with these,
|
||||
write to the author to ask for permission. For software which is
|
||||
copyrighted by the Free Software Foundation, write to the Free
|
||||
Software Foundation; we sometimes make exceptions for this. Our
|
||||
decision will be guided by the two goals of preserving the free status
|
||||
of all derivatives of our free software and of promoting the sharing
|
||||
and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
|
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
|
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
|
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
|
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
|
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
|
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
|
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
|
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
|
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
|
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
|
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
|
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
|
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
|
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Appendix: How to Apply These Terms to Your New Libraries
|
||||
|
||||
If you develop a new library, and you want it to be of the greatest
|
||||
possible use to the public, we recommend making it free software that
|
||||
everyone can redistribute and change. You can do so by permitting
|
||||
redistribution under these terms (or, alternatively, under the terms of the
|
||||
ordinary General Public License).
|
||||
|
||||
To apply these terms, attach the following notices to the library. It is
|
||||
safest to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least the
|
||||
"copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the library's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
|
||||
MA 02111-1307, USA
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the library, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the
|
||||
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1990
|
||||
Ty Coon, President of Vice
|
||||
|
||||
That's all there is to it!
|
|
@ -0,0 +1,4 @@
|
|||
Copyright (C) 2004 SKYRIX Software AG
|
||||
|
||||
|
||||
Contact: info@skyrix.com
|
|
@ -0,0 +1,334 @@
|
|||
2007-09-27 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* moved GCS out of SOPE, should be readded to the respective SOGo
|
||||
version
|
||||
|
||||
2007-08-29 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* EOQualifier+GCS.m: rewrote comparison code, now uses UPPER instead of
|
||||
the PostgreSQL specific ILIKE. Fixes OGo bug #1906 (v4.7.49)
|
||||
|
||||
2007-07-20 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GCSFolderManager.m: added 'some' rollback after an error (v4.7.48)
|
||||
|
||||
2007-07-20 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* GCSFolderManager.m: fixed a bug in last check, DROP TABLE is allowed
|
||||
to fail in the given context (bug #1883) (v4.7.47)
|
||||
|
||||
2007-07-11 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GCSFolderManager.m: added some error checking, plenty of open ends
|
||||
pending (eg folder creation not wrapped in a transaction) (v4.7.46)
|
||||
|
||||
2007-06-29 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* GCSFolderManager.m: fixed folder creation to populate empty path
|
||||
fields with NULLs (OGo bug #1883) (v4.7.45)
|
||||
|
||||
2007-04-25 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* GCSFolder.[hm]: added methods to delete ACL records (OGo bug #1866)
|
||||
(v4.7.44)
|
||||
|
||||
2007-04-22 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GCSChannelManager.m: improved error log (v4.7.43)
|
||||
|
||||
2007-04-17 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* fixed a few GNUstep compilation warnings (v4.7.42)
|
||||
|
||||
2007-03-21 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* GCSFolder.[hm], GCSFolderManager.[hm]: added ability to create and
|
||||
delete GCS folders programmatically (OGo bug #1850) (v4.7.41)
|
||||
|
||||
2007-02-12 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GCSFolder.m: fixed a gnustep-base compilation warning (v4.7.40)
|
||||
|
||||
2007-02-09 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* use -errorWithFormat:, fixed a few logging crashes (incomplete format
|
||||
strings) (v4.5.39)
|
||||
|
||||
2007-02-08 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* GCSFolder.m: added a gnustep-base hack to properly format bool
|
||||
numbers for SQL. Base returns YES or NO in -stringValue while
|
||||
libFoundation/NGExt returns 0 or 1 (v4.5.39)
|
||||
|
||||
2007-01-15 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* GCSFolder.[hm], GCSFolderManager.m: added support for content table
|
||||
ACLs (v4.5.38)
|
||||
|
||||
2006-08-31 Wolfgang Sourdeau <WSourdeau@Inverse.CA>
|
||||
|
||||
* EOQualifier+GCS.m: added support for OR qualifiers and for case
|
||||
insensitive-like qualifiers on PostgreSQL (v4.5.37)
|
||||
|
||||
2006-07-04 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* use %p for pointer formats, fixed gcc 4.1 warnings (v4.5.36)
|
||||
|
||||
2005-08-16 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GNUmakefile, GNUmakefile.preamble: added OSX framework compilation
|
||||
(v4.5.35)
|
||||
|
||||
2005-07-23 Sebastian Reitenbach <reitenbach@rapideye.de>
|
||||
|
||||
* GNUmakefile.preamble: added OpenBSD linking flags (v4.5.34)
|
||||
|
||||
2005-07-13 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GCSFolder.h: added -versionOfContentWithName: method to header file
|
||||
(v4.5.33)
|
||||
|
||||
* GCSFolder.m: return a proper exception if the extractor was unable to
|
||||
create a quickrow for a given content object (v4.5.32)
|
||||
|
||||
* GCSFolder.m: added -writeContent:toName:baseVersion: to support
|
||||
consistent update operations (eg using etags), properly increase
|
||||
content object version on update operations (v4.5.31)
|
||||
|
||||
* GCSFolderManager.m, GCSFolder.m: changed not to use EOF
|
||||
attribute-name 'beautification', eg 'c_name' will stay 'c_name'
|
||||
instead of being transformed into 'cName' (v4.5.30)
|
||||
|
||||
2005-07-11 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* GCSFolderManager.m: added automatic discovery of folder types by
|
||||
scanning for .ocs files (v4.5.29)
|
||||
|
||||
2005-04-25 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* fixed gcc 4.0 warnings (v4.5.28)
|
||||
|
||||
2005-03-21 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* GNUmakefile: added FHS support (v4.5.27)
|
||||
|
||||
2005-03-20 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* moved OGoContentStore as GDLContentStore into sope-gdl1, removed
|
||||
dependencies on NGiCal and removed some SOGo specific things
|
||||
(v4.5.26)
|
||||
|
||||
2005-03-07 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* appointment.ocs: added missing 'partstates' field (v0.9.25)
|
||||
|
||||
2005-03-04 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* v0.9.24
|
||||
|
||||
* ocs_gensql.m: started tool to create SQL CREATE from ocs model file
|
||||
|
||||
* OCSFolderType.m: small change to the factory API, changed to use
|
||||
NGResourceLocator
|
||||
|
||||
2005-03-03 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* OCSFolderManager.m: fixed a bug in subfolder listing (v0.9.23)
|
||||
|
||||
2005-03-01 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* v0.9.22
|
||||
|
||||
* appointment.ocs: added 'cycleenddate' and 'cycleinfo' to address
|
||||
previous performance issues
|
||||
|
||||
* OCSiCalFieldExtractor.m: set 'cycleenddate' and 'cycleinfo' for
|
||||
recurrent events. Reverted setting of 'enddate' to the previous
|
||||
behaviour since 'cycleenddate' is dedicated to the task now
|
||||
|
||||
* iCalRepeatableEntityObject+OCS.[hm]: new category used by the
|
||||
OCSiCalFieldExtractor to extract cycleInfo in an appropriate format
|
||||
|
||||
* sql/generate-folderinfo-sql-for-users.sh,
|
||||
sql/foldertablecreate-helge-privcal.psql,
|
||||
sql/foldertablecreate-helge-privcal.sqlite,
|
||||
sql/generate-folderinfo-sql-for-users-sqlite.sh: adjusted to new
|
||||
schema
|
||||
|
||||
2005-03-01 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* OCSFolder.m: added support for storing content and quick info in
|
||||
the same table (untested) (v0.9.21)
|
||||
|
||||
2005-02-21 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* v0.9.20
|
||||
|
||||
* OCSFolderManager.m: removed quoting of SQL table and column names
|
||||
(breaks with SQLite and isn't necessary for PG), fixed URL pooling
|
||||
for SQLite
|
||||
|
||||
* NSURL+OCS.m: use tablename for last path component
|
||||
|
||||
2005-02-12 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* OCSiCalFieldExtractor.m: uses new iCalEvent API to determine correct
|
||||
'enddate' for recurrent events. This is an optimization which can
|
||||
save quite some time for complex rules. (v0.9.19)
|
||||
|
||||
2004-12-17 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* v0.9.18
|
||||
|
||||
* OCSiCalFieldExtractor.m: extract participants' state
|
||||
|
||||
* sql/generate-folderinfo-sql-for-user.sh, sql/appointment-create.psql,
|
||||
sql/foldertablecreate-helge-privcal.psql: updated with new schema.
|
||||
|
||||
2004-12-15 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* OCSiCalFieldExtractor.m: partmails + cn's are concatenated by '\n'
|
||||
now - this directly eliminates any ambiguities. Also, instead of
|
||||
using 'email' for partmails and orgmail, the extractor uses the
|
||||
'rfc822Email' value which strips away any preceeding 'mailto:'
|
||||
prefix, compacting the representation and speeding up comparison.
|
||||
Also, "iscycle", "isallday" and "isopaque" are now provided by
|
||||
NGiCal and thus always extracted (v0.9.17)
|
||||
|
||||
2004-12-13 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* sql/generate-folderinfo-sql-for-user.sh: fixed critical error in
|
||||
Contacts folder_info, type was 'Appointment' but MUST be 'Contact'
|
||||
(v0.9.16)
|
||||
|
||||
2004-12-10 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* sql: updated all generation scripts to the latest version (v0.9.15)
|
||||
|
||||
2004-12-09 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* v0.9.14
|
||||
|
||||
* appointment.ocs: added "ispublic", "isopaque", "status" and
|
||||
"orgmail".
|
||||
|
||||
* OCSiCalFieldExtractor.m: updated to extract new fields (see above)
|
||||
|
||||
* sql: updated generate-folderinfo-sql-for-users.sh
|
||||
|
||||
2004-10-19 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* OCSFolder.m: added new method -fetchContentsOfAllFiles method which
|
||||
fetches the contents of all files stored in the folder (required for
|
||||
iCal generation, such bulk fetches should be avoided if possible!)
|
||||
(v0.9.13)
|
||||
|
||||
2004-10-15 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* OCSStringFormatter.[hm]: minor cleanup (v0.9.12)
|
||||
|
||||
* v0.9.11
|
||||
|
||||
* OCSStringFormatter.[hm]: new class to format strings according to
|
||||
Database requirements (escaping etc.).
|
||||
|
||||
* OCSFolder.m: uses new OCSStringFormatter now.
|
||||
|
||||
2004-09-25 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* fixed compilation on MacOSX (v0.9.10)
|
||||
|
||||
2004-09-10 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* v0.9.9
|
||||
|
||||
* fixed some gcc warnings
|
||||
|
||||
* GNUmakefile.preamble: added pathes to compile against an FHS SOPE
|
||||
|
||||
* OCSiCalFieldExtractor.m: fixed type of sequence iCalEvent field
|
||||
|
||||
2004-09-01 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* GNUmakefile: install type models into $(GNUSTEP_USER_ROOT) (v0.9.8)
|
||||
|
||||
2004-08-27 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* v0.9.7
|
||||
|
||||
* OCSChannelManager.m: use PostgreSQL as adaptor, not PostgreSQL72
|
||||
|
||||
* OCSFolder.m: added support for doing folder sorting in SQL
|
||||
|
||||
2004-08-26 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* v0.9.6
|
||||
|
||||
* added OCSContactFieldExtractor
|
||||
|
||||
* sql: added sample contact folder create scripts
|
||||
|
||||
* OCSFolderType.m: read extractor class name from type model
|
||||
|
||||
* OCSFolderManager.m: added contact type model per default (v0.9.5)
|
||||
|
||||
2004-08-25 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* GNUmakefile: automatically install OCSTypeModels (v0.9.4)
|
||||
|
||||
2004-08-15 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* OCSFolder.m: added content deletion (v0.9.3)
|
||||
|
||||
* OCSFolder.m: added sanity check to store method (v0.9.2)
|
||||
|
||||
2004-08-14 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* v0.9.1
|
||||
|
||||
* OCSiCalFieldExtractor.m: extract new quick fields: location,
|
||||
partmails, sequence (does not yet handle allday and cycle due to
|
||||
NGiCal restrictions)
|
||||
|
||||
* appointment.ocs, sql/foldertablecreate-helge-privcal.psql,
|
||||
sql/testapt-agenor-helge-privcal.psql, sql/appointment-create.psql:
|
||||
added quick fields: isallday, iscycle, location, partmails, sequence
|
||||
|
||||
* started ocs_recreatequick tool intended for recreating a quick table
|
||||
based on the content table of a folder
|
||||
|
||||
2004-07-20 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* OCSChannelManager.m: fixed a bug in the channel GC which resulted
|
||||
in an exception during the GC NSTimer
|
||||
|
||||
2004-07-16 Helge Hess <helge.hess@skyrix.com>
|
||||
|
||||
* improved error handling in various files
|
||||
|
||||
2004-07-02 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* OCSChannelManager.m: added garbage collector for channel pools
|
||||
|
||||
2004-06-30 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* OCSChannelManager.m: implemented pooling
|
||||
|
||||
* OCSFolder.m: added quick fetches
|
||||
|
||||
* GNUmakefile.preamble: fix link path
|
||||
|
||||
* GNUmakefile (libOGoContentStore_HEADER_FILES_INSTALL_DIR): install
|
||||
headers in OGoContentStore
|
||||
|
||||
* GNUmakefile.preamble (ocs_ls_TOOL_LIBS): added static dependencies
|
||||
for OSX
|
||||
|
||||
2004-06-30 Marcus Mueller <znek@mulle-kybernetik.com>
|
||||
|
||||
* ocs_cat.m, ocs_ls.m, ocs_mkdir.m: fixed for gnustep compile.
|
||||
|
||||
2004-06-29 Helge Hess <helge.hess@opengroupware.org>
|
||||
|
||||
* created ChangeLog
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_EOAdaptorChannel_GCS_H__
|
||||
#define __GDLContentStore_EOAdaptorChannel_GCS_H__
|
||||
|
||||
#include <GDLAccess/EOAdaptorChannel.h>
|
||||
|
||||
@interface EOAdaptorChannel(GCS)
|
||||
|
||||
- (BOOL)tableExistsWithName:(NSString *)_tableName;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_EOAdaptorChannel_GCS_H__ */
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "EOAdaptorChannel+GCS.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation EOAdaptorChannel(GCS)
|
||||
|
||||
- (BOOL)tableExistsWithName:(NSString *)_tableName {
|
||||
NSException *ex;
|
||||
NSString *sql;
|
||||
BOOL didOpen;
|
||||
|
||||
didOpen = NO;
|
||||
if (![self isOpen]) {
|
||||
if (![self openChannel])
|
||||
return NO;
|
||||
didOpen = YES;
|
||||
}
|
||||
|
||||
sql = @"SELECT COUNT(*) FROM ";
|
||||
sql = [sql stringByAppendingString:_tableName];
|
||||
sql = [sql stringByAppendingString:@" WHERE 1 = 2"];
|
||||
|
||||
ex = [[[self evaluateExpressionX:sql] retain] autorelease];
|
||||
[self cancelFetch];
|
||||
|
||||
if (didOpen) [self closeChannel];
|
||||
return ex != nil ? NO : YES;
|
||||
}
|
||||
|
||||
@end /* EOAdaptorChannel(GCS) */
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_EOQualifier_GCS_H__
|
||||
#define __GDLContentStore_EOQualifier_GCS_H__
|
||||
|
||||
#include <EOControl/EOQualifier.h>
|
||||
|
||||
@class NSMutableString;
|
||||
|
||||
@interface EOQualifier(GCS)
|
||||
|
||||
- (void)_gcsAppendToString:(NSMutableString *)_ms;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_EOQualifier_GCS_H__ */
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
Copyright (C) 2004-2007 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "EOQualifier+GCS.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation EOQualifier(GCS)
|
||||
|
||||
- (void)_appendAndQualifier:(EOAndQualifier *)_q
|
||||
toString:(NSMutableString *)_ms
|
||||
{
|
||||
// TODO: move to EOQualifier category
|
||||
NSArray *qs;
|
||||
unsigned i, count;
|
||||
|
||||
qs = [_q qualifiers];
|
||||
if ((count = [qs count]) == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (i != 0) [_ms appendString:@" AND "];
|
||||
if (count > 1) [_ms appendString:@"("];
|
||||
[[qs objectAtIndex:i] _gcsAppendToString:_ms];
|
||||
if (count > 1) [_ms appendString:@")"];
|
||||
}
|
||||
}
|
||||
- (void)_appendOrQualifier:(EOAndQualifier *)_q
|
||||
toString:(NSMutableString *)_ms
|
||||
{
|
||||
// TODO: move to EOQualifier category
|
||||
NSArray *qs;
|
||||
unsigned i, count;
|
||||
|
||||
qs = [_q qualifiers];
|
||||
if ((count = [qs count]) == 0)
|
||||
return;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (i != 0) [_ms appendString:@" OR "];
|
||||
if (count > 1) [_ms appendString:@"("];
|
||||
[[qs objectAtIndex:i] _gcsAppendToString:_ms];
|
||||
if (count > 1) [_ms appendString:@")"];
|
||||
}
|
||||
}
|
||||
- (void)_appendKeyValueQualifier:(EOKeyValueQualifier *)_q
|
||||
toString:(NSMutableString *)_ms
|
||||
{
|
||||
id val;
|
||||
NSString *qKey, *qOperator, *qValue, *qFormat;
|
||||
BOOL isCI;
|
||||
|
||||
qKey = [_q key];
|
||||
|
||||
if ((val = [_q value])) {
|
||||
SEL op = [_q selector];
|
||||
|
||||
if ([val isNotNull]) {
|
||||
isCI = NO;
|
||||
|
||||
if (sel_eq(op, EOQualifierOperatorEqual))
|
||||
qOperator = @"=";
|
||||
else if (sel_eq(op, EOQualifierOperatorNotEqual))
|
||||
qOperator = @"!=";
|
||||
else if (sel_eq(op, EOQualifierOperatorLessThan))
|
||||
qOperator = @"<";
|
||||
else if (sel_eq(op, EOQualifierOperatorGreaterThan))
|
||||
qOperator = @">";
|
||||
else if (sel_eq(op, EOQualifierOperatorLessThanOrEqualTo))
|
||||
qOperator = @"<=";
|
||||
else if (sel_eq(op, EOQualifierOperatorGreaterThanOrEqualTo))
|
||||
qOperator = @">=";
|
||||
else if (sel_eq(op, EOQualifierOperatorLike))
|
||||
qOperator = @"LIKE";
|
||||
else if (sel_eq(op, EOQualifierOperatorCaseInsensitiveLike)) {
|
||||
isCI = YES;
|
||||
qOperator = @"LIKE";
|
||||
}
|
||||
else {
|
||||
[self errorWithFormat:@"%s: unsupported operation for null: %@",
|
||||
__PRETTY_FUNCTION__, NSStringFromSelector(op)];
|
||||
}
|
||||
|
||||
if ([val isKindOfClass:[NSNumber class]])
|
||||
qValue = [val stringValue];
|
||||
else if ([val isKindOfClass:[NSString class]]) {
|
||||
qValue = [NSString stringWithFormat: @"'%@'", val];
|
||||
}
|
||||
else {
|
||||
[self errorWithFormat:@"%s: unsupported value class: %@",
|
||||
__PRETTY_FUNCTION__, NSStringFromClass([val class])];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (sel_eq(op, EOQualifierOperatorEqual)) {
|
||||
qOperator = @"IS";
|
||||
qValue = @"NULL";
|
||||
}
|
||||
else if (sel_eq(op, EOQualifierOperatorEqual)) {
|
||||
qOperator = @"IS NOT";
|
||||
qValue = @"NULL";
|
||||
}
|
||||
else {
|
||||
[self errorWithFormat:@"%s: invalid operation for null: %@",
|
||||
__PRETTY_FUNCTION__, NSStringFromSelector(op)];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
qOperator = @"IS";
|
||||
qValue = @"NULL";
|
||||
}
|
||||
|
||||
if (isCI)
|
||||
qFormat = @"UPPER(%@) %@ UPPER(%@)";
|
||||
else
|
||||
qFormat = @"%@ %@ %@";
|
||||
|
||||
[_ms appendFormat: qFormat, qKey, qOperator, qValue];
|
||||
}
|
||||
|
||||
- (void)_appendQualifier:(EOQualifier *)_q toString:(NSMutableString *)_ms {
|
||||
if (_q == nil) return;
|
||||
|
||||
if ([_q isKindOfClass:[EOAndQualifier class]])
|
||||
[self _appendAndQualifier:(id)_q toString:_ms];
|
||||
else if ([_q isKindOfClass:[EOOrQualifier class]])
|
||||
[self _appendOrQualifier:(id)_q toString:_ms];
|
||||
else if ([_q isKindOfClass:[EOKeyValueQualifier class]])
|
||||
[self _appendKeyValueQualifier:(id)_q toString:_ms];
|
||||
else
|
||||
[self errorWithFormat:@"unknown qualifier: %@", _q];
|
||||
}
|
||||
|
||||
- (void)_gcsAppendToString:(NSMutableString *)_ms {
|
||||
[self _appendQualifier:self toString:_ms];
|
||||
}
|
||||
|
||||
@end /* EOQualifier(GCS) */
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSChannelManager_H__
|
||||
#define __GDLContentStore_GCSChannelManager_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSChannelManager
|
||||
|
||||
This object manages the connection pooling.
|
||||
*/
|
||||
|
||||
@class NSURL, NSMutableDictionary, NSMutableArray, NSTimer;
|
||||
@class EOAdaptorChannel, EOAdaptor;
|
||||
|
||||
@interface GCSChannelManager : NSObject
|
||||
{
|
||||
NSMutableDictionary *urlToAdaptor;
|
||||
|
||||
NSMutableArray *availableChannels;
|
||||
NSMutableArray *busyChannels;
|
||||
NSTimer *gcTimer;
|
||||
}
|
||||
|
||||
+ (id)defaultChannelManager;
|
||||
|
||||
/* channels */
|
||||
|
||||
- (EOAdaptorChannel *)acquireOpenChannelForURL:(NSURL *)_url;
|
||||
- (void)releaseChannel:(EOAdaptorChannel *)_channel;
|
||||
|
||||
/* checking for tables */
|
||||
|
||||
- (BOOL)canConnect:(NSURL *)_url;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSChannelManager_H__ */
|
|
@ -0,0 +1,516 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GCSChannelManager.h"
|
||||
#include "NSURL+GCS.h"
|
||||
#include "EOAdaptorChannel+GCS.h"
|
||||
#include <GDLAccess/EOAdaptor.h>
|
||||
#include <GDLAccess/EOAdaptorContext.h>
|
||||
#include <GDLAccess/EOAdaptorChannel.h>
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
TODO:
|
||||
- implemented pooling
|
||||
- auto-close channels which are very old?!
|
||||
(eg missing release due to an exception)
|
||||
*/
|
||||
|
||||
@interface GCSChannelHandle : NSObject
|
||||
{
|
||||
@public
|
||||
NSURL *url;
|
||||
EOAdaptorChannel *channel;
|
||||
NSDate *creationTime;
|
||||
NSDate *lastReleaseTime;
|
||||
NSDate *lastAcquireTime;
|
||||
}
|
||||
|
||||
- (EOAdaptorChannel *)channel;
|
||||
- (BOOL)canHandleURL:(NSURL *)_url;
|
||||
- (NSTimeInterval)age;
|
||||
|
||||
@end
|
||||
|
||||
@implementation GCSChannelManager
|
||||
|
||||
static BOOL debugOn = NO;
|
||||
static BOOL debugPools = NO;
|
||||
static int ChannelExpireAge = 180;
|
||||
static NSTimeInterval ChannelCollectionTimer = 5 * 60;
|
||||
|
||||
+ (void)initialize {
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
debugOn = [ud boolForKey:@"GCSChannelManagerDebugEnabled"];
|
||||
debugPools = [ud boolForKey:@"GCSChannelManagerPoolDebugEnabled"];
|
||||
|
||||
ChannelExpireAge = [[ud objectForKey:@"GCSChannelExpireAge"] intValue];
|
||||
if (ChannelExpireAge < 1)
|
||||
ChannelExpireAge = 180;
|
||||
|
||||
ChannelCollectionTimer =
|
||||
[[ud objectForKey:@"GCSChannelCollectionTimer"] intValue];
|
||||
if (ChannelCollectionTimer < 1)
|
||||
ChannelCollectionTimer = 5*60;
|
||||
}
|
||||
|
||||
+ (NSString *)adaptorNameForURLScheme:(NSString *)_scheme {
|
||||
// TODO: map scheme to adaptors (eg 'postgresql://' to PostgreSQL
|
||||
return @"PostgreSQL";
|
||||
}
|
||||
|
||||
+ (id)defaultChannelManager {
|
||||
static GCSChannelManager *cm = nil;
|
||||
if (cm == nil)
|
||||
cm = [[self alloc] init];
|
||||
return cm;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
self->urlToAdaptor = [[NSMutableDictionary alloc] initWithCapacity:4];
|
||||
self->availableChannels = [[NSMutableArray alloc] initWithCapacity:16];
|
||||
self->busyChannels = [[NSMutableArray alloc] initWithCapacity:16];
|
||||
|
||||
self->gcTimer = [[NSTimer scheduledTimerWithTimeInterval:
|
||||
ChannelCollectionTimer
|
||||
target:self selector:@selector(_garbageCollect:)
|
||||
userInfo:nil repeats:YES] retain];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
if (self->gcTimer) [self->gcTimer invalidate];
|
||||
[self->gcTimer release];
|
||||
|
||||
[self->busyChannels release];
|
||||
[self->availableChannels release];
|
||||
[self->urlToAdaptor release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* DB key */
|
||||
|
||||
- (NSString *)databaseKeyForURL:(NSURL *)_url {
|
||||
/*
|
||||
We need to build a proper key that omits passwords and URL path components
|
||||
which are not required.
|
||||
*/
|
||||
NSString *key;
|
||||
|
||||
key = [NSString stringWithFormat:@"%@\n%@\n%@\n%@",
|
||||
[_url host], [_url port],
|
||||
[_url user], [_url gcsDatabaseName]];
|
||||
return key;
|
||||
}
|
||||
|
||||
/* adaptors */
|
||||
|
||||
- (NSDictionary *)connectionDictionaryForURL:(NSURL *)_url {
|
||||
NSMutableDictionary *md;
|
||||
id tmp;
|
||||
|
||||
md = [NSMutableDictionary dictionaryWithCapacity:4];
|
||||
|
||||
if ((tmp = [_url host]) != nil)
|
||||
[md setObject:tmp forKey:@"hostName"];
|
||||
if ((tmp = [_url port]) != nil)
|
||||
[md setObject:tmp forKey:@"port"];
|
||||
if ((tmp = [_url user]) != nil)
|
||||
[md setObject:tmp forKey:@"userName"];
|
||||
if ((tmp = [_url password]) != nil)
|
||||
[md setObject:tmp forKey:@"password"];
|
||||
|
||||
if ((tmp = [_url gcsDatabaseName]) != nil)
|
||||
[md setObject:tmp forKey:@"databaseName"];
|
||||
|
||||
[self debugWithFormat:@"build connection dictionary for URL %@: %@",
|
||||
[_url absoluteString], md];
|
||||
return md;
|
||||
}
|
||||
|
||||
- (EOAdaptor *)adaptorForURL:(NSURL *)_url {
|
||||
EOAdaptor *adaptor;
|
||||
NSString *key;
|
||||
|
||||
if (_url == nil)
|
||||
return nil;
|
||||
if ((key = [self databaseKeyForURL:_url]) == nil)
|
||||
return nil;
|
||||
if ((adaptor = [self->urlToAdaptor objectForKey:key]) != nil) {
|
||||
[self debugWithFormat:@"using cached adaptor: %@", adaptor];
|
||||
return adaptor; /* cached :-) */
|
||||
}
|
||||
|
||||
[self debugWithFormat:@"creating new adaptor for URL: %@", _url];
|
||||
|
||||
if ([EOAdaptor respondsToSelector:@selector(adaptorForURL:)]) {
|
||||
adaptor = [EOAdaptor adaptorForURL:_url];
|
||||
}
|
||||
else {
|
||||
NSString *adaptorName;
|
||||
NSDictionary *condict;
|
||||
|
||||
adaptorName = [[self class] adaptorNameForURLScheme:[_url scheme]];
|
||||
if ([adaptorName length] == 0) {
|
||||
[self errorWithFormat:@"cannot handle URL: %@", _url];
|
||||
return nil;
|
||||
}
|
||||
|
||||
condict = [self connectionDictionaryForURL:_url];
|
||||
|
||||
if ((adaptor = [EOAdaptor adaptorWithName:adaptorName]) == nil) {
|
||||
[self errorWithFormat:@"did not find adaptor '%@' for URL: %@",
|
||||
adaptorName, _url];
|
||||
return nil;
|
||||
}
|
||||
|
||||
[adaptor setConnectionDictionary:condict];
|
||||
}
|
||||
|
||||
[self->urlToAdaptor setObject:adaptor forKey:key];
|
||||
return adaptor;
|
||||
}
|
||||
|
||||
/* channels */
|
||||
|
||||
- (GCSChannelHandle *)findBusyChannelHandleForChannel:(EOAdaptorChannel *)_ch {
|
||||
NSEnumerator *e;
|
||||
GCSChannelHandle *handle;
|
||||
|
||||
e = [self->busyChannels objectEnumerator];
|
||||
while ((handle = [e nextObject])) {
|
||||
if ([handle channel] == _ch)
|
||||
return handle;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
- (GCSChannelHandle *)findAvailChannelHandleForURL:(NSURL *)_url {
|
||||
NSEnumerator *e;
|
||||
GCSChannelHandle *handle;
|
||||
|
||||
e = [self->availableChannels objectEnumerator];
|
||||
while ((handle = [e nextObject])) {
|
||||
if ([handle canHandleURL:_url])
|
||||
return handle;
|
||||
|
||||
if (debugPools) {
|
||||
[self logWithFormat:@"DBPOOL: cannot use handle (%@ vs %@)",
|
||||
[_url absoluteString], [handle->url absoluteString]];
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (EOAdaptorChannel *)_createChannelForURL:(NSURL *)_url {
|
||||
EOAdaptor *adaptor;
|
||||
EOAdaptorContext *adContext;
|
||||
EOAdaptorChannel *adChannel;
|
||||
|
||||
if ((adaptor = [self adaptorForURL:_url]) == nil)
|
||||
return nil;
|
||||
|
||||
if ((adContext = [adaptor createAdaptorContext]) == nil) {
|
||||
[self errorWithFormat:@"could not create adaptor context!"];
|
||||
return nil;
|
||||
}
|
||||
if ((adChannel = [adContext createAdaptorChannel]) == nil) {
|
||||
[self errorWithFormat:@"could not create adaptor channel!"];
|
||||
return nil;
|
||||
}
|
||||
return adChannel;
|
||||
}
|
||||
|
||||
- (EOAdaptorChannel *)acquireOpenChannelForURL:(NSURL *)_url {
|
||||
// TODO: naive implementation, add pooling!
|
||||
EOAdaptorChannel *channel;
|
||||
GCSChannelHandle *handle;
|
||||
NSCalendarDate *now;
|
||||
|
||||
now = [NSCalendarDate date];
|
||||
|
||||
/* look for cached handles */
|
||||
|
||||
if ((handle = [self findAvailChannelHandleForURL:_url]) != nil) {
|
||||
// TODO: check age?
|
||||
[self->busyChannels addObject:handle];
|
||||
[self->availableChannels removeObject:handle];
|
||||
ASSIGN(handle->lastAcquireTime, now);
|
||||
|
||||
if (debugPools)
|
||||
[self logWithFormat:@"DBPOOL: reused cached DB channel!"];
|
||||
return [[handle channel] retain];
|
||||
}
|
||||
|
||||
if (debugPools) {
|
||||
[self logWithFormat:@"DBPOOL: create new DB channel for URL: %@",
|
||||
[_url absoluteString]];
|
||||
}
|
||||
|
||||
/* create channel */
|
||||
|
||||
if ((channel = [self _createChannelForURL:_url]) == nil)
|
||||
return nil;
|
||||
|
||||
if ([channel isOpen])
|
||||
;
|
||||
else if (![channel openChannel]) {
|
||||
[self errorWithFormat:@"could not open channel %@ for URL: %@",
|
||||
channel, [_url absoluteString]];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* create handle for channel */
|
||||
|
||||
handle = [[GCSChannelHandle alloc] init];
|
||||
handle->url = [_url retain];
|
||||
handle->channel = [channel retain];
|
||||
handle->creationTime = [now retain];
|
||||
handle->lastAcquireTime = [now retain];
|
||||
|
||||
[self->busyChannels addObject:handle];
|
||||
[handle release];
|
||||
|
||||
return [channel retain];
|
||||
}
|
||||
- (void)releaseChannel:(EOAdaptorChannel *)_channel {
|
||||
GCSChannelHandle *handle;
|
||||
|
||||
if ((handle = [self findBusyChannelHandleForChannel:_channel]) != nil) {
|
||||
NSCalendarDate *now;
|
||||
|
||||
now = [NSCalendarDate date];
|
||||
|
||||
handle = [handle retain];
|
||||
ASSIGN(handle->lastReleaseTime, now);
|
||||
|
||||
[self->busyChannels removeObject:handle];
|
||||
|
||||
if ([[handle channel] isOpen] && [handle age] < ChannelExpireAge) {
|
||||
// TODO: consider age
|
||||
[self->availableChannels addObject:handle];
|
||||
if (debugPools) {
|
||||
[self logWithFormat:
|
||||
@"DBPOOL: keeping channel (age %ds, #%d): %@",
|
||||
(int)[handle age], [self->availableChannels count],
|
||||
[handle->url absoluteString]];
|
||||
}
|
||||
[_channel release];
|
||||
[handle release];
|
||||
return;
|
||||
}
|
||||
|
||||
if (debugPools) {
|
||||
[self logWithFormat:
|
||||
@"DBPOOL: freeing old channel (age %ds)", (int)[handle age]];
|
||||
}
|
||||
|
||||
/* not reusing channel */
|
||||
[handle release]; handle = nil;
|
||||
}
|
||||
|
||||
if ([_channel isOpen])
|
||||
[_channel closeChannel];
|
||||
|
||||
[_channel release];
|
||||
}
|
||||
|
||||
/* checking for tables */
|
||||
|
||||
- (BOOL)canConnect:(NSURL *)_url {
|
||||
/*
|
||||
this can check for DB connect as well as for table URLs (whether a table
|
||||
exists)
|
||||
*/
|
||||
EOAdaptorChannel *channel;
|
||||
NSString *table;
|
||||
BOOL result;
|
||||
|
||||
if ((channel = [self acquireOpenChannelForURL:_url]) == nil) {
|
||||
if (debugOn) [self debugWithFormat:@"could not acquire channel: %@", _url];
|
||||
return NO;
|
||||
}
|
||||
if (debugOn) [self debugWithFormat:@"acquired channel: %@", channel];
|
||||
result = YES; /* could open channel */
|
||||
|
||||
/* check whether table exists */
|
||||
|
||||
table = [_url gcsTableName];
|
||||
if ([table length] > 0)
|
||||
result = [channel tableExistsWithName:table];
|
||||
|
||||
/* release channel */
|
||||
|
||||
[self releaseChannel:channel]; channel = nil;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* collect old channels */
|
||||
|
||||
- (void)_garbageCollect:(NSTimer *)_timer {
|
||||
NSMutableArray *handlesToRemove;
|
||||
unsigned i, count;
|
||||
|
||||
if ((count = [self->availableChannels count]) == 0)
|
||||
/* no available channels */
|
||||
return;
|
||||
|
||||
/* collect channels to expire */
|
||||
|
||||
handlesToRemove = [[NSMutableArray alloc] initWithCapacity:4];
|
||||
for (i = 0; i < count; i++) {
|
||||
GCSChannelHandle *handle;
|
||||
|
||||
handle = [self->availableChannels objectAtIndex:i];
|
||||
if (![[handle channel] isOpen]) {
|
||||
[handlesToRemove addObject:handle];
|
||||
continue;
|
||||
}
|
||||
if ([handle age] > ChannelExpireAge) {
|
||||
[handlesToRemove addObject:handle];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* remove channels */
|
||||
count = [handlesToRemove count];
|
||||
if (debugPools)
|
||||
[self logWithFormat:@"DBPOOL: garbage collecting %d channels.", count];
|
||||
for (i = 0; i < count; i++) {
|
||||
GCSChannelHandle *handle;
|
||||
|
||||
handle = [[handlesToRemove objectAtIndex:i] retain];
|
||||
[self->availableChannels removeObject:handle];
|
||||
if ([[handle channel] isOpen])
|
||||
[[handle channel] closeChannel];
|
||||
[handle release];
|
||||
}
|
||||
|
||||
[handlesToRemove release];
|
||||
}
|
||||
|
||||
/* debugging */
|
||||
|
||||
- (BOOL)isDebuggingEnabled {
|
||||
return debugOn;
|
||||
}
|
||||
|
||||
/* description */
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:256];
|
||||
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
|
||||
|
||||
[ms appendFormat:@" #adaptors=%d", [self->urlToAdaptor count]];
|
||||
|
||||
[ms appendString:@">"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
@end /* GCSChannelManager */
|
||||
|
||||
@implementation GCSChannelHandle
|
||||
|
||||
- (void)dealloc {
|
||||
[self->channel release];
|
||||
[self->creationTime release];
|
||||
[self->lastReleaseTime release];
|
||||
[self->lastAcquireTime release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (EOAdaptorChannel *)channel {
|
||||
return self->channel;
|
||||
}
|
||||
|
||||
- (BOOL)canHandleURL:(NSURL *)_url {
|
||||
BOOL isSQLite;
|
||||
|
||||
if (_url == nil) {
|
||||
[self logWithFormat:@"MISMATCH: no url .."];
|
||||
return NO;
|
||||
}
|
||||
if (_url == self->url)
|
||||
return YES;
|
||||
|
||||
isSQLite = [[_url scheme] isEqualToString:@"sqlite"];
|
||||
|
||||
if (!isSQLite && ![[self->url host] isEqual:[_url host]]) {
|
||||
[self logWithFormat:@"MISMATCH: different host (%@ vs %@)",
|
||||
[self->url host], [_url host]];
|
||||
return NO;
|
||||
}
|
||||
if (![[self->url gcsDatabaseName] isEqualToString:[_url gcsDatabaseName]]) {
|
||||
[self logWithFormat:@"MISMATCH: different db .."];
|
||||
return NO;
|
||||
}
|
||||
if (!isSQLite) {
|
||||
if (![[self->url user] isEqual:[_url user]]) {
|
||||
[self logWithFormat:@"MISMATCH: different user .."];
|
||||
return NO;
|
||||
}
|
||||
if ([[self->url port] intValue] != [[_url port] intValue]) {
|
||||
[self logWithFormat:@"MISMATCH: different port (%@ vs %@) ..",
|
||||
[self->url port], [_url port]];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSTimeInterval)age {
|
||||
return [[NSCalendarDate calendarDate]
|
||||
timeIntervalSinceDate:self->creationTime];
|
||||
}
|
||||
|
||||
/* NSCopying */
|
||||
|
||||
- (id)copyWithZone:(NSZone *)_zone {
|
||||
return [self retain];
|
||||
}
|
||||
|
||||
/* description */
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:256];
|
||||
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
|
||||
|
||||
[ms appendFormat:@" channel=0x%p", self->channel];
|
||||
if (self->creationTime) [ms appendFormat:@" created=%@", self->creationTime];
|
||||
if (self->lastReleaseTime)
|
||||
[ms appendFormat:@" last-released=%@", self->lastReleaseTime];
|
||||
if (self->lastAcquireTime)
|
||||
[ms appendFormat:@" last-acquired=%@", self->lastAcquireTime];
|
||||
|
||||
[ms appendString:@">"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
@end /* GCSChannelHandle */
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSContext_H__
|
||||
#define __GDLContentStore_GCSContext_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSContext
|
||||
|
||||
Context passed to all operations.
|
||||
*/
|
||||
|
||||
@interface GCSContext : NSObject
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSContext_H__ */
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GCSContext.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation GCSContext
|
||||
@end /* GCSContext */
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSFieldExtractor_H__
|
||||
#define __GDLContentStore_GCSFieldExtractor_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
@class NSString, NSMutableDictionary;
|
||||
|
||||
@interface GCSFieldExtractor : NSObject
|
||||
{
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)extractQuickFieldsFromContent:(NSString *)_content;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSFieldExtractor_H__ */
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GCSFieldExtractor.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation GCSFieldExtractor
|
||||
|
||||
- (NSMutableDictionary *)extractQuickFieldsFromContent:(NSString *)_content {
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end /* GCSFieldExtractor */
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSFieldInfo_H__
|
||||
#define __GDLContentStore_GCSFieldInfo_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSFieldInfo
|
||||
|
||||
The field info inside an .ocs schema file.
|
||||
|
||||
The field info objects are stored in an GCSFolderType.
|
||||
*/
|
||||
|
||||
@class NSString, NSArray;
|
||||
|
||||
@interface GCSFieldInfo : NSObject
|
||||
{
|
||||
NSString *columnName;
|
||||
NSString *sqlType;
|
||||
BOOL allowsNull;
|
||||
BOOL isPrimaryKey;
|
||||
}
|
||||
|
||||
+ (NSArray *)fieldsForPropertyList:(NSArray *)_plist;
|
||||
- (id)initWithPropertyList:(id)_plist;
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (NSString *)columnName;
|
||||
- (NSString *)sqlType;
|
||||
- (BOOL)doesAllowNull;
|
||||
- (BOOL)isPrimaryKey;
|
||||
|
||||
/* generating SQL */
|
||||
|
||||
- (NSString *)sqlCreateSection;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSFieldInfo_H__ */
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GCSFieldInfo.h"
|
||||
#include "common.h"
|
||||
|
||||
@implementation GCSFieldInfo
|
||||
|
||||
+ (NSArray *)fieldsForPropertyList:(NSArray *)_plist {
|
||||
NSMutableArray *fields;
|
||||
unsigned i, count;
|
||||
|
||||
if (_plist == nil)
|
||||
return nil;
|
||||
|
||||
count = [_plist count];
|
||||
fields = [NSMutableArray arrayWithCapacity:count];
|
||||
for (i = 0; i < count; i++) {
|
||||
GCSFieldInfo *field;
|
||||
|
||||
field = [[GCSFieldInfo alloc] initWithPropertyList:
|
||||
[_plist objectAtIndex:i]];
|
||||
if (field != nil) [fields addObject:field];
|
||||
[field release];
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
- (id)initWithPropertyList:(id)_plist {
|
||||
if ((self = [super init])) {
|
||||
NSDictionary *plist = _plist;
|
||||
|
||||
self->columnName = [[plist objectForKey:@"columnName"] copy];
|
||||
self->sqlType = [[plist objectForKey:@"sqlType"] copy];
|
||||
|
||||
self->allowsNull = [[plist objectForKey:@"allowsNull"] boolValue];
|
||||
self->isPrimaryKey = [[plist objectForKey:@"isPrimaryKey"] boolValue];
|
||||
|
||||
if (![self->columnName isNotNull] || ![self->sqlType isNotNull]) {
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self->columnName release];
|
||||
[self->sqlType release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (NSString *)columnName {
|
||||
return self->columnName;
|
||||
}
|
||||
- (NSString *)sqlType {
|
||||
return self->sqlType;
|
||||
}
|
||||
|
||||
- (BOOL)doesAllowNull {
|
||||
return self->allowsNull;
|
||||
}
|
||||
- (BOOL)isPrimaryKey {
|
||||
return self->isPrimaryKey;
|
||||
}
|
||||
|
||||
/* generating SQL */
|
||||
|
||||
- (NSString *)sqlCreateSection {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:32];
|
||||
[ms appendString:[self columnName]];
|
||||
[ms appendString:@" "];
|
||||
[ms appendString:[self sqlType]];
|
||||
|
||||
[ms appendString:@" "];
|
||||
if (![self doesAllowNull]) [ms appendString:@"NOT "];
|
||||
[ms appendString:@"NULL"];
|
||||
|
||||
if ([self isPrimaryKey]) [ms appendString:@" PRIMARY KEY"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
/* description */
|
||||
|
||||
- (void)appendAttributesToDescription:(NSMutableString *)ms {
|
||||
id tmp;
|
||||
|
||||
if ((tmp = [self columnName]) != nil) [ms appendFormat:@" column=%@", tmp];
|
||||
if ((tmp = [self sqlType]) != nil) [ms appendFormat:@" sql=%@", tmp];
|
||||
|
||||
if ([self doesAllowNull]) [ms appendString:@" allows-null"];
|
||||
if ([self isPrimaryKey]) [ms appendString:@" pkey"];
|
||||
}
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:256];
|
||||
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
|
||||
[self appendAttributesToDescription:ms];
|
||||
[ms appendString:@">"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
@end /* GCSFieldInfo */
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
Copyright (C) 2004-2007 SKYRIX Software AG
|
||||
Copyright (C) 2007 Helge Hess
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSFolder_H__
|
||||
#define __GDLContentStore_GCSFolder_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSFolder
|
||||
|
||||
TODO: document
|
||||
|
||||
Fixed Quick-Table SQL fields:
|
||||
- "c_name" (name of the file in the folder)
|
||||
|
||||
Fixed BLOB-Table SQL fields:
|
||||
- "c_name" (name of the file in the folder)
|
||||
- "c_content" (content of the file in the folder)
|
||||
- "c_version" (update revision of the file in the folder)
|
||||
*/
|
||||
|
||||
@class NSString, NSURL, NSNumber, NSArray, NSException, NSMutableString;
|
||||
@class NSDictionary;
|
||||
@class EOQualifier, EOFetchSpecification;
|
||||
@class EOAdaptorChannel;
|
||||
@class GCSFolderManager, GCSFolderType, GCSChannelManager;
|
||||
|
||||
@interface GCSFolder : NSObject
|
||||
{
|
||||
GCSFolderManager *folderManager;
|
||||
GCSFolderType *folderInfo;
|
||||
|
||||
NSNumber *folderId;
|
||||
NSString *folderName;
|
||||
NSString *path;
|
||||
NSURL *location;
|
||||
NSURL *quickLocation;
|
||||
NSURL *aclLocation;
|
||||
NSString *folderTypeName;
|
||||
|
||||
struct {
|
||||
int requiresFolderSelect:1;
|
||||
int sameTableForQuick:1;
|
||||
int reserved:30;
|
||||
} ofFlags;
|
||||
}
|
||||
|
||||
- (id)initWithPath:(NSString *)_path primaryKey:(id)_folderId
|
||||
folderTypeName:(NSString *)_ftname folderType:(GCSFolderType *)_ftype
|
||||
location:(NSURL *)_loc quickLocation:(NSURL *)_qloc
|
||||
aclLocation: (NSURL *)_aloc
|
||||
folderManager:(GCSFolderManager *)_fm;
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (NSNumber *)folderId;
|
||||
- (NSString *)folderName;
|
||||
- (NSString *)path;
|
||||
- (NSURL *)location;
|
||||
- (NSURL *)quickLocation;
|
||||
- (NSURL *)aclLocation;
|
||||
- (NSString *)folderTypeName;
|
||||
|
||||
- (GCSFolderManager *)folderManager;
|
||||
- (GCSChannelManager *)channelManager;
|
||||
|
||||
- (NSString *)storeTableName;
|
||||
- (NSString *)quickTableName;
|
||||
- (NSString *)aclTableName;
|
||||
- (BOOL)isQuickInfoStoredInContentTable;
|
||||
|
||||
/* connection */
|
||||
|
||||
- (EOAdaptorChannel *)acquireStoreChannel;
|
||||
- (EOAdaptorChannel *)acquireQuickChannel;
|
||||
- (EOAdaptorChannel *)acquireAclChannel;
|
||||
- (void)releaseChannel:(EOAdaptorChannel *)_channel;
|
||||
|
||||
- (BOOL)canConnectStore;
|
||||
- (BOOL)canConnectQuick;
|
||||
|
||||
/* operations */
|
||||
|
||||
- (NSArray *)subFolderNames;
|
||||
- (NSArray *)allSubFolderNames;
|
||||
|
||||
- (NSNumber *)versionOfContentWithName:(NSString *)_name;
|
||||
|
||||
- (NSString *)fetchContentWithName:(NSString *)_name;
|
||||
- (NSException *)writeContent:(NSString *)_content toName:(NSString *)_name
|
||||
baseVersion:(unsigned int)_baseVersion;
|
||||
- (NSException *)writeContent:(NSString *)_content toName:(NSString *)_name;
|
||||
- (NSException *)deleteContentWithName:(NSString *)_name;
|
||||
|
||||
- (NSException *)deleteFolder;
|
||||
|
||||
- (NSDictionary *)fetchContentsOfAllFiles;
|
||||
|
||||
- (NSArray *)fetchFields:(NSArray *)_flds
|
||||
fetchSpecification:(EOFetchSpecification *)_fs;
|
||||
- (NSArray *)fetchFields:(NSArray *)_flds matchingQualifier:(EOQualifier *)_q;
|
||||
- (NSArray *)fetchAclMatchingQualifier:(EOQualifier *)_q;
|
||||
- (void)deleteAclMatchingQualifier:(EOQualifier *)_q;
|
||||
- (void)deleteAclWithSpecification:(EOFetchSpecification *)_fs;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSFolder_H__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GDLContentStore_GCSFolderManager_H__
|
||||
#define __GDLContentStore_GCSFolderManager_H__
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
/*
|
||||
GCSFolderManager
|
||||
|
||||
Objects of this class manage the "folder_info" table, they manage the
|
||||
model and manage the tables required for a folder.
|
||||
*/
|
||||
|
||||
@class NSString, NSArray, NSURL, NSDictionary, NSException;
|
||||
@class GCSChannelManager, GCSFolder, GCSFolderType;
|
||||
|
||||
@interface GCSFolderManager : NSObject
|
||||
{
|
||||
GCSChannelManager *channelManager;
|
||||
NSDictionary *nameToType;
|
||||
NSURL *folderInfoLocation;
|
||||
NSString *folderNamePrefix;
|
||||
}
|
||||
|
||||
+ (id)defaultFolderManager;
|
||||
- (id)initWithFolderInfoLocation:(NSURL *)_url;
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (void) setFolderNamePrefix:(NSString *)_folderNamePrefix;
|
||||
- (NSString *) folderNamePrefix;
|
||||
|
||||
- (NSURL *)folderInfoLocation;
|
||||
- (NSString *)folderInfoTableName;
|
||||
|
||||
/* connection */
|
||||
|
||||
- (GCSChannelManager *)channelManager;
|
||||
- (BOOL)canConnect;
|
||||
|
||||
/* handling folder names */
|
||||
|
||||
- (NSString *)internalNameFromPath:(NSString *)_path;
|
||||
- (NSArray *)internalNamesFromPath:(NSString *)_path;
|
||||
- (NSString *)pathFromInternalName:(NSString *)_name;
|
||||
|
||||
/* operations */
|
||||
|
||||
- (BOOL)folderExistsAtPath:(NSString *)_path;
|
||||
- (NSArray *)listSubFoldersAtPath:(NSString *)_path recursive:(BOOL)_flag;
|
||||
|
||||
- (GCSFolder *)folderAtPath:(NSString *)_path;
|
||||
|
||||
- (NSException *)createFolderOfType:(NSString *)_type atPath:(NSString *)_path;
|
||||
- (NSException *)deleteFolderAtPath:(NSString *)_path;
|
||||
|
||||
/* folder types */
|
||||
|
||||
- (GCSFolderType *)folderTypeWithName:(NSString *)_name;
|
||||
|
||||
/* cache management */
|
||||
|
||||
- (void)reset;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* __GDLContentStore_GCSFolderManager_H__ */
|
|
@ -0,0 +1,895 @@
|
|||
/*
|
||||
Copyright (C) 2004-2007 SKYRIX Software AG
|
||||
|
||||
This file is part of OpenGroupware.org.
|
||||
|
||||
OGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
OGo 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 Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with OGo; see the file COPYING. If not, write to the
|
||||
Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GCSFolderManager.h"
|
||||
#include "GCSChannelManager.h"
|
||||
#include "GCSFolderType.h"
|
||||
#include "GCSFolder.h"
|
||||
#include "NSURL+GCS.h"
|
||||
#include "EOAdaptorChannel+GCS.h"
|
||||
#include "common.h"
|
||||
#include <GDLAccess/EOAdaptorChannel.h>
|
||||
#include <NGExtensions/NGResourceLocator.h>
|
||||
|
||||
/*
|
||||
Required database schema:
|
||||
|
||||
<arbitary table>
|
||||
c_path
|
||||
c_path1, path2, path3... [quickPathCount times]
|
||||
c_foldername
|
||||
|
||||
TODO:
|
||||
- add a local cache?
|
||||
*/
|
||||
|
||||
@implementation GCSFolderManager
|
||||
|
||||
static GCSFolderManager *fm = nil;
|
||||
static BOOL debugOn = NO;
|
||||
static BOOL debugSQLGen = NO;
|
||||
static BOOL debugPathTraversal = NO;
|
||||
static int quickPathCount = 4;
|
||||
static NSArray *emptyArray = nil;
|
||||
#if 0
|
||||
static NSString *GCSPathColumnName = @"c_path";
|
||||
static NSString *GCSTypeColumnName = @"c_folder_type";
|
||||
static NSString *GCSTypeRecordName = @"c_folder_type";
|
||||
#endif
|
||||
static NSString *GCSPathRecordName = @"c_path";
|
||||
static NSString *GCSGenericFolderTypeName = @"Container";
|
||||
static const char *GCSPathColumnPattern = "c_path%i";
|
||||
static NSCharacterSet *asciiAlphaNumericCS = nil;
|
||||
|
||||
+ (void)initialize {
|
||||
NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
|
||||
|
||||
debugOn = [ud boolForKey:@"GCSFolderManagerDebugEnabled"];
|
||||
debugSQLGen = [ud boolForKey:@"GCSFolderManagerSQLDebugEnabled"];
|
||||
emptyArray = [[NSArray alloc] init];
|
||||
if (!asciiAlphaNumericCS)
|
||||
{
|
||||
asciiAlphaNumericCS
|
||||
= [NSCharacterSet characterSetWithCharactersInString:
|
||||
@"0123456789"
|
||||
@"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
@"abcdefghijklmnopqrstuvwxyz"];
|
||||
[asciiAlphaNumericCS retain];
|
||||
}
|
||||
}
|
||||
|
||||
+ (id)defaultFolderManager {
|
||||
NSString *s;
|
||||
NSURL *url;
|
||||
if (fm) return fm;
|
||||
|
||||
s = [[NSUserDefaults standardUserDefaults] stringForKey:@"OCSFolderInfoURL"];
|
||||
if ([s length] == 0) {
|
||||
NSLog(@"ERROR(%s): default 'OCSFolderInfoURL' is not configured.",
|
||||
__PRETTY_FUNCTION__);
|
||||
return nil;
|
||||
}
|
||||
if ((url = [NSURL URLWithString:s]) == nil) {
|
||||
NSLog(@"ERROR(%s): default 'OCSFolderInfoURL' is not a valid URL: '%@'",
|
||||
__PRETTY_FUNCTION__, s);
|
||||
return nil;
|
||||
}
|
||||
if ((fm = [[self alloc] initWithFolderInfoLocation:url]) == nil) {
|
||||
NSLog(@"ERROR(%s): could not create folder manager with URL: '%@'",
|
||||
__PRETTY_FUNCTION__, [url absoluteString]);
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSLog(@"Note: setup default manager at: %@", url);
|
||||
return fm;
|
||||
}
|
||||
|
||||
- (NSDictionary *)loadDefaultFolderTypes {
|
||||
NSMutableDictionary *typeMap;
|
||||
NSArray *types;
|
||||
unsigned i, count;
|
||||
|
||||
|
||||
types = [[GCSFolderType resourceLocator] lookupAllFilesWithExtension:@"ocs"
|
||||
doReturnFullPath:NO];
|
||||
if ((count = [types count]) == 0) {
|
||||
[self logWithFormat:@"Note: no GCS folder types found."];
|
||||
return nil;
|
||||
}
|
||||
|
||||
typeMap = [NSMutableDictionary dictionaryWithCapacity:count];
|
||||
|
||||
[self logWithFormat:@"Note: loading %d GCS folder types:", count];
|
||||
for (i = 0, count = [types count]; i < count; i++) {
|
||||
NSString *type;
|
||||
GCSFolderType *typeObject;
|
||||
|
||||
type = [[types objectAtIndex:i] stringByDeletingPathExtension];
|
||||
typeObject = [[GCSFolderType alloc] initWithFolderTypeName:type];
|
||||
|
||||
[self logWithFormat:@" %@: %s",
|
||||
type, [typeObject isNotNull] ? "OK" : "FAIL"];
|
||||
[typeMap setObject:typeObject forKey:type];
|
||||
[typeObject release];
|
||||
}
|
||||
|
||||
return typeMap;
|
||||
}
|
||||
|
||||
- (id)initWithFolderInfoLocation:(NSURL *)_url {
|
||||
if (_url == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): missing folder info url!",
|
||||
__PRETTY_FUNCTION__];
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
if ((self = [super init])) {
|
||||
self->channelManager = [[GCSChannelManager defaultChannelManager] retain];
|
||||
self->folderInfoLocation = [_url retain];
|
||||
self->folderNamePrefix = nil;
|
||||
|
||||
if ([[self folderInfoTableName] length] == 0) {
|
||||
[self logWithFormat:@"ERROR(%s): missing tablename in URL: %@",
|
||||
__PRETTY_FUNCTION__, [_url absoluteString]];
|
||||
[self release];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* register default folder types */
|
||||
self->nameToType = [[self loadDefaultFolderTypes] copy];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self->nameToType release];
|
||||
[self->folderInfoLocation release];
|
||||
[self->channelManager release];
|
||||
[self->folderNamePrefix release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
/* accessors */
|
||||
|
||||
- (void) setFolderNamePrefix:(NSString *)_folderNamePrefix
|
||||
{
|
||||
ASSIGN(self->folderNamePrefix, _folderNamePrefix);
|
||||
}
|
||||
|
||||
- (NSString *) folderNamePrefix
|
||||
{
|
||||
return self->folderNamePrefix;
|
||||
}
|
||||
|
||||
- (NSURL *)folderInfoLocation {
|
||||
return self->folderInfoLocation;
|
||||
}
|
||||
|
||||
- (NSString *)folderInfoTableName {
|
||||
return [[self folderInfoLocation] gcsTableName];
|
||||
}
|
||||
|
||||
/* connection */
|
||||
|
||||
- (GCSChannelManager *)channelManager {
|
||||
return self->channelManager;
|
||||
}
|
||||
|
||||
- (EOAdaptorChannel *)acquireOpenChannel {
|
||||
EOAdaptorChannel *ch;
|
||||
|
||||
ch = [[self channelManager] acquireOpenChannelForURL:
|
||||
[self folderInfoLocation]];
|
||||
return ch;
|
||||
}
|
||||
- (void)releaseChannel:(EOAdaptorChannel *)_channel {
|
||||
[[self channelManager] releaseChannel:_channel];
|
||||
if (debugOn) [self debugWithFormat:@"released channel: %@", _channel];
|
||||
}
|
||||
|
||||
- (BOOL)canConnect {
|
||||
return [[self channelManager] canConnect:[self folderInfoLocation]];
|
||||
}
|
||||
|
||||
- (NSArray *)performSQL:(NSString *)_sql {
|
||||
EOAdaptorChannel *channel;
|
||||
NSException *ex;
|
||||
NSMutableArray *rows;
|
||||
NSDictionary *row;
|
||||
NSArray *attrs;
|
||||
|
||||
/* acquire channel */
|
||||
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
if (debugOn) [self debugWithFormat:@"could not acquire channel!"];
|
||||
return nil;
|
||||
}
|
||||
if (debugOn) [self debugWithFormat:@"acquired channel: %@", channel];
|
||||
|
||||
/* run SQL */
|
||||
|
||||
if ((ex = [channel evaluateExpressionX:_sql]) != nil) {
|
||||
[self logWithFormat:@"ERROR(%s): cannot execute\n SQL '%@':\n %@",
|
||||
__PRETTY_FUNCTION__, _sql, ex];
|
||||
[self releaseChannel:channel];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* fetch results */
|
||||
|
||||
attrs = [channel describeResults:NO /* do not beautify names */];
|
||||
rows = [NSMutableArray arrayWithCapacity:16];
|
||||
while ((row = [channel fetchAttributes:attrs withZone:NULL]) != nil)
|
||||
[rows addObject:row];
|
||||
|
||||
[self releaseChannel:channel];
|
||||
return rows;
|
||||
}
|
||||
|
||||
/* row factory */
|
||||
|
||||
- (GCSFolder *)folderForRecord:(NSDictionary *)_record {
|
||||
GCSFolder *folder;
|
||||
GCSFolderType *folderType;
|
||||
NSString *folderTypeName, *locationString, *folderName, *path;
|
||||
NSNumber *folderId;
|
||||
NSURL *location, *quickLocation, *aclLocation;
|
||||
|
||||
if (_record == nil) return nil;
|
||||
|
||||
folderTypeName = [_record objectForKey:@"c_folder_type"];
|
||||
if (![folderTypeName isNotNull]) {
|
||||
[self logWithFormat:@"ERROR(%s): missing type in folder: %@",
|
||||
__PRETTY_FUNCTION__, _record];
|
||||
return nil;
|
||||
}
|
||||
if ((folderType = [self folderTypeWithName:folderTypeName]) == nil) {
|
||||
[self logWithFormat:
|
||||
@"ERROR(%s): could not resolve type '%@' of folder: %@",
|
||||
__PRETTY_FUNCTION__,
|
||||
folderTypeName, [_record valueForKey:@"c_path"]];
|
||||
return nil;
|
||||
}
|
||||
|
||||
folderId = [_record objectForKey:@"c_folder_id"];
|
||||
folderName = [_record objectForKey:@"c_path"];
|
||||
path = [self pathFromInternalName:folderName];
|
||||
|
||||
locationString = [_record objectForKey:@"c_location"];
|
||||
location = [locationString isNotNull]
|
||||
? [NSURL URLWithString:locationString]
|
||||
: nil;
|
||||
if (location == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): missing folder location in record: %@",
|
||||
__PRETTY_FUNCTION__, _record];
|
||||
return nil;
|
||||
}
|
||||
|
||||
locationString = [_record objectForKey:@"c_quick_location"];
|
||||
quickLocation = [locationString isNotNull]
|
||||
? [NSURL URLWithString:locationString]
|
||||
: nil;
|
||||
|
||||
if (quickLocation == nil) {
|
||||
[self logWithFormat:@"WARNING(%s): missing quick location in record: %@",
|
||||
__PRETTY_FUNCTION__, _record];
|
||||
}
|
||||
|
||||
locationString = [_record objectForKey:@"c_acl_location"];
|
||||
aclLocation = [locationString isNotNull]
|
||||
? [NSURL URLWithString:locationString]
|
||||
: nil;
|
||||
|
||||
folder = [[GCSFolder alloc] initWithPath:path primaryKey:folderId
|
||||
folderTypeName:folderTypeName
|
||||
folderType:folderType
|
||||
location:location quickLocation:quickLocation
|
||||
aclLocation:aclLocation
|
||||
folderManager:self];
|
||||
return [folder autorelease];
|
||||
}
|
||||
|
||||
/* path SQL */
|
||||
|
||||
- (NSString *)generateSQLWhereForInternalNames:(NSArray *)_names
|
||||
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
|
||||
{
|
||||
/* generates a WHERE qualifier for matching the "quick" entries */
|
||||
NSMutableString *sql;
|
||||
unsigned i, count;
|
||||
|
||||
if ((count = [_names count]) == 0) {
|
||||
[self debugWithFormat:@"WARNING(%s): passed in empty name array!",
|
||||
__PRETTY_FUNCTION__];
|
||||
return @"1 = 2";
|
||||
}
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:(count * 8)];
|
||||
for (i = 0; i < quickPathCount; i++) {
|
||||
NSString *pathColumn;
|
||||
char buf[32];
|
||||
|
||||
sprintf(buf, GCSPathColumnPattern, (i + 1));
|
||||
pathColumn = [[NSString alloc] initWithCString:buf];
|
||||
|
||||
/* Note: the AND addition must be inside the if's for non-exact stuff */
|
||||
|
||||
if (i < count) {
|
||||
/* exact match, regular column */
|
||||
if ([sql length] > 0) [sql appendString:@" AND "];
|
||||
[sql appendString:pathColumn];
|
||||
[sql appendFormat:@" = '%@'", [_names objectAtIndex:i]];
|
||||
}
|
||||
else if (_beExact) {
|
||||
/* exact match, ensure that all additional quick-cols are NULL */
|
||||
if ([sql length] > 0) [sql appendString:@" AND "];
|
||||
[sql appendString:pathColumn];
|
||||
[sql appendString:@" IS NULL"];
|
||||
if (debugPathTraversal) [self logWithFormat:@"BE EXACT, NULL columns"];
|
||||
}
|
||||
else if (_directSubs) {
|
||||
/* fetch immediate subfolders */
|
||||
if ([sql length] > 0) [sql appendString:@" AND "];
|
||||
[sql appendString:pathColumn];
|
||||
if (i == count) {
|
||||
/* if it is a direct subfolder, the next path cannot be empty */
|
||||
[sql appendString:@" IS NOT NULL"];
|
||||
if (debugPathTraversal)
|
||||
[self logWithFormat:@"DIRECT SUBS, first level"];
|
||||
}
|
||||
else {
|
||||
/* but for 'direct' subfolders, all following things must be empty */
|
||||
[sql appendString:@" IS NULL"];
|
||||
if (debugPathTraversal)
|
||||
[self logWithFormat:@"DIRECT SUBS, lower level"];
|
||||
}
|
||||
}
|
||||
|
||||
[pathColumn release];
|
||||
}
|
||||
|
||||
if (_beExact && (count > quickPathCount)) {
|
||||
[sql appendString:@" AND c_foldername = '"];
|
||||
[sql appendString:[_names lastObject]];
|
||||
[sql appendString:@"'"];
|
||||
}
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
- (NSString *)generateSQLPathFetchForInternalNames:(NSArray *)_names
|
||||
exactMatch:(BOOL)_beExact orDirectSubfolderMatch:(BOOL)_directSubs
|
||||
{
|
||||
/* fetches the 'path' subset for a given quick-names */
|
||||
NSMutableString *sql;
|
||||
NSString *ws;
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:_names
|
||||
exactMatch:_beExact orDirectSubfolderMatch:_directSubs];
|
||||
if ([ws length] == 0)
|
||||
return nil;
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:256];
|
||||
[sql appendString:@"SELECT c_path FROM "];
|
||||
[sql appendString:[self folderInfoTableName]];
|
||||
[sql appendString:@" WHERE "];
|
||||
[sql appendString:ws];
|
||||
if (debugSQLGen) [self logWithFormat:@"PathFetch-SQL: %@", sql];
|
||||
return sql;
|
||||
}
|
||||
|
||||
/* handling folder names */
|
||||
|
||||
- (BOOL)_isStandardizedPath:(NSString *)_path {
|
||||
if (![_path isAbsolutePath]) return NO;
|
||||
if ([_path rangeOfString:@".."].length > 0) return NO;
|
||||
if ([_path rangeOfString:@"~"].length > 0) return NO;
|
||||
if ([_path rangeOfString:@"//"].length > 0) return NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString *)internalNameFromPath:(NSString *)_path {
|
||||
// TODO: ensure proper path and SQL escaping!
|
||||
|
||||
if (![self _isStandardizedPath:_path]) {
|
||||
[self debugWithFormat:@"%s: not a standardized path: '%@'",
|
||||
__PRETTY_FUNCTION__, _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ([_path hasSuffix:@"/"] && [_path length] > 1)
|
||||
_path = [_path substringToIndex:([_path length] - 1)];
|
||||
|
||||
return _path;
|
||||
}
|
||||
- (NSArray *)internalNamesFromPath:(NSString *)_path {
|
||||
NSString *fname;
|
||||
NSArray *fnames;
|
||||
|
||||
if ((fname = [self internalNameFromPath:_path]) == nil)
|
||||
return nil;
|
||||
|
||||
if ([fname hasPrefix:@"/"])
|
||||
fname = [fname substringFromIndex:1];
|
||||
|
||||
fnames = [fname componentsSeparatedByString:@"/"];
|
||||
if ([fnames count] == 0)
|
||||
return nil;
|
||||
|
||||
return fnames;
|
||||
}
|
||||
- (NSString *)pathFromInternalName:(NSString *)_name {
|
||||
/* for incomplete pathes, like '/Users/helge/' */
|
||||
return _name;
|
||||
}
|
||||
- (NSString *)pathPartFromInternalName:(NSString *)_name {
|
||||
/* for incomplete pathes, like 'Users/' */
|
||||
return _name;
|
||||
}
|
||||
|
||||
- (NSDictionary *)filterRecords:(NSArray *)_records forPath:(NSString *)_path {
|
||||
unsigned i, count;
|
||||
NSString *name;
|
||||
|
||||
if (_records == nil) return nil;
|
||||
if ((name = [self internalNameFromPath:_path]) == nil) return nil;
|
||||
|
||||
for (i = 0, count = [_records count]; i < count; i++) {
|
||||
NSDictionary *record;
|
||||
NSString *recName;
|
||||
|
||||
record = [_records objectAtIndex:i];
|
||||
recName = [record objectForKey:GCSPathRecordName];
|
||||
#if 0
|
||||
[self logWithFormat:@"check '%@' vs '%@' (%@)...",
|
||||
name, recName, [_records objectAtIndex:i]];
|
||||
#endif
|
||||
|
||||
if ([name isEqualToString:recName])
|
||||
return [_records objectAtIndex:i];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (BOOL)folderExistsAtPath:(NSString *)_path {
|
||||
NSString *fname;
|
||||
NSArray *fnames, *records;
|
||||
NSString *sql;
|
||||
unsigned count;
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return NO;
|
||||
}
|
||||
|
||||
sql = [self generateSQLPathFetchForInternalNames:fnames
|
||||
exactMatch:YES orDirectSubfolderMatch:NO];
|
||||
if ([sql length] == 0) {
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
return NO;
|
||||
}
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return NO;
|
||||
}
|
||||
|
||||
if ((count = [records count]) == 0)
|
||||
return NO;
|
||||
|
||||
fname = [self internalNameFromPath:_path];
|
||||
if (count == 1) {
|
||||
NSDictionary *record;
|
||||
NSString *sname;
|
||||
|
||||
record = [records objectAtIndex:0];
|
||||
sname = [record objectForKey:GCSPathRecordName];
|
||||
return [fname isEqualToString:sname];
|
||||
}
|
||||
|
||||
[self logWithFormat:@"records: %@", records];
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSArray *)listSubFoldersAtPath:(NSString *)_path recursive:(BOOL)_recursive{
|
||||
NSMutableArray *result;
|
||||
NSString *fname;
|
||||
NSArray *fnames, *records;
|
||||
NSString *sql;
|
||||
unsigned i, count;
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
sql = [self generateSQLPathFetchForInternalNames:fnames
|
||||
exactMatch:NO orDirectSubfolderMatch:(_recursive ? NO : YES)];
|
||||
if ([sql length] == 0) {
|
||||
[self debugWithFormat:@"got no SQL for names: %@", fnames];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((count = [records count]) == 0)
|
||||
return emptyArray;
|
||||
|
||||
result = [NSMutableArray arrayWithCapacity:(count > 128 ? 128 : count)];
|
||||
|
||||
fname = [self internalNameFromPath:_path];
|
||||
fname = [fname stringByAppendingString:@"/"]; /* add slash */
|
||||
for (i = 0; i < count; i++) {
|
||||
NSDictionary *record;
|
||||
NSString *sname, *spath;
|
||||
|
||||
record = [records objectAtIndex:i];
|
||||
sname = [record objectForKey:GCSPathRecordName];
|
||||
if (![sname hasPrefix:fname]) /* does not match at all ... */
|
||||
continue;
|
||||
|
||||
/* strip prefix and following slash */
|
||||
sname = [sname substringFromIndex:[fname length]];
|
||||
spath = [self pathPartFromInternalName:sname];
|
||||
|
||||
if (_recursive) {
|
||||
if ([spath length] > 0) [result addObject:spath];
|
||||
}
|
||||
else {
|
||||
/* direct children only, so exclude everything with a slash */
|
||||
if ([sname rangeOfString:@"/"].length == 0 && [spath length] > 0)
|
||||
[result addObject:spath];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (GCSFolder *)folderAtPath:(NSString *)_path {
|
||||
NSMutableString *sql;
|
||||
NSArray *fnames, *records;
|
||||
NSString *ws;
|
||||
NSDictionary *record;
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
/* generate SQL to fetch folder attributes */
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:fnames
|
||||
exactMatch:YES orDirectSubfolderMatch:NO];
|
||||
|
||||
sql = [NSMutableString stringWithCapacity:256];
|
||||
[sql appendString:@"SELECT "];
|
||||
[sql appendString:@"c_folder_id, "];
|
||||
[sql appendString:@"c_path, "];
|
||||
[sql appendString:@"c_location, c_quick_location, c_acl_location,"];
|
||||
[sql appendString:@" c_folder_type"];
|
||||
[sql appendString:@" FROM "];
|
||||
[sql appendString:[self folderInfoTableName]];
|
||||
[sql appendString:@" WHERE "];
|
||||
[sql appendString:ws];
|
||||
|
||||
/* fetching */
|
||||
|
||||
if ((records = [self performSQL:sql]) == nil) {
|
||||
[self logWithFormat:@"ERROR(%s): executing SQL failed: '%@'",
|
||||
__PRETTY_FUNCTION__, sql];
|
||||
return nil;
|
||||
}
|
||||
|
||||
// TODO: need to filter on path
|
||||
// required when we start to have deeper hierarchies
|
||||
// => isn't that already done below?
|
||||
|
||||
if ([records count] != 1) {
|
||||
if ([records count] == 0) {
|
||||
[self debugWithFormat:@"found no records for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
[self logWithFormat:@"ERROR(%s): more than one row for path: '%@'",
|
||||
__PRETTY_FUNCTION__, _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
if ((record = [self filterRecords:records forPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"found no record for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [self folderForRecord:record];
|
||||
}
|
||||
|
||||
- (NSString *)sqlCreateWithTableName: (NSString *)_tabName {
|
||||
return [NSString stringWithFormat: @"CREATE TABLE %@ (\n"
|
||||
@" c_name VARCHAR (256) NOT NULL,\n"
|
||||
@" c_content VARCHAR (100000) NOT NULL,\n"
|
||||
@" c_creationdate INT4 NOT NULL,\n"
|
||||
@" c_lastmodified INT4 NOT NULL,\n"
|
||||
@" c_version INT4 NOT NULL\n"
|
||||
@")",
|
||||
_tabName];
|
||||
}
|
||||
|
||||
- (NSString *)sqlAclCreateWithTableName: (NSString *)_tabName {
|
||||
return [NSString stringWithFormat: @"CREATE TABLE %@ (\n"
|
||||
@" c_uid VARCHAR (256) NOT NULL,\n"
|
||||
@" c_object VARCHAR (256) NOT NULL,\n"
|
||||
@" c_role VARCHAR (80) NOT NULL\n"
|
||||
@")",
|
||||
_tabName];
|
||||
}
|
||||
|
||||
- (NSString *)baseTableNameForFolderAtPath:(NSString *)_path {
|
||||
NSMutableString *fixedPath;
|
||||
unsigned int count, max;
|
||||
unichar currentChar;
|
||||
|
||||
fixedPath = [NSMutableString new];
|
||||
[fixedPath autorelease];
|
||||
|
||||
if (self->folderNamePrefix != nil)
|
||||
[fixedPath appendString: self->folderNamePrefix];
|
||||
|
||||
max = [_path length];
|
||||
for (count = 0; count < max; count++) {
|
||||
currentChar = [_path characterAtIndex: count];
|
||||
if ([asciiAlphaNumericCS characterIsMember: currentChar])
|
||||
[fixedPath appendFormat: @"%Lc", currentChar];
|
||||
else
|
||||
[fixedPath appendString: @"_"];
|
||||
}
|
||||
|
||||
return (([fixedPath length] < 49)
|
||||
? (NSString *)fixedPath : [fixedPath substringToIndex: 49]);
|
||||
}
|
||||
|
||||
- (NSString *)finalizedTableNameForBaseName:(NSString *)_baseName
|
||||
atBaseURL:(NSString *)_baseURL
|
||||
withChannel:(EOAdaptorChannel *)_channel {
|
||||
NSString *potentialName, *sqlTestFormat, *sqlTest;
|
||||
unsigned int count;
|
||||
|
||||
potentialName = _baseName;
|
||||
sqlTestFormat = [NSString stringWithFormat: @"SELECT * FROM %@"
|
||||
@" WHERE c_location = '%@/%%@'"
|
||||
@" OR c_quick_location = '%@/%%@_quick'"
|
||||
@" OR c_acl_location = '%@/%%@_acl'",
|
||||
[self folderInfoTableName],
|
||||
_baseURL, _baseURL, _baseURL];
|
||||
|
||||
sqlTest = [NSString stringWithFormat: sqlTestFormat,
|
||||
potentialName, potentialName, potentialName];
|
||||
count = 0;
|
||||
while ([[self performSQL: sqlTest] isNotEmpty]) {
|
||||
count++;
|
||||
potentialName = [NSString stringWithFormat: @"%@%d", _baseName, count];
|
||||
sqlTest = [NSString stringWithFormat: sqlTestFormat,
|
||||
potentialName, potentialName, potentialName];
|
||||
}
|
||||
|
||||
return potentialName;
|
||||
}
|
||||
|
||||
- (NSException *)createFolderOfType:(NSString *)_type atPath:(NSString *)_path{
|
||||
// TBD: badly broken, needs to be wrapped in a transaction.
|
||||
// TBD: would be best to perform all operations as a single SQL statement.
|
||||
GCSFolderType *ftype;
|
||||
NSString *tableName, *quickTableName, *aclTableName;
|
||||
NSString *baseURL, *pathElement;
|
||||
EOAdaptorChannel *channel;
|
||||
NSEnumerator *pathElements;
|
||||
NSMutableArray *paths;
|
||||
NSException *error;
|
||||
NSString *sql;
|
||||
|
||||
// TBD: fix SQL injection issue!
|
||||
sql = [NSString stringWithFormat: @"SELECT * FROM %@ WHERE c_path = '%@'",
|
||||
[self folderInfoTableName], _path];
|
||||
if ([[self performSQL: sql] isNotEmpty]) {
|
||||
return [NSException exceptionWithName:@"GCSExitingFolder"
|
||||
reason:@"a folder already exists at that path"
|
||||
userInfo:nil];
|
||||
}
|
||||
if ((ftype = [self folderTypeWithName:_type]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSMissingFolderType"
|
||||
reason:@"missing folder type"userInfo:nil];
|
||||
}
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not open channel"
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
tableName = [self baseTableNameForFolderAtPath: _path];
|
||||
baseURL
|
||||
= [[folderInfoLocation absoluteString] stringByDeletingLastPathComponent];
|
||||
tableName = [self finalizedTableNameForBaseName: tableName
|
||||
atBaseURL: baseURL withChannel: channel];
|
||||
quickTableName = [tableName stringByAppendingString: @"_quick"];
|
||||
aclTableName = [tableName stringByAppendingString: @"_acl"];
|
||||
|
||||
sql = [@"DROP TABLE " stringByAppendingString:quickTableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil)
|
||||
; // 'DROP TABLE' is allowed to fail (DROP IF EXISTS is not in PG<8.2)
|
||||
|
||||
sql = [@"DROP TABLE " stringByAppendingString:tableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil)
|
||||
; // 'DROP TABLE' is allowed to fail (DROP IF EXISTS is not in PG<8.2)
|
||||
|
||||
sql = [@"DROP TABLE " stringByAppendingString:aclTableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil)
|
||||
; // 'DROP TABLE' is allowed to fail (DROP IF EXISTS is not in PG<8.2)
|
||||
|
||||
sql = [self sqlCreateWithTableName: tableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil)
|
||||
return error;
|
||||
|
||||
sql = [ftype sqlQuickCreateWithTableName: quickTableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil) {
|
||||
/* 'rollback' TBD: wrap in proper tx */
|
||||
sql = [@"DROP TABLE " stringByAppendingString:tableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil) {
|
||||
[self warnWithFormat:@"failed to drop freshly created table: %@",
|
||||
tableName];
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
sql = [self sqlAclCreateWithTableName: aclTableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil) {
|
||||
/* 'rollback' TBD: wrap in proper tx */
|
||||
sql = [@"DROP TABLE " stringByAppendingString:quickTableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil) {
|
||||
[self warnWithFormat:@"failed to drop freshly created table: %@",
|
||||
tableName];
|
||||
}
|
||||
sql = [@"DROP TABLE " stringByAppendingString:tableName];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil) {
|
||||
[self warnWithFormat:@"failed to drop freshly created table: %@",
|
||||
tableName];
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
paths = [[NSMutableArray alloc] initWithCapacity: 5];
|
||||
|
||||
pathElements = [[_path componentsSeparatedByString: @"/"] objectEnumerator];
|
||||
while ((pathElement = [pathElements nextObject]) != nil) {
|
||||
NSString *p = [[NSString alloc] initWithFormat: @"'%@'", pathElement];
|
||||
[paths addObject: p];
|
||||
[p release]; p = nil;
|
||||
}
|
||||
|
||||
while ([paths count] < 5)
|
||||
[paths addObject: @"NULL"];
|
||||
|
||||
// TBD: fix SQL injection issues
|
||||
sql = [NSString stringWithFormat: @"INSERT INTO %@"
|
||||
@" (c_path, c_path1, c_path2, c_path3, c_path4,"
|
||||
@" c_foldername, c_location, c_quick_location,"
|
||||
@" c_acl_location, c_folder_type)"
|
||||
@" VALUES ('%@', %@, %@, %@, %@, '%@', '%@/%@',"
|
||||
@" '%@/%@', '%@/%@', '%@')",
|
||||
[self folderInfoTableName], _path,
|
||||
[paths objectAtIndex: 1], [paths objectAtIndex: 2],
|
||||
[paths objectAtIndex: 3], [paths objectAtIndex: 4],
|
||||
[_path lastPathComponent],
|
||||
baseURL, tableName,
|
||||
baseURL, quickTableName,
|
||||
baseURL, aclTableName,
|
||||
_type];
|
||||
if ((error = [channel evaluateExpressionX:sql]) != nil)
|
||||
return error;
|
||||
|
||||
[paths release]; paths = nil;
|
||||
[self releaseChannel: channel];
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSException *)deleteFolderAtPath:(NSString *)_path {
|
||||
GCSFolder *folder;
|
||||
NSArray *fnames;
|
||||
NSString *sql, *ws;
|
||||
EOAdaptorChannel *channel;
|
||||
NSException *ex;
|
||||
|
||||
if ((folder = [self folderAtPath:_path]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSMissingFolder"
|
||||
reason:@"missing folder"
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
if ((fnames = [self internalNamesFromPath:_path]) == nil) {
|
||||
[self debugWithFormat:@"got no internal names for path: '%@'", _path];
|
||||
return nil;
|
||||
}
|
||||
|
||||
ws = [self generateSQLWhereForInternalNames:fnames
|
||||
exactMatch:YES orDirectSubfolderMatch:NO];
|
||||
|
||||
sql = [NSString stringWithFormat: @"DELETE FROM %@ WHERE %@",
|
||||
[self folderInfoTableName], ws];
|
||||
if ((channel = [self acquireOpenChannel]) == nil) {
|
||||
return [NSException exceptionWithName:@"GCSNoChannel"
|
||||
reason:@"could not "
|
||||
userInfo:nil];
|
||||
}
|
||||
|
||||
if ((ex = [channel evaluateExpressionX:sql]) != nil) {
|
||||
[self releaseChannel:channel];
|
||||
return ex;
|
||||
}
|
||||
|
||||
[self releaseChannel:channel];
|
||||
|
||||
return [folder deleteFolder];
|
||||
}
|
||||
|
||||
/* folder types */
|
||||
|
||||
- (GCSFolderType *)folderTypeWithName:(NSString *)_name {
|
||||
if ([_name length] == 0)
|
||||
_name = GCSGenericFolderTypeName;
|
||||
|
||||
return [self->nameToType objectForKey:[_name lowercaseString]];
|
||||
}
|
||||
|
||||
/* cache management */
|
||||
|
||||
- (void)reset {
|
||||
/* does nothing in the moment, but we need a way to signal refreshes */
|
||||
}
|
||||
|
||||
/* debugging */
|
||||
|
||||
- (BOOL)isDebuggingEnabled {
|
||||
return debugOn;
|
||||
}
|
||||
|
||||
/* description */
|
||||
|
||||
- (NSString *)description {
|
||||
NSMutableString *ms;
|
||||
|
||||
ms = [NSMutableString stringWithCapacity:256];
|
||||
[ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
|
||||
|
||||
[ms appendFormat:@" url=%@", [self->folderInfoLocation absoluteString]];
|
||||
[ms appendFormat:@" channel-manager=0x%p", [self channelManager]];
|
||||
|
||||
[ms appendString:@">"];
|
||||
return ms;
|
||||
}
|
||||
|
||||
@end /* GCSFolderManager */
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue