1 /*
2  Copyright (C) 2016-2017 Alexander Borisov
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Lesser General Public
6  License as published by the Free Software Foundation; either
7  version 2.1 of the License, or (at your option) any later version.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Lesser General Public License for more details.
13 
14  You should have received a copy of the GNU Lesser General Public
15  License along with this library; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 
18  Author: lex.borisov@gmail.com (Alexander Borisov)
19 */
20 
21 #include "mycss/mycss.h"
22 #include "mycss/tokenizer_resource.h"
23 
mycss_create(void)24 mycss_t * mycss_create(void)
25 {
26     return (mycss_t*)mycore_calloc(1, sizeof(mycss_t));
27 }
28 
mycss_init(mycss_t * mycss)29 mystatus_t mycss_init(mycss_t* mycss)
30 {
31     mystatus_t status = mycss_tokenizer_state_init(mycss);
32 
33     if(status != MyCSS_STATUS_OK)
34         return status;
35 
36     return MyCSS_STATUS_OK;
37 }
38 
mycss_destroy(mycss_t * mycss,bool self_destroy)39 mycss_t * mycss_destroy(mycss_t* mycss, bool self_destroy)
40 {
41     if(mycss == NULL)
42         return NULL;
43 
44     mycss_tokenizer_state_destroy(mycss);
45 
46     if(self_destroy) {
47         mycore_free(mycss);
48         return NULL;
49     }
50 
51     return mycss;
52 }
53 
mycss_parse(mycss_entry_t * entry,myencoding_t encoding,const char * css,size_t css_size)54 mystatus_t mycss_parse(mycss_entry_t* entry, myencoding_t encoding, const char* css, size_t css_size)
55 {
56     mycss_entry_clean(entry);
57 
58     /* set parser */
59     entry->parser = mycss_parser_token;
60 
61     /* stylesheet */
62     entry->stylesheet = mycss_stylesheet_create();
63     mycss_stylesheet_init(entry->stylesheet, entry);
64 
65     /* and parse css */
66     mycss_encoding_set(entry, encoding);
67 
68     mystatus_t status = mycss_tokenizer_chunk(entry, css, css_size);
69     if(status != MyCSS_STATUS_OK)
70         return status;
71 
72     status = mycss_tokenizer_end(entry);
73 
74     return status;
75 }
76 
mycss_parse_chunk(mycss_entry_t * entry,const char * css,size_t css_size)77 mystatus_t mycss_parse_chunk(mycss_entry_t* entry, const char* css, size_t css_size)
78 {
79     if(entry->type & MyCSS_ENTRY_TYPE_END) {
80         mycss_entry_clean_all(entry);
81     }
82 
83     /* create and init new Result */
84     if(entry->stylesheet == NULL) {
85         entry->stylesheet = mycss_stylesheet_create();
86         mycss_stylesheet_init(entry->stylesheet, entry);
87     }
88 
89     return mycss_tokenizer_chunk(entry, css, css_size);
90 }
91 
mycss_parse_chunk_end(mycss_entry_t * entry)92 mystatus_t mycss_parse_chunk_end(mycss_entry_t* entry)
93 {
94     mystatus_t status = mycss_tokenizer_end(entry);
95     mycss_entry_end(entry);
96 
97     return status;
98 }
99 
100 // token
mycss_token_position(mycss_token_t * token,size_t * return_length)101 size_t mycss_token_position(mycss_token_t* token, size_t *return_length)
102 {
103     if(return_length)
104         *return_length = token->length;
105 
106     return token->begin;
107 }
108 
mycss_token_begin(mycss_token_t * token)109 size_t mycss_token_begin(mycss_token_t* token)
110 {
111     return token->begin;
112 }
113 
mycss_token_length(mycss_token_t * token)114 size_t mycss_token_length(mycss_token_t* token)
115 {
116     return token->length;
117 }
118 
mycss_token_type(mycss_token_t * token)119 mycss_token_type_t mycss_token_type(mycss_token_t* token)
120 {
121     return token->type;
122 }
123 
mycss_token_name_by_type(mycss_token_type_t type)124 const char * mycss_token_name_by_type(mycss_token_type_t type)
125 {
126     if(type >= MyCSS_TOKEN_TYPE_LAST_ENTRY)
127         return mycss_token_type_description[MyCSS_TOKEN_TYPE_LAST_ENTRY];
128 
129     return mycss_token_type_description[type];
130 }
131 
mycss_token_data_to_string(mycss_entry_t * entry,mycss_token_t * token,mycore_string_t * str,bool init_string,bool case_insensitive)132 size_t mycss_token_data_to_string(mycss_entry_t* entry, mycss_token_t* token, mycore_string_t* str, bool init_string, bool case_insensitive)
133 {
134     if(init_string)
135         mycore_string_init(entry->mchar, entry->mchar_node_id, str, (token->length + 4));
136 
137     mycss_string_res_t out_res;
138     mycss_string_res_clean(&out_res);
139 
140     out_res.encoding = entry->encoding;
141     out_res.case_insensitive = case_insensitive;
142 
143     mycore_incoming_buffer_t *buffer = mycore_incoming_buffer_find_by_position(entry->current_buffer, token->begin);
144     size_t relative_begin = token->begin - buffer->offset;
145 
146     // if token data length in one buffer then print them all at once
147     if((relative_begin + token->length) <= buffer->size) {
148         mycss_string_data_process(str, &buffer->data[relative_begin], 0, token->length, &out_res);
149         mycss_string_data_process_end(str, &out_res);
150 
151         return token->length;
152     }
153 
154     // if the data are spread across multiple buffers that join them
155     size_t length = token->length;
156     while(buffer) {
157         if((relative_begin + length) > buffer->size)
158         {
159             size_t relative_end = (buffer->size - relative_begin);
160             length -= relative_end;
161 
162             mycss_string_data_process(str, buffer->data, relative_begin, relative_end, &out_res);
163 
164             relative_begin = 0;
165             buffer         = buffer->next;
166         }
167         else {
168             mycss_string_data_process(str, &buffer->data[relative_begin], 0, length, &out_res);
169             break;
170         }
171     }
172 
173     mycss_string_data_process_end(str, &out_res);
174 
175     return token->length;
176 }
177 
mycss_token_buffer_first(mycss_entry_t * entry,mycss_token_t * token)178 mycore_incoming_buffer_t * mycss_token_buffer_first(mycss_entry_t* entry, mycss_token_t* token)
179 {
180     return mycore_incoming_buffer_find_by_position(entry->current_buffer, token->begin);
181 }
182 
183 // encoding
184 
mycss_encoding_set(mycss_entry_t * entry,myencoding_t encoding)185 void mycss_encoding_set(mycss_entry_t* entry, myencoding_t encoding)
186 {
187     entry->encoding = encoding;
188 }
189 
mycss_encoding_get(mycss_entry_t * entry)190 myencoding_t mycss_encoding_get(mycss_entry_t* entry)
191 {
192     return entry->encoding;
193 }
194 
mycss_encoding_check_charset_rule(const char * css,size_t size)195 myencoding_t mycss_encoding_check_charset_rule(const char* css, size_t size)
196 {
197     if(size < 15)
198         return MyENCODING_UTF_8;
199 
200     if(strncmp("@charset \"", css, 10))
201         return MyENCODING_UTF_8;
202 
203     size_t begin = 10;
204     size_t length = begin;
205 
206     while(length < size) {
207         if(css[length] == '"')
208         {
209             ++length;
210 
211             if(length >= size || css[length] != ';')
212                 return MyENCODING_UTF_8;
213 
214             size_t name_len = (length - begin) - 1;
215 
216             myencoding_t encoding;
217             if(myencoding_by_name(&css[begin], name_len, &encoding))
218                 return encoding;
219 
220             break;
221         }
222 
223         ++length;
224     }
225 
226     return MyENCODING_UTF_8;
227 }
228 
229 
230