1 /*
2  * This file is part of Hubbub.
3  * Licensed under the MIT License,
4  *                http://www.opensource.org/licenses/mit-license.php
5  * Copyright 2007 John-Mark Bell <jmb@netsurf-browser.org>
6  */
7 
8 #include "utils/utils.h"
9 #include "tokeniser/entities.h"
10 
11 /** Node in our entity tree */
12 typedef struct hubbub_entity_node {
13         /* Do not reorder this without fixing make-entities.pl */
14 	uint8_t split;	/**< Data to split on */
15 	int32_t lt;	/**< Subtree for data less than split */
16 	int32_t eq;	/**< Subtree for data equal to split */
17 	int32_t gt;	/**< Subtree for data greater than split */
18 	uint32_t value;	/**< Data for this node */
19 } hubbub_entity_node;
20 
21 #include "entities.inc"
22 
23 /**
24  * Step-wise search for a key in our entity tree
25  *
26  * \param c        Character to look for
27  * \param result   Pointer to location for result
28  * \param context  Pointer to location for search context
29  * \return HUBBUB_OK if key found,
30  *         HUBBUB_NEEDDATA if more steps are required
31  *         HUBBUB_INVALID if nothing matches
32  *
33  * The value pointed to by \p context must be NULL for the first call.
34  * Thereafter, pass in the same value as returned by the previous call.
35  * The context is opaque to the caller and should not be inspected.
36  *
37  * The location pointed to by \p result will be set to NULL unless a match
38  * is found.
39  */
hubbub_entity_tree_search_step(uint8_t c,uint32_t * result,int32_t * context)40 static hubbub_error hubbub_entity_tree_search_step(uint8_t c,
41 		uint32_t *result, int32_t *context)
42 {
43 	bool match = false;
44 	int32_t p;
45 
46 	if (result == NULL || context == NULL)
47 		return HUBBUB_BADPARM;
48 
49 	if (*context == -1) {
50 		p = dict_root;
51 	} else {
52 		p = *context;
53 	}
54 
55 	while (p != -1) {
56 		if (c < dict[p].split) {
57 			p = dict[p].lt;
58 		} else if (c == dict[p].split) {
59 			if (dict[p].split == '\0') {
60 				match = true;
61 				p = -1;
62 			} else if (dict[p].eq != -1 && dict[dict[p].eq].split == '\0') {
63 				match = true;
64 				*result = dict[dict[p].eq].value;
65 				p = dict[p].eq;
66 			} else if (dict[p].value != 0) {
67 				match = true;
68 				*result = dict[p].value;
69 				p = dict[p].eq;
70 			} else {
71 				p = dict[p].eq;
72 			}
73 
74 			break;
75 		} else {
76 			p = dict[p].gt;
77 		}
78 	}
79 
80 	*context = p;
81 
82 	return (match) ? HUBBUB_OK :
83 			(p == -1) ? HUBBUB_INVALID : HUBBUB_NEEDDATA;
84 }
85 
86 /**
87  * Step-wise search for an entity in the dictionary
88  *
89  * \param c        Character to look for
90  * \param result   Pointer to location for result
91  * \param context  Pointer to location for search context
92  * \return HUBBUB_OK if key found,
93  *         HUBBUB_NEEDDATA if more steps are required
94  *         HUBBUB_INVALID if nothing matches
95  *
96  * The value pointed to by \p context should be -1 for the first call.
97  * Thereafter, pass in the same value as returned by the previous call.
98  * The context is opaque to the caller and should not be inspected.
99  *
100  * The location pointed to by \p result will be set to U+FFFD unless a match
101  * is found.
102  */
hubbub_entities_search_step(uint8_t c,uint32_t * result,int32_t * context)103 hubbub_error hubbub_entities_search_step(uint8_t c, uint32_t *result,
104 		int32_t *context)
105 {
106 	if (result == NULL)
107 		return HUBBUB_BADPARM;
108 
109         *result = 0xFFFD;
110 
111 	return hubbub_entity_tree_search_step(c, result, context);
112 }
113