1 /*-
2 * Copyright (c) 2004 Jacques A. Vidrine
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 */
27 #include <sys/param.h>
28
29 #include <algorithm>
30 #include <cctype>
31 #include <cerrno>
32 #include <cstdlib>
33 #include <fstream>
34 #include <iostream>
35 #include <map>
36 #include <memory>
37 #include <sstream>
38 #include <stack>
39 #include <string>
40 #include <vector>
41
42 #include <unistd.h>
43
44 #include <vuxml/vuxml.hh>
45 #include <vuxml/constants.hh>
46 #include <vuxml/parser.hh>
47 #include <vuxml/handlers.hh>
48
49
50 using namespace vuxml;
51
52
BasicHandler(EntryProcessor & proc)53 BasicHandler::BasicHandler(EntryProcessor &proc)
54 : parser_(0), proc_(proc), state_(&F_docroot)
55 #define CLASS BasicHandler
56 #include <vuxml/state_init.hh>
57 #include <vuxml/state_head.hh>
58 #include <vuxml/basic_state.hh>
59 #include <vuxml/state_undef.hh>
60 {
61 #if defined(DEBUG_STATE)
62 #include <vuxml/state_debug.hh>
63 #include <vuxml/state_head.hh>
64 #include <vuxml/basic_state.hh>
65 #include <vuxml/state_undef.hh>
66 #endif
67 }
68
69
~BasicHandler()70 BasicHandler::~BasicHandler()
71 {
72 }
73
74
75 XMLState *
signalError_(const char * msg)76 BasicHandler::signalError_(const char *msg)
77 {
78 parser_->signalError(msg);
79 return &F_ignore;
80 }
81
82
83 XMLState *
docroot_child(const Element & element)84 BasicHandler::docroot_child(const Element &element)
85 {
86 if (element.id() != T_vuxml)
87 return signalError_("Not a VuXML document.");
88 return &F_vuxml;
89 }
90
91
92 XMLState *
vuxml_child(const Element & element)93 BasicHandler::vuxml_child(const Element &element)
94 {
95 if (element.id() != T_vuln)
96 return signalError_("Expected `vuln' element.");
97 return &F_vuln0;
98 }
99
100
101 XMLState *
vuxml_end(const Element & element)102 BasicHandler::vuxml_end(const Element &element)
103 {
104 if (element.id() != T_vuxml)
105 return &F_dead;
106 return state_;
107 }
108
109
110 XMLState *
vuln0_child(const Element & element)111 BasicHandler::vuln0_child(const Element &element)
112 {
113 if (element.id() == T_topic)
114 return &F_topic;
115 else if (element.id() == T_cancelled)
116 return &F_cxl;
117 else
118 return signalError_("Expected `topic' element.");
119 }
120
121
122 namespace {
isValidVidCharacter(char c)123 bool isValidVidCharacter(char c) {
124 using std::islower;
125 using std::isdigit;
126 return (islower(c) || isdigit(c) || c == '-');
127 }
128 }
129
130
131 void
vuln0_start(const Element & __unused element,Attributes & attr)132 BasicHandler::vuln0_start(const Element & __unused element,
133 Attributes &attr)
134 {
135 entry_.reset(new Entry);
136 std::string vid = killspace(attr["vid"]);
137 if (vid.size() == 0) {
138 signalError_("Empty or missing `vid' attribute.");
139 return;
140 }
141 std::transform(vid.begin(), vid.end(), vid.begin(), ::tolower);
142 std::string::const_iterator p = std::find_if(vid.begin(), vid.end(),
143 std::not1(std::ptr_fun(isValidVidCharacter)));
144 if (p != vid.end()) {
145 signalError_("Malformed `vid' attribute.");
146 return;
147 }
148 entry_->setVid(vid);
149 }
150
151
152 void
tmp_start(const Element & __unused element,Attributes & __unused attr)153 BasicHandler::tmp_start(const Element & __unused element,
154 Attributes & __unused attr)
155 {
156 tmp_ = std::string();
157 }
158
159
160 void
tmp_characters(std::string & pcdata)161 BasicHandler::tmp_characters(std::string &pcdata)
162 {
163 tmp_ += pcdata;
164 }
165
166
167 XMLState *
topic_end(const Element & __unused element)168 BasicHandler::topic_end(const Element & __unused element)
169 {
170 entry_->setTopic(killspace(tmp_));
171 return &F_vuln1;
172 }
173
174
175 XMLState *
vuln1_child(const Element & element)176 BasicHandler::vuln1_child(const Element &element)
177 {
178 if (element.id() != T_affects)
179 return signalError_("Expected `affects' element.");
180 return &F_affects;
181 }
182
183
184 XMLState *
affects_child(const Element & element)185 BasicHandler::affects_child(const Element &element)
186 {
187 switch (element.id()) {
188 case T_package:
189 return &F_package;
190 case T_system:
191 return &F_system;
192 default:
193 return signalError_("Expected `package' or `system' element.");
194 }
195 }
196
197
198 XMLState *
affects_end(const Element & element)199 BasicHandler::affects_end(const Element &element)
200 {
201 if (element.id() != T_affects)
202 return &F_dead;
203 return &F_vuln2;
204 }
205
206
207 XMLState *
package_child(const Element & element)208 BasicHandler::package_child(const Element &element)
209 {
210 switch (element.id()) {
211 case T_name:
212 push_state(state_);
213 return &F_name;
214 case T_range:
215 push_state(state_);
216 return &F_range;
217 default:
218 return signalError_("Expected `name' or `range' element.");
219 }
220 }
221
222
223 void
package_start(const Element & __unused element,Attributes & __unused attr)224 BasicHandler::package_start(const Element & __unused element,
225 Attributes & __unused attr)
226 {
227 entry_->addAffectedSet();
228 }
229
230
231 XMLState *
package_end(const Element & element)232 BasicHandler::package_end(const Element &element)
233 {
234 if (element.id() != T_package && element.id() != T_system)
235 return &F_dead;
236 return &F_affects;
237 }
238
239
240 XMLState *
name_end(const Element & __unused element)241 BasicHandler::name_end(const Element & __unused element)
242 {
243 entry_->addAffectedName(killspace(tmp_));
244 return pop_state();
245 }
246
247
248 XMLState *
range_child(const Element & element)249 BasicHandler::range_child(const Element &element)
250 {
251 switch (element.id()) {
252 case T_gt:
253 case T_ge:
254 case T_lt:
255 case T_le:
256 case T_eq:
257 return &F_rangeop;
258 default:
259 return signalError_("Expected range operator element.");
260 }
261 }
262
263
264 void
range_start(const Element & __unused element,Attributes & __unused attr)265 BasicHandler::range_start(const Element & __unused element,
266 Attributes & __unused attr)
267 {
268 range_ = VersionRange();
269 }
270
271
272 XMLState *
range_end(const Element & __unused element)273 BasicHandler::range_end(const Element & __unused element)
274 {
275 entry_->addAffectedRange(range_);
276 return pop_state();
277 }
278
279
280 XMLState *
rangeop_end(const Element & element)281 BasicHandler::rangeop_end(const Element &element)
282 {
283 tmp_ = killspace(tmp_);
284 switch (element.id()) {
285 case T_gt:
286 range_.lo_closed = false;
287 // fallthrough
288 case T_ge:
289 range_.lo = tmp_;
290 break;
291 case T_lt:
292 range_.hi_closed = false;
293 // fallthrough
294 case T_le:
295 range_.hi = tmp_;
296 break;
297 case T_eq:
298 range_.hi = range_.lo = tmp_;
299 break;
300 default:
301 throw except("Internal error: rangeop_end, bad element");
302 }
303 return &F_range;
304 }
305
306
307
308 namespace {
309 class appendAttribute : public std::unary_function<void,
310 std::pair<const std::string, std::string> &> {
311 private:
312 std::string &s_;
313 public:
appendAttribute(std::string & s)314 appendAttribute(std::string &s) : s_(s) {}
operator ()(std::pair<const std::string,std::string> & item)315 void operator()(std::pair<const std::string, std::string> &item) {
316 s_ += ' ';
317 s_ += item.first;
318 s_ += "=\"";
319 s_ += xmlescape(item.second);
320 s_ += '"';
321 }
322 };
323 }
324
325
326 XMLState *
vuln2_child(const Element & element)327 BasicHandler::vuln2_child(const Element &element)
328 {
329 if (element.id() != T_description)
330 return signalError_("Expected `description' element.");
331 return &F_description;
332 }
333
334
335 void
description_start(const Element & element,Attributes & attr)336 BasicHandler::description_start(const Element &element, Attributes &attr)
337 {
338 std::string s;
339 switch (element.id()) {
340 case T_description:
341 break;
342 case T_XHTML_BODY:
343 break;
344 case T_XHTML:
345 s += '<';
346 s += element.name();
347 if (element.id() == T_XHTML_BODY) {
348 s += " xmlns=\"";
349 s += XHTML_NAMESPACE;
350 s += '"';
351 }
352 std::for_each(attr.begin(), attr.end(), appendAttribute(s));
353 s += '>';
354 entry_->appendDescription(s);
355 break;
356 default:
357 signalError_("Expected element in XHTML namespace.");
358 break;
359 }
360 }
361
362
363 void
description_characters(std::string & pcdata)364 BasicHandler::description_characters(std::string &pcdata)
365 {
366 entry_->appendDescription(xmlescape(pcdata));
367 }
368
369
370 XMLState *
description_end(const Element & element)371 BasicHandler::description_end(const Element &element)
372 {
373 if (element.id() == T_description)
374 return &F_vuln3;
375 else if (element.id() == T_XHTML_BODY)
376 return state_;
377 std::string s;
378 s += "</";
379 s += element.name();
380 s += '>';
381 entry_->appendDescription(s);
382 return state_;
383 }
384
385
386 XMLState *
vuln3_child(const Element & element)387 BasicHandler::vuln3_child(const Element &element)
388 {
389 if (element.id() != T_references)
390 return signalError_("Expected `references' element.");
391 return &F_references;
392 }
393
394
395 XMLState *
references_child(const Element & element)396 BasicHandler::references_child(const Element &element)
397 {
398 switch (element.id()) {
399 case T_url:
400 case T_cvename:
401 case T_freebsdsa:
402 case T_bid:
403 case T_certsa:
404 case T_certvu:
405 case T_mlist:
406 case T_uscertsa:
407 case T_uscertta:
408 case T_freebsdpr:
409 return &F_reference;
410 default:
411 return signalError_("Expected a reference element.");
412 }
413 }
414
415
416 XMLState *
references_end(const Element & element)417 BasicHandler::references_end(const Element &element)
418 {
419 if (element.id() != T_references)
420 return &F_dead;
421 return &F_vuln4;
422 }
423
424
425 XMLState *
reference_end(const Element & element)426 BasicHandler::reference_end(const Element &element)
427 {
428 entry_->addReference(element.name(), killspace(tmp_));
429 return &F_references;
430 }
431
432
433 XMLState *
vuln4_child(const Element & element)434 BasicHandler::vuln4_child(const Element &element)
435 {
436 if (element.id() != T_dates)
437 return signalError_("Expected `dates' element.");
438 return &F_dates0;
439 }
440
441
442 XMLState *
dates0_child(const Element & element)443 BasicHandler::dates0_child(const Element &element)
444 {
445 if (element.id() != T_discovery)
446 return signalError_("Expected `discovery' element.");
447 return &F_discovery;
448 }
449
450
451 XMLState *
discovery_end(const Element & __unused element)452 BasicHandler::discovery_end(const Element & __unused element)
453 {
454 entry_->setDiscoveryDate(killspace(tmp_));
455 return &F_dates1;
456 }
457
458
459 XMLState *
dates1_child(const Element & element)460 BasicHandler::dates1_child(const Element &element)
461 {
462 if (element.id() != T_entry)
463 return signalError_("Expected `entry' element.");
464 return &F_entry;
465 }
466
467
468 XMLState *
entry_end(const Element & __unused element)469 BasicHandler::entry_end(const Element & __unused element)
470 {
471 entry_->setEntryDate(killspace(tmp_));
472 return &F_dates2;
473 }
474
475
476 XMLState *
dates2_child(const Element & element)477 BasicHandler::dates2_child(const Element &element)
478 {
479 if (element.id() != T_modified)
480 return signalError_("Expected `modified' element.");
481 return &F_modified;
482 }
483
484
485 XMLState *
modified_end(const Element & __unused element)486 BasicHandler::modified_end(const Element & __unused element)
487 {
488 entry_->setModifiedDate(killspace(tmp_));
489 return &F_dates3;
490 }
491
492
493 XMLState *
dates2_end(const Element & element)494 BasicHandler::dates2_end(const Element &element)
495 {
496 if (element.id() != T_dates)
497 return &F_dead;
498 return &F_vuln5;
499 }
500
501
502 XMLState *
vuln5_end(const Element & element)503 BasicHandler::vuln5_end(const Element &element)
504 {
505 if (element.id() == T_vuln) {
506 proc_(*entry_);
507 return &F_vuxml;
508 }
509 return state_;
510 }
511
512
513 XMLState *
cxl_end(const Element & element)514 BasicHandler::cxl_end(const Element &element)
515 {
516 return &F_vuln5;
517 }
518
519
520 void
setParser(Parser & parser)521 BasicHandler::setParser(Parser &parser)
522 {
523 parser_ = &parser;
524 }
525
526
527 XMLState *
top_state()528 BasicHandler::top_state()
529 {
530 return state_stack_.top();
531 }
532
533
534 XMLState *
pop_state()535 BasicHandler::pop_state()
536 {
537 XMLState *s = state_stack_.top();
538 state_stack_.pop();
539 return s;
540 }
541
542
543 void
push_state(XMLState * state)544 BasicHandler::push_state(XMLState *state)
545 {
546 state_stack_.push(state);
547 }
548
549
550 void
startElement(std::string & xmlns,std::string & name,Attributes & attr)551 BasicHandler::startElement(std::string &xmlns, std::string &name,
552 Attributes &attr)
553 {
554 Element element(xmlns, name);
555 #if defined(DEBUG_STATE)
556 LOG << "child state=" << static_cast<void *>(state_) << '\n';
557 #endif
558 state_ = state_->child(element);
559 #if defined(DEBUG_STATE)
560 LOG << "start state=" << static_cast<void *>(state_) << '\n';
561 #endif
562 state_->start(element, attr);
563 }
564
565
566 void
characters(std::string & pcdata)567 BasicHandler::characters(std::string &pcdata)
568 {
569 #if defined(DEBUG_STATE)
570 LOG << "characters state=" << static_cast<void *>(state_) << '\n';
571 #endif
572 state_->characters(pcdata);
573 }
574
575
576 void
endElement(std::string & xmlns,std::string & name)577 BasicHandler::endElement(std::string &xmlns, std::string &name)
578 {
579 Element element(xmlns, name);
580 #if defined(DEBUG_STATE)
581 LOG << "end state=" << static_cast<void *>(state_) << '\n';
582 #endif
583 state_ = state_->end(element);
584 }
585
586
587 XMLState *
dead_child(const Element & __unused element)588 BasicHandler::dead_child(const Element & __unused element)
589 {
590 return signalError_("Start of element unexpected.");
591 }
592
593
594 void
dead_start(const Element & __unused element,Attributes & __unused attr)595 BasicHandler::dead_start(const Element & __unused element,
596 Attributes & __unused attr)
597 {
598 signalError_("Attributes unexpected.");
599 }
600
601
602 void
dead_characters(std::string & __unused pcdata)603 BasicHandler::dead_characters(std::string & __unused pcdata)
604 {
605 signalError_("Character data unexpected.");
606 }
607
608
609 XMLState *
dead_end(const Element & __unused element)610 BasicHandler::dead_end(const Element & __unused element)
611 {
612 return signalError_("End of element unexpected.");
613 }
614
615
616 XMLState *
ignore_child(const Element & __unused element)617 BasicHandler::ignore_child(const Element & __unused element)
618 {
619 return state_;
620 }
621
622
623 void
ignore_start(const Element & __unused element,Attributes & __unused attr)624 BasicHandler::ignore_start(const Element & __unused element,
625 Attributes & __unused attr)
626 {
627 }
628
629
630 void
ignore_characters(std::string & __unused pcdata)631 BasicHandler::ignore_characters(std::string & __unused pcdata)
632 {
633 }
634
635
636 XMLState *
ignore_end(const Element & __unused element)637 BasicHandler::ignore_end(const Element & __unused element)
638 {
639 return state_;
640 }
641