Rewrite low level sax routines to move towards better support for subclassing

of sax handlers.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@16778 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
CaS 2003-05-23 08:58:52 +00:00
parent 83f5979a69
commit fbf3bb6fd9
4 changed files with 302 additions and 121 deletions

View file

@ -1,3 +1,9 @@
2003-05-23 Richard Frith-Macdonald <rfm@gnu.org>
* Source/Additions/GSXML.m: Some work towards making it possible to
subclass GSTreeSAXHandler cleanly, so you can build a tree
representation of a document but still handle data incrementally.
2003-05-22 Richard Frith-Macdonald <rfm@gnu.org> 2003-05-22 Richard Frith-Macdonald <rfm@gnu.org>
* Source/Additions/GSXML.m: ([GSXPathContext-evaluateExpression:]) * Source/Additions/GSXML.m: ([GSXPathContext-evaluateExpression:])

View file

@ -203,6 +203,8 @@
{ {
void *lib; // xmlSAXHandlerPtr void *lib; // xmlSAXHandlerPtr
GSXMLParser *parser; GSXMLParser *parser;
@protected
BOOL isHtmlHandler;
} }
+ (GSSAXHandler*) handler; + (GSSAXHandler*) handler;
- (void*) lib; - (void*) lib;

View file

@ -77,19 +77,20 @@ extern int xmlGetWarningsDefaultValue;
* *
*/ */
static Class NSString_class; static Class NSString_class;
static Class treeClass;
static IMP usImp; static IMP usImp;
static SEL usSel; static SEL usSel;
inline static NSString* inline static NSString*
UTF8Str(const char *bytes) UTF8Str(const unsigned char *bytes)
{ {
return (*usImp)(NSString_class, usSel, bytes); return (*usImp)(NSString_class, usSel, bytes);
} }
inline static NSString* inline static NSString*
UTF8StrLen(const char *bytes, unsigned length) UTF8StrLen(const unsigned char *bytes, unsigned length)
{ {
char *buf = NSZoneMalloc(NSDefaultMallocZone(), length+1); unsigned char *buf = NSZoneMalloc(NSDefaultMallocZone(), length+1);
NSString *str; NSString *str;
memcpy(buf, bytes, length); memcpy(buf, bytes, length);
@ -110,11 +111,13 @@ setupCache()
NSString_class = [NSString class]; NSString_class = [NSString class];
usSel = @selector(stringWithUTF8String:); usSel = @selector(stringWithUTF8String:);
usImp = [NSString_class methodForSelector: usSel]; usImp = [NSString_class methodForSelector: usSel];
treeClass = [GSTreeSAXHandler class];
} }
} }
static xmlParserInputPtr static xmlParserInputPtr
loadEntityFunction(const char *url, const char *eid, xmlParserCtxtPtr ctxt); loadEntityFunction(const unsigned char *url, const unsigned char *eid,
xmlParserCtxtPtr ctxt);
@interface GSXMLDocument (GSPrivate) @interface GSXMLDocument (GSPrivate)
- (id) _initFrom: (void*)data parent: (id)p ownsLib: (BOOL)f; - (id) _initFrom: (void*)data parent: (id)p ownsLib: (BOOL)f;
@ -2207,7 +2210,7 @@ static NSString *endMarker = @"At end of incremental parse";
- (BOOL) _initLibXML - (BOOL) _initLibXML
{ {
const char *file; const unsigned char *file;
if ([src isKindOfClass: [NSString class]]) if ([src isKindOfClass: [NSString class]])
{ {
@ -2329,10 +2332,11 @@ static NSString *endMarker = @"At end of incremental parse";
* We can use a (xmlParserCtxtPtr) cast because xmlParserCtxt and * We can use a (xmlParserCtxtPtr) cast because xmlParserCtxt and
* htmlParserCtxt are the same structure (and will remain, cf libxml author). * htmlParserCtxt are the same structure (and will remain, cf libxml author).
*/ */
#define HANDLER (GSSAXHandler*)(((xmlParserCtxtPtr)ctx)->_private) #define HANDLER ((GSSAXHandler*)(((xmlParserCtxtPtr)ctx)->_private))
static xmlParserInputPtr static xmlParserInputPtr
loadEntityFunction(const char *url, const char *eid, xmlParserCtxtPtr ctx) loadEntityFunction(const unsigned char *url, const unsigned char *eid,
xmlParserCtxtPtr ctx)
{ {
extern xmlParserInputPtr xmlNewInputFromFile(); extern xmlParserInputPtr xmlNewInputFromFile();
NSString *file; NSString *file;
@ -2476,217 +2480,385 @@ loadEntityFunction(const char *url, const char *eid, xmlParserCtxtPtr ctx)
return ret; return ret;
} }
#define TREEFUN(NAME,ARGS) ((HANDLER->isHtmlHandler == YES) ? (*(htmlDefaultSAXHandler.NAME))ARGS : (*(xmlDefaultSAXHandler.NAME))ARGS)
#define START(SELNAME, RET, ARGS) \
static SEL sel; \
static RET (*treeImp)ARGS = 0; \
RET (*imp)ARGS; \
\
NSCAssert(ctx,@"No Context"); \
\
if (treeImp == 0) \
{ \
sel = @selector(SELNAME); \
treeImp = (RET (*)ARGS)[treeClass instanceMethodForSelector: sel];\
} \
imp = (RET (*)ARGS)[HANDLER methodForSelector: sel]
static void static void
startDocumentFunction(void *ctx) startDocumentFunction(void *ctx)
{ {
NSCAssert(ctx,@"No Context"); START(startDocument, void, (id,SEL));
[HANDLER startDocument];
if (imp == treeImp)
{
TREEFUN(startDocument, (ctx));
}
else
{
(*imp)(HANDLER, sel);
}
} }
static void static void
endDocumentFunction(void *ctx) endDocumentFunction(void *ctx)
{ {
NSCAssert(ctx,@"No Context"); START(endDocument, void, (id,SEL));
[HANDLER endDocument];
if (imp == treeImp)
{
TREEFUN(endDocument, (ctx));
}
else
{
(*imp)(HANDLER, sel);
}
} }
static int static int
isStandaloneFunction(void *ctx) isStandaloneFunction(void *ctx)
{ {
NSCAssert(ctx,@"No Context"); START(isStandalone, int, (id,SEL));
return [HANDLER isStandalone];
if (imp == treeImp)
{
return TREEFUN(isStandalone, (ctx));
}
else
{
return (*imp)(HANDLER, sel);
}
} }
static int static int
hasInternalSubsetFunction(void *ctx) hasInternalSubsetFunction(void *ctx)
{ {
int has; int has = -1;
START(hasInternalSubset, int, (id,SEL));
NSCAssert(ctx,@"No Context"); if (imp != treeImp)
has = [HANDLER hasInternalSubset]; {
has = (*imp)(HANDLER, sel);
}
if (has < 0) if (has < 0)
has = (*xmlDefaultSAXHandler.hasInternalSubset)(ctx); {
has = TREEFUN(hasInternalSubset, (ctx));
}
return has; return has;
} }
static int static int
hasExternalSubsetFunction(void *ctx) hasExternalSubsetFunction(void *ctx)
{ {
int has; int has = -1;
START(hasExternalSubset, int, (id,SEL));
NSCAssert(ctx,@"No Context"); if (imp != treeImp)
has = [HANDLER hasExternalSubset]; {
has = (*imp)(HANDLER, sel);
}
if (has < 0) if (has < 0)
has = (*xmlDefaultSAXHandler.hasExternalSubset)(ctx); {
has = TREEFUN(hasExternalSubset, (ctx));
}
return has; return has;
} }
static void static void
internalSubsetFunction(void *ctx, const char *name, internalSubsetFunction(void *ctx, const unsigned char *name,
const xmlChar *ExternalID, const xmlChar *SystemID) const xmlChar *ExternalID, const xmlChar *SystemID)
{ {
NSCAssert(ctx,@"No Context"); START(internalSubset:externalID:systemID:, BOOL, (id,SEL,id,id,id));
if ([HANDLER internalSubset: UTF8Str(name) if (imp == treeImp || (*imp)(HANDLER, sel, UTF8Str(name),
externalID: UTF8Str(ExternalID) UTF8Str(ExternalID), UTF8Str(SystemID)) == NO)
systemID: UTF8Str(SystemID)] == NO) {
(*xmlDefaultSAXHandler.internalSubset)(ctx, name, ExternalID, SystemID); TREEFUN(internalSubset, (ctx, name, ExternalID, SystemID));
}
} }
static void static void
externalSubsetFunction(void *ctx, const char *name, externalSubsetFunction(void *ctx, const unsigned char *name,
const xmlChar *ExternalID, const xmlChar *SystemID) const xmlChar *ExternalID, const xmlChar *SystemID)
{ {
NSCAssert(ctx,@"No Context"); START(externalSubset:externalID:systemID:, BOOL, (id,SEL,id,id,id));
if ([HANDLER externalSubset: UTF8Str(name) if (imp == treeImp || (*imp)(HANDLER, sel, UTF8Str(name),
externalID: UTF8Str(ExternalID) UTF8Str(ExternalID), UTF8Str(SystemID)) == NO)
systemID: UTF8Str(SystemID)] == NO) {
(*xmlDefaultSAXHandler.externalSubset)(ctx, name, ExternalID, SystemID); TREEFUN(externalSubset, (ctx, name, ExternalID, SystemID));
}
} }
static xmlEntityPtr static xmlEntityPtr
getEntityFunction(void *ctx, const char *name) getEntityFunction(void *ctx, const unsigned char *name)
{ {
NSCAssert(ctx,@"No Context"); START(getEntity:, xmlEntityPtr, (id,SEL,id));
return [HANDLER getEntity: UTF8Str(name)];
if (imp != treeImp)
{
return (*imp)(HANDLER, sel, UTF8Str(name));
}
else
{
return TREEFUN(getEntity, (ctx, name));
}
} }
static xmlEntityPtr static xmlEntityPtr
getParameterEntityFunction(void *ctx, const char *name) getParameterEntityFunction(void *ctx, const unsigned char *name)
{ {
NSCAssert(ctx,@"No Context"); START(getParameterEntity:, xmlEntityPtr, (id,SEL,id));
return [HANDLER getParameterEntity: UTF8Str(name)];
if (imp != treeImp)
{
return (*imp)(HANDLER, sel, UTF8Str(name));
}
else
{
return TREEFUN(getParameterEntity, (ctx, name));
}
} }
static void static void
entityDeclFunction(void *ctx, const char *name, int type, entityDeclFunction(void *ctx, const unsigned char *name, int type,
const char *publicId, const char *systemId, char *content) const unsigned char *publicId, const unsigned char *systemId,
unsigned char *content)
{ {
NSCAssert(ctx,@"No Context"); START(entityDecl:type:public:system:content:, void, (id,SEL,id,int,id,id,id));
[HANDLER entityDecl: UTF8Str(name)
type: type if (imp != treeImp)
public: UTF8Str(publicId) {
system: UTF8Str(systemId) (*imp)(HANDLER, sel, UTF8Str(name), type, UTF8Str(publicId),
content: UTF8Str(content)]; UTF8Str(systemId), UTF8Str(content));
}
else
{
TREEFUN(entityDecl, (ctx, name, type, publicId, systemId, content));
}
} }
static void static void
attributeDeclFunction(void *ctx, const char *elem, const char *name, attributeDeclFunction(void *ctx, const unsigned char *elem,
int type, int def, const char *defaultValue, xmlEnumerationPtr tree) const unsigned char *name, int type, int def,
const unsigned char *defaultValue, xmlEnumerationPtr tree)
{ {
NSCAssert(ctx,@"No Context"); START(attributeDecl:name:type:typeDefValue:defaultValue:, void, (id,SEL,id,id,int,int,id));
[HANDLER attributeDecl: UTF8Str(elem)
name: UTF8Str(name) if (imp != treeImp)
type: type {
typeDefValue: def (*imp)(HANDLER, sel, UTF8Str(elem), UTF8Str(name), type, def,
defaultValue: UTF8Str(defaultValue)]; UTF8Str(defaultValue));
}
else
{
TREEFUN(attributeDecl, (ctx, elem, name, type, def, defaultValue, tree));
}
} }
static void static void
elementDeclFunction(void *ctx, const char *name, int type, elementDeclFunction(void *ctx, const unsigned char *name, int type,
xmlElementContentPtr content) xmlElementContentPtr content)
{ {
NSCAssert(ctx,@"No Context"); START(elementDecl:type:, void, (id,SEL,id,int));
[HANDLER elementDecl: UTF8Str(name)
type: type];
if (imp != treeImp)
{
(*imp)(HANDLER, sel, UTF8Str(name), type);
}
else
{
TREEFUN(elementDecl, (ctx, name, type, content));
}
} }
static void static void
notationDeclFunction(void *ctx, const char *name, notationDeclFunction(void *ctx, const unsigned char *name,
const char *publicId, const char *systemId) const unsigned char *publicId, const unsigned char *systemId)
{ {
NSCAssert(ctx,@"No Context"); START(notationDecl:public:system:, void, (id,SEL,id,id, id));
[HANDLER notationDecl: UTF8Str(name)
public: UTF8Str(publicId) if (imp != treeImp)
system: UTF8Str(systemId)]; {
(*imp)(HANDLER, sel, UTF8Str(name), UTF8Str(publicId), UTF8Str(systemId));
}
else
{
TREEFUN(notationDecl, (ctx, name, publicId, systemId));
}
} }
static void static void
unparsedEntityDeclFunction(void *ctx, const char *name, unparsedEntityDeclFunction(void *ctx, const unsigned char *name,
const char *publicId, const char *systemId, const char *notationName) const unsigned char *publicId, const unsigned char *systemId,
const unsigned char *notationName)
{ {
NSCAssert(ctx,@"No Context"); NSCAssert(ctx,@"No Context");
[HANDLER unparsedEntityDecl: UTF8Str(name) [HANDLER unparsedEntityDecl: UTF8Str(name)
public: UTF8Str(publicId) public: UTF8Str(publicId)
system: UTF8Str(systemId) system: UTF8Str(systemId)
notationName: UTF8Str(notationName)]; notationName: UTF8Str(notationName)];
} START(unparsedEntityDecl:public:system:notationName:, void, (id,SEL,id,id,id,id));
static void if (imp != treeImp)
startElementFunction(void *ctx, const char *name, const char **atts)
{
int i;
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSString *key, *obj;
NSCAssert(ctx,@"No Context");
if (atts != NULL)
{ {
for (i = 0; (atts[i] != NULL); i++) (*imp)(HANDLER, sel, UTF8Str(name), UTF8Str(publicId), UTF8Str(systemId),
{ UTF8Str(notationName));
key = UTF8Str(atts[i++]); }
obj = UTF8Str(atts[i]); else
[dict setObject: obj forKey: key]; {
} TREEFUN(unparsedEntityDecl, (ctx,name,publicId,systemId,notationName));
} }
[HANDLER startElement: UTF8Str(name)
attributes: dict];
} }
static void static void
endElementFunction(void *ctx, const char *name) startElementFunction(void *ctx, const unsigned char *name,
const unsigned char **atts)
{ {
NSCAssert(ctx,@"No Context"); START(startElement:attributes:, void, (id,SEL,id,id));
[HANDLER endElement: UTF8Str(name)];
if (imp != treeImp)
{
int i;
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
NSString *key, *obj;
if (atts != NULL)
{
for (i = 0; (atts[i] != NULL); i++)
{
key = UTF8Str(atts[i++]);
obj = UTF8Str(atts[i]);
[dict setObject: obj forKey: key];
}
}
(*imp)(HANDLER, sel, UTF8Str(name), dict);
}
else
{
TREEFUN(startElement, (ctx, name, atts));
}
} }
static void static void
charactersFunction(void *ctx, const char *ch, int len) endElementFunction(void *ctx, const unsigned char *name)
{ {
NSCAssert(ctx,@"No Context"); START(endElement:, void, (id,SEL,id));
[HANDLER characters: UTF8StrLen(ch, len)];
if (imp != treeImp)
{
(*imp)(HANDLER, sel, UTF8Str(name));
}
else
{
TREEFUN(endElement, (ctx, name));
}
} }
static void static void
referenceFunction(void *ctx, const char *name) charactersFunction(void *ctx, const unsigned char *ch, int len)
{ {
NSCAssert(ctx,@"No Context"); START(characters:, void, (id,SEL,id));
[HANDLER reference: UTF8Str(name)];
if (imp != treeImp)
{
(*imp)(HANDLER, sel, UTF8StrLen(ch, len));
}
else
{
TREEFUN(characters, (ctx, ch, len));
}
} }
static void static void
ignorableWhitespaceFunction(void *ctx, const char *ch, int len) referenceFunction(void *ctx, const unsigned char *name)
{ {
NSCAssert(ctx,@"No Context"); START(reference:, void, (id,SEL,id));
[HANDLER ignoreWhitespace: UTF8StrLen(ch, len)];
if (imp != treeImp)
{
(*imp)(HANDLER, sel, UTF8Str(name));
}
else
{
TREEFUN(reference, (ctx, name));
}
} }
static void static void
processInstructionFunction(void *ctx, const char *target, const char *data) ignorableWhitespaceFunction(void *ctx, const unsigned char *ch, int len)
{ {
NSCAssert(ctx,@"No Context"); START(ignoreWhitespace:, void, (id,SEL,id));
[HANDLER processInstruction: UTF8Str(target)
data: UTF8Str(data)]; if (imp != treeImp)
{
(*imp)(HANDLER, sel, UTF8StrLen(ch, len));
}
else
{
TREEFUN(ignorableWhitespace, (ctx, ch, len));
}
} }
static void static void
cdataBlockFunction(void *ctx, const char *value, int len) processingInstructionFunction(void *ctx, const unsigned char *target,
const char *data)
{ {
NSCAssert(ctx,@"No Context"); START(processInstruction:, void, (id,SEL,id,id));
[HANDLER cdataBlock: UTF8StrLen(value, len)];
if (imp != treeImp)
{
(*imp)(HANDLER, sel, UTF8Str(target), UTF8Str(data));
}
else
{
TREEFUN(processingInstruction, (ctx, target, data));
}
} }
static void static void
commentFunction(void *ctx, const char *value) cdataBlockFunction(void *ctx, const unsigned char *value, int len)
{ {
NSCAssert(ctx,@"No Context"); START(cdataBlock:, void, (id,SEL,id));
[HANDLER comment: UTF8Str(value)];
if (imp != treeImp)
{
(*imp)(HANDLER, sel, UTF8StrLen(value, len));
}
else
{
TREEFUN(cdataBlock, (ctx, value, len));
}
} }
static void static void
warningFunction(void *ctx, const char *msg, ...) commentFunction(void *ctx, const unsigned char *value)
{ {
char allMsg[2048]; START(comment:, void, (id,SEL,id));
if (imp != treeImp)
{
(*imp)(HANDLER, sel, UTF8Str(value));
}
else
{
TREEFUN(comment, (ctx, value));
}
}
static void
warningFunction(void *ctx, const unsigned char *msg, ...)
{
unsigned char allMsg[2048];
va_list args; va_list args;
int lineNumber = -1; int lineNumber = -1;
int colNumber = -1; int colNumber = -1;
@ -2704,9 +2876,9 @@ warningFunction(void *ctx, const char *msg, ...)
} }
static void static void
errorFunction(void *ctx, const char *msg, ...) errorFunction(void *ctx, const unsigned char *msg, ...)
{ {
char allMsg[2048]; unsigned char allMsg[2048];
va_list args; va_list args;
int lineNumber = -1; int lineNumber = -1;
int colNumber = -1; int colNumber = -1;
@ -2723,9 +2895,9 @@ errorFunction(void *ctx, const char *msg, ...)
} }
static void static void
fatalErrorFunction(void *ctx, const char *msg, ...) fatalErrorFunction(void *ctx, const unsigned char *msg, ...)
{ {
char allMsg[2048]; unsigned char allMsg[2048];
va_list args; va_list args;
int lineNumber = -1; int lineNumber = -1;
int colNumber = -1; int colNumber = -1;
@ -3095,7 +3267,7 @@ fatalErrorFunction(void *ctx, const char *msg, ...)
LIB->reference = (void*) referenceFunction; LIB->reference = (void*) referenceFunction;
LIB->characters = (void*) charactersFunction; LIB->characters = (void*) charactersFunction;
LIB->ignorableWhitespace = (void*) ignorableWhitespaceFunction; LIB->ignorableWhitespace = (void*) ignorableWhitespaceFunction;
LIB->processingInstruction = (void*) processInstructionFunction; LIB->processingInstruction = (void*) processingInstructionFunction;
LIB->comment = (void*) commentFunction; LIB->comment = (void*) commentFunction;
LIB->warning = (void*) warningFunction; LIB->warning = (void*) warningFunction;
LIB->error = (void*) errorFunction; LIB->error = (void*) errorFunction;
@ -3207,6 +3379,7 @@ fatalErrorFunction(void *ctx, const char *msg, ...)
@implementation GSHTMLSAXHandler @implementation GSHTMLSAXHandler
- (BOOL) _initLibXML - (BOOL) _initLibXML
{ {
isHtmlHandler = YES;
lib = (xmlSAXHandler*)malloc(sizeof(htmlSAXHandler)); lib = (xmlSAXHandler*)malloc(sizeof(htmlSAXHandler));
if (lib == NULL) if (lib == NULL)
{ {
@ -3214,7 +3387,7 @@ fatalErrorFunction(void *ctx, const char *msg, ...)
} }
else else
{ {
memcpy(lib, &xmlDefaultSAXHandler, sizeof(htmlSAXHandler)); memcpy(lib, &htmlDefaultSAXHandler, sizeof(htmlSAXHandler));
#define LIB ((htmlSAXHandlerPtr)lib) #define LIB ((htmlSAXHandlerPtr)lib)
LIB->internalSubset = (void*) internalSubsetFunction; LIB->internalSubset = (void*) internalSubsetFunction;
@ -3235,7 +3408,7 @@ fatalErrorFunction(void *ctx, const char *msg, ...)
LIB->reference = (void*) referenceFunction; LIB->reference = (void*) referenceFunction;
LIB->characters = (void*) charactersFunction; LIB->characters = (void*) charactersFunction;
LIB->ignorableWhitespace = (void*) ignorableWhitespaceFunction; LIB->ignorableWhitespace = (void*) ignorableWhitespaceFunction;
LIB->processingInstruction = (void*) processInstructionFunction; LIB->processingInstruction = (void*) processingInstructionFunction;
LIB->comment = (void*) commentFunction; LIB->comment = (void*) commentFunction;
LIB->warning = (void*) warningFunction; LIB->warning = (void*) warningFunction;
LIB->error = (void*) errorFunction; LIB->error = (void*) errorFunction;

View file

@ -22,11 +22,11 @@
<!-- <!--
plist is an XML language - Typical usage: plist is an XML language - Typical usage:
<?xml version="1.0" encoding=\"UTF-8\"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//GNUstep//DTD plist 0.9//EN" <!DOCTYPE plist PUBLIC "-//GNUstep//DTD plist 0.9//EN"
"http://www.gnustep.org/plist-0_9.xml"> "http://www.gnustep.org/plist-0_9.xml">
<plist> <plist>
</plist> </plist>
--> -->
<!ENTITY % item "(array | data | date | dict | false | integer | real | string | true)"> <!ENTITY % item "(array | data | date | dict | false | integer | real | string | true)">