2633 lines · 61.7 KB · C
RawDownload
/* * This file is part of LibCSS. * Licensed under the MIT License, *                http://www.opensource.org/licenses/mit-license.php * Copyright 2008 John-Mark Bell <jmb@netsurf-browser.org> */ #include <assert.h>#include <ctype.h>#include <stdbool.h> #include <libwapcaplet/libwapcaplet.h> #include <parserutils/input/inputstream.h>#include <parserutils/utils/stack.h>#include <parserutils/utils/vector.h> #include "charset/detect.h"#include "lex/lex.h"#include "parse/parse.h"#include "utils/parserutilserror.h"#include "utils/utils.h" #undef DEBUG_STACK#undef DEBUG_EVENTS #ifndef NDEBUG#include <stdio.h>extern void parserutils_stack_dump(parserutils_stack *stack, const char *prefix,		void (*printer)(void *item));extern void parserutils_vector_dump(parserutils_vector *vector,		const char *prefix, void (*printer)(void *item));#ifdef DEBUG_STACKstatic void printer(void *item);#endif#ifdef DEBUG_EVENTSstatic void tprinter(void *token);#endif#endif /** * Major state numbers */enum {	sStart = 0,	sStylesheet = 1,	sStatement = 2,	sRuleset = 3,	sRulesetEnd = 4,	sAtRule = 5,	sAtRuleEnd = 6,	sBlock = 7,	sBlockContent = 8,	sSelector = 9,	sDeclaration = 10,	sDeclList = 11,	sDeclListEnd = 12,	sProperty = 13,	sValue0 = 14,	sValue1 = 15,	sValue = 16,	sAny0 = 17,	sAny1 = 18,	sAny = 19,	sMalformedDecl = 20,	sMalformedSelector = 21,	sMalformedAtRule = 22,	sInlineStyle = 23,	sISBody0 = 24,	sISBody = 25}; /** * Representation of a parser state */typedef struct parser_state{	unsigned int state : 16,	             substate : 16;} parser_state; /** * CSS parser object */struct css_parser{	parserutils_inputstream *stream;	/**< The inputstream */	css_lexer *lexer;		/**< The lexer to use */ 	bool quirks;			/**< Whether to enable parsing quirks */ #define STACK_CHUNK 32	parserutils_stack *states;	/**< Stack of states */ 	parserutils_vector *tokens;	/**< Vector of pending tokens */ 	const css_token *pushback;	/**< Push back buffer */ 	bool parseError;		/**< A parse error has occurred */	parserutils_stack *open_items;	/**< Stack of open brackets */ 	uint8_t match_char;		/**< Close bracket type for parseAny */ 	bool last_was_ws;		/**< Last token was whitespace */ 	css_parser_event_handler event;	/**< Client's event handler */	void *event_pw;			/**< Client data for event handler */ 	css_allocator_fn alloc;		/**< Memory (de)allocation function */	void *pw;			/**< Client-specific private data */}; static css_error css__parser_create_internal(const char *charset, 		css_charset_source cs_source,		css_allocator_fn alloc, void *pw, parser_state initial, 		css_parser **parser); static css_error transition(css_parser *parser, parser_state to,		parser_state subsequent);static css_error transitionNoRet(css_parser *parser, parser_state to);static css_error done(css_parser *parser);static css_error expect(css_parser *parser, css_token_type type);static css_error getToken(css_parser *parser, const css_token **token);static css_error pushBack(css_parser *parser, const css_token *token);static css_error eatWS(css_parser *parser); static css_error parseStart(css_parser *parser);static css_error parseStylesheet(css_parser *parser);static css_error parseStatement(css_parser *parser);static css_error parseRuleset(css_parser *parser);static css_error parseRulesetEnd(css_parser *parser);static css_error parseAtRule(css_parser *parser);static css_error parseAtRuleEnd(css_parser *parser);static css_error parseBlock(css_parser *parser);static css_error parseBlockContent(css_parser *parser);static css_error parseSelector(css_parser *parser);static css_error parseDeclaration(css_parser *parser);static css_error parseDeclList(css_parser *parser);static css_error parseDeclListEnd(css_parser *parser);static css_error parseProperty(css_parser *parser);static css_error parseValue0(css_parser *parser);static css_error parseValue1(css_parser *parser);static css_error parseValue(css_parser *parser);static css_error parseAny0(css_parser *parser);static css_error parseAny1(css_parser *parser);static css_error parseAny(css_parser *parser);static css_error parseMalformedDeclaration(css_parser *parser);static css_error parseMalformedSelector(css_parser *parser);static css_error parseMalformedAtRule(css_parser *parser);static css_error parseInlineStyle(css_parser *parser);static css_error parseISBody0(css_parser *parser);static css_error parseISBody(css_parser *parser); static void unref_interned_strings_in_tokens(css_parser *parser); /** * Dispatch table for parsing, indexed by major state number */static css_error (*parseFuncs[])(css_parser *parser) = {	parseStart,	parseStylesheet,	parseStatement,	parseRuleset,	parseRulesetEnd,	parseAtRule,	parseAtRuleEnd,	parseBlock,	parseBlockContent,	parseSelector,	parseDeclaration,	parseDeclList,	parseDeclListEnd,	parseProperty,	parseValue0,	parseValue1,	parseValue,	parseAny0,	parseAny1,	parseAny,	parseMalformedDeclaration,	parseMalformedSelector,	parseMalformedAtRule,	parseInlineStyle,	parseISBody0,	parseISBody}; /** * Create a CSS parser * * \param charset     Charset of data, if known, or NULL * \param cs_source   Source of charset information, or CSS_CHARSET_DEFAULT * \param alloc       Memory (de)allocation function * \param pw          Pointer to client-specific private data * \param parser      Pointer to location to receive parser instance * \return CSS_OK on success, *         CSS_BADPARM on bad parameters, *         CSS_NOMEM on memory exhaustion */css_error css__parser_create(const char *charset, css_charset_source cs_source,		css_allocator_fn alloc, void *pw, 		css_parser **parser){	parser_state initial = { sStart, 0 }; 	return css__parser_create_internal(charset, cs_source,			alloc, pw, initial, parser);} /** * Create a CSS parser for an inline style * * \param charset     Charset of data, if known, or NULL * \param cs_source   Source of charset information, or CSS_CHARSET_DEFAULT * \param alloc       Memory (de)allocation function * \param pw          Pointer to client-specific private data * \param parser      Pointer to location to receive parser instance * \return CSS_OK on success, *         CSS_BADPARM on bad parameters, *         CSS_NOMEM on memory exhaustion */css_error css__parser_create_for_inline_style(const char *charset,		css_charset_source cs_source,		css_allocator_fn alloc, void *pw, css_parser **parser){	parser_state initial = { sInlineStyle, 0 }; 	return css__parser_create_internal(charset, cs_source,			alloc, pw, initial, parser);} /** * Destroy a CSS parser * * \param parser  The parser instance to destroy * \return CSS_OK on success, appropriate error otherwise */css_error css__parser_destroy(css_parser *parser){	if (parser == NULL)		return CSS_BADPARM; 	parserutils_stack_destroy(parser->open_items); 	parserutils_vector_destroy(parser->tokens); 	parserutils_stack_destroy(parser->states); 	css__lexer_destroy(parser->lexer); 	parserutils_inputstream_destroy(parser->stream); 	parser->alloc(parser, 0, parser->pw); 	return CSS_OK;} /** * Configure a CSS parser * * \param parser  The parser instance to configure * \param type    The option to configure * \param params  Option-specific data * \return CSS_OK on success, appropriate error otherwise */css_error css__parser_setopt(css_parser *parser, css_parser_opttype type,		css_parser_optparams *params){	if (parser == NULL || params == NULL)		return CSS_BADPARM; 	switch (type) {	case CSS_PARSER_QUIRKS:		parser->quirks = params->quirks;		break;	case CSS_PARSER_EVENT_HANDLER:		parser->event = params->event_handler.handler;		parser->event_pw = params->event_handler.pw;		break;	} 	return CSS_OK;} /** * Parse a chunk of data using a CSS parser * * \param parser  The parser to use * \param data    Pointer to the chunk to parse * \param len     Length of chunk * \return CSS_OK on success, appropriate error otherwise */css_error css__parser_parse_chunk(css_parser *parser, const uint8_t *data, 		size_t len){	parserutils_error perror;	parser_state *state;	css_error error = CSS_OK; 	if (parser == NULL || data == NULL)		return CSS_BADPARM; 	perror = parserutils_inputstream_append(parser->stream, data, len);	if (perror != PARSERUTILS_OK)		return css_error_from_parserutils_error(perror); 	do {		state = parserutils_stack_get_current(parser->states);		if (state == NULL)			break; 		error = parseFuncs[state->state](parser);	} while (error == CSS_OK); 	return error;} /** * Inform a CSS parser that all data has been received. * * \param parser  The parser to inform * \return CSS_OK on success, appropriate error otherwise */css_error css__parser_completed(css_parser *parser){	parserutils_error perror;	parser_state *state;	css_error error = CSS_OK; 	if (parser == NULL)		return CSS_BADPARM; 	/* Send EOF to input stream */	perror = parserutils_inputstream_append(parser->stream, NULL, 0);	if (perror != PARSERUTILS_OK)		return css_error_from_parserutils_error(perror); 	/* Flush through any remaining data */	do {		state = parserutils_stack_get_current(parser->states);		if (state == NULL)			break; 		error = parseFuncs[state->state](parser);	} while (error == CSS_OK); 	return error;} /** * Retrieve document charset information from a CSS parser * * \param parser  The parser instance * \param source  Pointer to location to receive charset source * \return Pointer to charset name (constant; do not free) */const char *css__parser_read_charset(css_parser *parser, 		css_charset_source *source){	const char *charset;	uint32_t src; 	if (parser == NULL || source == NULL)		return NULL; 	charset = parserutils_inputstream_read_charset(parser->stream, &src); 	*source = (css_charset_source) src; 	return charset;} /** * Quirks permitted when parsing * * \param parser  Parser to query * \return True if quirks permitted, false otherwise */bool css__parser_quirks_permitted(css_parser *parser){	return parser->quirks;} /****************************************************************************** * Parser creation helper                                                     * ******************************************************************************/ /** * Create a CSS parser (internal) * * \param charset     Charset of data, if known, or NULL * \param cs_source   Source of charset information, or CSS_CHARSET_DEFAULT * \param alloc       Memory (de)allocation function * \param pw          Pointer to client-specific private data * \param initial     The required initial state of the parser * \param parser      Pointer to location to receive parser instance * \return CSS_OK on success, *         CSS_BADPARM on bad parameters, *         CSS_NOMEM on memory exhaustion */css_error css__parser_create_internal(const char *charset, 		css_charset_source cs_source,		css_allocator_fn alloc, void *pw, parser_state initial, 		css_parser **parser){	css_parser *p;	parserutils_error perror;	css_error error; 	if (alloc == NULL || parser == NULL)		return CSS_BADPARM; 	p = alloc(NULL, sizeof(css_parser), pw);	if (p == NULL)		return CSS_NOMEM; 	perror = parserutils_inputstream_create(charset, cs_source,			css__charset_extract, (parserutils_alloc) alloc, pw,			&p->stream);	if (perror != PARSERUTILS_OK) {		alloc(p, 0, pw);		return css_error_from_parserutils_error(perror);	} 	error = css__lexer_create(p->stream, alloc, pw, &p->lexer);	if (error != CSS_OK) {		parserutils_inputstream_destroy(p->stream);		alloc(p, 0, pw);		return error;	} 	perror = parserutils_stack_create(sizeof(parser_state), 			STACK_CHUNK, (parserutils_alloc) alloc, pw,			&p->states);	if (perror != PARSERUTILS_OK) {		css__lexer_destroy(p->lexer);		parserutils_inputstream_destroy(p->stream);		alloc(p, 0, pw);		return css_error_from_parserutils_error(perror);	} 	perror = parserutils_vector_create(sizeof(css_token), 			STACK_CHUNK, (parserutils_alloc) alloc, pw,			&p->tokens);	if (perror != PARSERUTILS_OK) {		parserutils_stack_destroy(p->states);		css__lexer_destroy(p->lexer);		parserutils_inputstream_destroy(p->stream);		alloc(p, 0, pw);		return css_error_from_parserutils_error(perror);	} 	perror = parserutils_stack_create(sizeof(char), 			STACK_CHUNK, (parserutils_alloc) alloc, pw,			&p->open_items);	if (perror != PARSERUTILS_OK) {		parserutils_vector_destroy(p->tokens);		parserutils_stack_destroy(p->states);		css__lexer_destroy(p->lexer);		parserutils_inputstream_destroy(p->stream);		alloc(p, 0, pw);		return css_error_from_parserutils_error(perror);	} 	perror = parserutils_stack_push(p->states, (void *) &initial);	if (perror != PARSERUTILS_OK) {		parserutils_stack_destroy(p->open_items);		parserutils_vector_destroy(p->tokens);		parserutils_stack_destroy(p->states);		css__lexer_destroy(p->lexer);		parserutils_inputstream_destroy(p->stream);		alloc(p, 0, pw);		return css_error_from_parserutils_error(perror);	} 	p->quirks = false;	p->pushback = NULL;	p->parseError = false;	p->match_char = 0;	p->event = NULL;	p->last_was_ws = false;	p->event_pw = NULL;	p->alloc = alloc;	p->pw = pw; 	*parser = p; 	return CSS_OK;} /****************************************************************************** * Helper functions                                                           * ******************************************************************************/ /** * Transition to a new state, ensuring return to the one specified * * \param parser      The parser instance * \param to          Destination state * \param subsequent  The state to return to

Lines 1–500 of 2633.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t