/* * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im> * * All rights reserved. * * This program is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License version 3.0 only, * as published by the Free Software Foundation. * * This program 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 * version 3.0 for more details. * * You should have received a copy of the GNU Lesser General Public License * version 3.0 along with this program. If not, see * <https://www.gnu.org/licenses/>. */ #import "OFObject.h" #import "OFString.h" #import "OFXMLAttribute.h" OF_ASSUME_NONNULL_BEGIN @class OFArray OF_GENERIC(ObjectType); @class OFMutableData; @class OFMutableArray OF_GENERIC(ObjectType); @class OFMutableDictionary OF_GENERIC(KeyType, ObjectType); @class OFStream; @class OFXMLParser; /** * @protocol OFXMLParserDelegate OFXMLParser.h ObjFW/ObjFW.h * * @brief A protocol that needs to be implemented by delegates for OFXMLParser. */ @protocol OFXMLParserDelegate <OFObject> @optional /** * @brief This callback is called when the XML parser found a processing * instruction. * * @param parser The parser which found a processing instruction * @param target The target of the processing instruction * @param text The text of the processing instruction */ - (void)parser: (OFXMLParser *)parser foundProcessingInstructionWithTarget: (OFString *)target text: (nullable OFString *)text; /** * @brief This callback is called when the XML parser found the start of a new * tag. * * @param parser The parser which found a new tag * @param name The name of the tag which just started * @param prefix The prefix of the tag which just started or `nil` * @param nameSpace The namespace of the tag which just started or `nil` * @param attributes The attributes included in the tag which just started or * `nil` */ - (void)parser: (OFXMLParser *)parser didStartElement: (OFString *)name prefix: (nullable OFString *)prefix namespace: (nullable OFString *)nameSpace attributes: (nullable OFArray OF_GENERIC(OFXMLAttribute *) *)attributes; /** * @brief This callback is called when the XML parser found the end of a tag. * * @param parser The parser which found the end of a tag * @param name The name of the tag which just ended * @param prefix The prefix of the tag which just ended or `nil` * @param nameSpace The namespace of the tag which just ended or `nil` */ - (void)parser: (OFXMLParser *)parser didEndElement: (OFString *)name prefix: (nullable OFString *)prefix namespace: (nullable OFString *)nameSpace; /** * @brief This callback is called when the XML parser found characters. * * In case there are comments or CDATA, it is possible that this callback is * called multiple times in a row. * * @param parser The parser which found a string * @param characters The characters the XML parser found */ - (void)parser: (OFXMLParser *)parser foundCharacters: (OFString *)characters; /** * @brief This callback is called when the XML parser found CDATA. * * @param parser The parser which found a string * @param CDATA The CDATA the XML parser found */ - (void)parser: (OFXMLParser *)parser foundCDATA: (OFString *)CDATA; /** * @brief This callback is called when the XML parser found a comment. * * @param parser The parser which found a comment * @param comment The comment the XML parser found */ - (void)parser: (OFXMLParser *)parser foundComment: (OFString *)comment; /** * @brief This callback is called when the XML parser found an entity it * doesn't know. * * The callback is supposed to return a substitution for the entity or `nil` if * it is not known to the callback as well, in which case an exception will be * risen. * * @param parser The parser which found an unknown entity * @param entity The name of the entity the XML parser didn't know * @return A substitution for the entity or `nil` */ - (nullable OFString *)parser: (OFXMLParser *)parser foundUnknownEntityNamed: (OFString *)entity; @end /** * @class OFXMLParser OFXMLParser.h ObjFW/ObjFW.h * * @brief An event-based XML parser. * * OFXMLParser is an event-based XML parser which calls the delegate's callbacks * as soon as it finds something, thus suitable for streams as well. */ OF_SUBCLASSING_RESTRICTED @interface OFXMLParser: OFObject { id <OFXMLParserDelegate> _Nullable _delegate; uint_least8_t _state; size_t _i, _last; const char *_Nullable _data; OFMutableData *_buffer; OFString *_Nullable _name, *_Nullable _prefix; OFMutableArray OF_GENERIC(OFMutableDictionary OF_GENERIC(OFString *, OFString *) *) *_namespaces; OFMutableArray OF_GENERIC(OFXMLAttribute *) *_attributes; OFString *_Nullable _attributeName, *_Nullable _attributePrefix; char _delimiter; OFMutableArray OF_GENERIC(OFString *) *_previous; size_t _level; bool _acceptProlog; size_t _lineNumber; bool _lastCarriageReturn, _finishedParsing; OFStringEncoding _encoding; size_t _depthLimit; } /** * @brief The delegate that is used by the XML parser. */ @property OF_NULLABLE_PROPERTY (assign, nonatomic) id <OFXMLParserDelegate> delegate; /** * @brief The current line number. */ @property (readonly, nonatomic) size_t lineNumber; /** * @brief Whether the XML parser has finished parsing. */ @property (readonly, nonatomic, getter=hasFinishedParsing) bool finishedParsing; /** * @brief The depth limit for the XML parser. * * If the depth limit is exceeded, an OFMalformedXMLException is thrown. * * The default is 32. 0 means unlimited (insecure!). */ @property (nonatomic) size_t depthLimit; /** * @brief Creates a new XML parser. * * @return A new, autoreleased OFXMLParser */ + (instancetype)parser; /** * @brief Parses the specified buffer with the specified size. * * @param buffer The buffer to parse * @param length The length of the buffer * @throw OFMalformedXMLException The XML was malformed * @throw OFUnboundPrefixException A prefix was used that was not bound to any * namespace * @throw OFInvalidEncodingException The XML is not in the encoding it specified */ - (void)parseBuffer: (const char *)buffer length: (size_t)length; /** * @brief Parses the specified string. * * @param string The string to parse * @throw OFMalformedXMLException The XML was malformed * @throw OFUnboundPrefixException A prefix was used that was not bound to any * namespace * @throw OFInvalidEncodingException The XML is not in the encoding it specified */ - (void)parseString: (OFString *)string; /** * @brief Parses the specified stream. * * @param stream The stream to parse * @throw OFMalformedXMLException The XML was malformed * @throw OFUnboundPrefixException A prefix was used that was not bound to any * namespace * @throw OFInvalidEncodingException The XML is not in the encoding it specified */ - (void)parseStream: (OFStream *)stream; @end OF_ASSUME_NONNULL_END