Bug Summary

File:src/mod/xml_int/mod_xml_rpc/../../../../libs/xmlrpc-c/src/xmlrpc_expat.c
Location:line 300, column 10
Description:Dereference of null pointer

Annotated Source Code

1/* Copyright information is at end of file */
2
3#include "xmlrpc_config.h"
4
5#include <stddef.h>
6#include <stdlib.h>
7#include <string.h>
8
9#include <xmlparse.h> /* Expat */
10
11#include "bool.h"
12
13#include "xmlrpc-c/base.h"
14#include "xmlrpc-c/base_int.h"
15#include "xmlrpc-c/string_int.h"
16#include "xmlrpc-c/xmlparser.h"
17
18/* Define the contents of our internal structure. */
19struct _xml_element {
20 struct _xml_element *_parent;
21 char *_name;
22 xmlrpc_mem_block _cdata; /* char */
23 xmlrpc_mem_block _children; /* xml_element* */
24};
25
26/* Check that we're using expat in UTF-8 mode, not wchar_t mode.
27** If you need to use expat in wchar_t mode, write a subroutine to
28** copy a wchar_t string to a char string & return an error for
29** any non-ASCII characters. Then call this subroutine on all
30** XML_Char strings passed to our event handlers before using the
31** data. */
32/* #if sizeof(char) != sizeof(XML_Char)
33** #error expat must define XML_Char to be a regular char.
34** #endif
35*/
36
37#define XMLRPC_ASSERT_ELEM_OK(elem)do if (!((elem) != ((void*)0) && (elem)->_name != (
(void*) 0xDEADBEEF))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 37); while (0)
\
38 XMLRPC_ASSERT((elem) != NULL && (elem)->_name != XMLRPC_BAD_POINTER)do if (!((elem) != ((void*)0) && (elem)->_name != (
(void*) 0xDEADBEEF))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 38); while (0)
39
40
41/*=========================================================================
42** xml_element_new
43**=========================================================================
44** Create a new xml_element. This routine isn't exported, because the
45** arguments are implementation-dependent.
46*/
47
48static xml_element *
49xml_element_new (xmlrpc_env * const env,
50 const char * const name) {
51
52 xml_element *retval;
53 int name_valid, cdata_valid, children_valid;
54
55 XMLRPC_ASSERT_ENV_OK(env)do if (!((env) != ((void*)0) && (env->fault_string
== ((void*)0)) && !(env)->fault_occurred)) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c", 55); while (
0)
;
56 XMLRPC_ASSERT(name != NULL)do if (!(name != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 56); while (0)
;
57
58 /* Set up our error-handling preconditions. */
59 retval = NULL((void*)0);
60 name_valid = cdata_valid = children_valid = 0;
61
62 /* Allocate our xml_element structure. */
63 retval = (xml_element*) malloc(sizeof(xml_element));
64 XMLRPC_FAIL_IF_NULL(retval, env, XMLRPC_INTERNAL_ERROR,do { if ((retval) == ((void*)0)) do { xmlrpc_env_set_fault(((
env)),(((-500))),(("Couldn't allocate memory for XML element"
))); goto cleanup; } while (0); } while (0)
65 "Couldn't allocate memory for XML element")do { if ((retval) == ((void*)0)) do { xmlrpc_env_set_fault(((
env)),(((-500))),(("Couldn't allocate memory for XML element"
))); goto cleanup; } while (0); } while (0)
;
66
67 /* Set our parent field to NULL. */
68 retval->_parent = NULL((void*)0);
69
70 /* Copy over the element name. */
71 retval->_name = (char*) malloc(strlen(name) + 1);
72 XMLRPC_FAIL_IF_NULL(retval->_name, env, XMLRPC_INTERNAL_ERROR,do { if ((retval->_name) == ((void*)0)) do { xmlrpc_env_set_fault
(((env)),(((-500))),(("Couldn't allocate memory for XML element"
))); goto cleanup; } while (0); } while (0)
73 "Couldn't allocate memory for XML element")do { if ((retval->_name) == ((void*)0)) do { xmlrpc_env_set_fault
(((env)),(((-500))),(("Couldn't allocate memory for XML element"
))); goto cleanup; } while (0); } while (0)
;
74 name_valid = 1;
75 strcpy(retval->_name, name);
76
77 /* Initialize a block to hold our CDATA. */
78 XMLRPC_TYPED_MEM_BLOCK_INIT(char, env, &retval->_cdata, 0)xmlrpc_mem_block_init((env), (&retval->_cdata), sizeof
(char) * (0))
;
79 XMLRPC_FAIL_IF_FAULT(env)do { if ((env)->fault_occurred) goto cleanup; } while (0);
80 cdata_valid = 1;
81
82 /* Initialize a block to hold our child elements. */
83 XMLRPC_TYPED_MEM_BLOCK_INIT(xml_element*, env, &retval->_children, 0)xmlrpc_mem_block_init((env), (&retval->_children), sizeof
(xml_element*) * (0))
;
84 XMLRPC_FAIL_IF_FAULT(env)do { if ((env)->fault_occurred) goto cleanup; } while (0);
85 children_valid = 1;
86
87 cleanup:
88 if (env->fault_occurred) {
89 if (retval) {
90 if (name_valid)
91 free(retval->_name);
92 if (cdata_valid)
93 xmlrpc_mem_block_clean(&retval->_cdata);
94 if (children_valid)
95 xmlrpc_mem_block_clean(&retval->_children);
96 free(retval);
97 }
98 return NULL((void*)0);
99 } else {
100 return retval;
101 }
102}
103
104
105/*=========================================================================
106** xml_element_free
107**=========================================================================
108** Blow away an existing element & all of its child elements.
109*/
110void
111xml_element_free(xml_element * const elemP) {
112
113 xmlrpc_mem_block * childrenP;
114 size_t size, i;
115 xml_element ** contents;
116
117 XMLRPC_ASSERT_ELEM_OK(elemP)do if (!((elemP) != ((void*)0) && (elemP)->_name !=
((void*) 0xDEADBEEF))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 117); while (0)
;
118
119 free(elemP->_name);
120 elemP->_name = XMLRPC_BAD_POINTER((void*) 0xDEADBEEF);
121 XMLRPC_MEMBLOCK_CLEAN(xml_element *, &elemP->_cdata)xmlrpc_mem_block_clean(&elemP->_cdata);
122
123 /* Deallocate all of our children recursively. */
124 childrenP = &elemP->_children;
125 contents = XMLRPC_MEMBLOCK_CONTENTS(xml_element *, childrenP)((xml_element **) xmlrpc_mem_block_contents(childrenP));
126 size = XMLRPC_MEMBLOCK_SIZE(xml_element *, childrenP)(xmlrpc_mem_block_size(childrenP) / sizeof(xml_element *));
127 for (i = 0; i < size; ++i)
128 xml_element_free(contents[i]);
129
130 XMLRPC_MEMBLOCK_CLEAN(xml_element *, &elemP->_children)xmlrpc_mem_block_clean(&elemP->_children);
131
132 free(elemP);
133}
134
135
136/*=========================================================================
137** Miscellaneous Accessors
138**=========================================================================
139** Return the fields of the xml_element. See the header for more
140** documentation on each function works.
141*/
142
143
144
145const char *
146xml_element_name(const xml_element * const elemP) {
147
148 XMLRPC_ASSERT_ELEM_OK(elemP)do if (!((elemP) != ((void*)0) && (elemP)->_name !=
((void*) 0xDEADBEEF))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 148); while (0)
;
149 return elemP->_name;
150}
151
152
153
154/* The result of this function is NOT VALID until the end_element handler
155** has been called! */
156size_t xml_element_cdata_size (xml_element *elem)
157{
158 XMLRPC_ASSERT_ELEM_OK(elem)do if (!((elem) != ((void*)0) && (elem)->_name != (
(void*) 0xDEADBEEF))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 158); while (0)
;
159 return XMLRPC_TYPED_MEM_BLOCK_SIZE(char, &elem->_cdata)(xmlrpc_mem_block_size(&elem->_cdata) / sizeof(char)) - 1;
160}
161
162char *xml_element_cdata (xml_element *elem)
163{
164 XMLRPC_ASSERT_ELEM_OK(elem)do if (!((elem) != ((void*)0) && (elem)->_name != (
(void*) 0xDEADBEEF))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 164); while (0)
;
165 return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(char, &elem->_cdata)((char*) xmlrpc_mem_block_contents(&elem->_cdata));
166}
167
168
169
170size_t
171xml_element_children_size(const xml_element * const elemP) {
172 XMLRPC_ASSERT_ELEM_OK(elemP)do if (!((elemP) != ((void*)0) && (elemP)->_name !=
((void*) 0xDEADBEEF))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 172); while (0)
;
173 return XMLRPC_TYPED_MEM_BLOCK_SIZE(xml_element *, &elemP->_children)(xmlrpc_mem_block_size(&elemP->_children) / sizeof(xml_element
*))
;
174}
175
176
177
178xml_element **
179xml_element_children(const xml_element * const elemP) {
180 XMLRPC_ASSERT_ELEM_OK(elemP)do if (!((elemP) != ((void*)0) && (elemP)->_name !=
((void*) 0xDEADBEEF))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 180); while (0)
;
181 return XMLRPC_TYPED_MEM_BLOCK_CONTENTS(xml_element *, &elemP->_children)((xml_element **) xmlrpc_mem_block_contents(&elemP->_children
))
;
182}
183
184
185
186/*=========================================================================
187** Internal xml_element Utility Functions
188**=========================================================================
189*/
190
191static void xml_element_append_cdata (xmlrpc_env *env,
192 xml_element *elem,
193 char *cdata,
194 size_t size)
195{
196 XMLRPC_ASSERT_ENV_OK(env)do if (!((env) != ((void*)0) && (env->fault_string
== ((void*)0)) && !(env)->fault_occurred)) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c", 196); while (
0)
;
197 XMLRPC_ASSERT_ELEM_OK(elem)do if (!((elem) != ((void*)0) && (elem)->_name != (
(void*) 0xDEADBEEF))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 197); while (0)
;
198
199 XMLRPC_TYPED_MEM_BLOCK_APPEND(char, env, &elem->_cdata, cdata, size)xmlrpc_mem_block_append(env, &elem->_cdata, cdata, sizeof
(char) * (size))
;
200}
201
202/* Whether or not this function succeeds, it takes ownership of the 'child'
203** argument.
204** WARNING - This is the exact opposite of the usual memory ownership
205** rules for xmlrpc_value! So please pay attention. */
206static void xml_element_append_child (xmlrpc_env *env,
207 xml_element *elem,
208 xml_element *child)
209{
210 XMLRPC_ASSERT_ENV_OK(env)do if (!((env) != ((void*)0) && (env->fault_string
== ((void*)0)) && !(env)->fault_occurred)) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c", 210); while (
0)
;
211 XMLRPC_ASSERT_ELEM_OK(elem)do if (!((elem) != ((void*)0) && (elem)->_name != (
(void*) 0xDEADBEEF))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 211); while (0)
;
212 XMLRPC_ASSERT_ELEM_OK(child)do if (!((child) != ((void*)0) && (child)->_name !=
((void*) 0xDEADBEEF))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 212); while (0)
;
213 XMLRPC_ASSERT(child->_parent == NULL)do if (!(child->_parent == ((void*)0))) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c", 213); while (
0)
;
214
215 XMLRPC_TYPED_MEM_BLOCK_APPEND(xml_element*, env, &elem->_children,xmlrpc_mem_block_append(env, &elem->_children, &child
, sizeof(xml_element*) * (1))
216 &child, 1)xmlrpc_mem_block_append(env, &elem->_children, &child
, sizeof(xml_element*) * (1))
;
217 if (!env->fault_occurred)
218 child->_parent = elem;
219 else
220 xml_element_free(child);
221}
222
223
224/*=========================================================================
225** Our parse context. We pass this around as expat user data.
226**=========================================================================
227*/
228
229typedef struct {
230 xmlrpc_env env;
231 xml_element * rootP;
232 xml_element * currentP;
233} parseContext;
234
235
236/*=========================================================================
237** Expat Event Handler Functions
238**=========================================================================
239*/
240
241static void
242startElement(void * const userData,
243 XML_Char * const name,
244 XML_Char ** const atts ATTR_UNUSED__attribute__((__unused__))) {
245
246 parseContext * const contextP = userData;
247
248 XMLRPC_ASSERT(contextP != NULL)do if (!(contextP != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 248); while (0)
;
249 XMLRPC_ASSERT(name != NULL)do if (!(name != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 249); while (0)
;
250
251 if (!contextP->env.fault_occurred) {
252 xml_element * elemP;
253
254 elemP = xml_element_new(&contextP->env, name);
255 if (!contextP->env.fault_occurred) {
256 XMLRPC_ASSERT(elemP != NULL)do if (!(elemP != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 256); while (0)
;
257
258 /* Insert the new element in the appropriate place. */
259 if (!contextP->rootP) {
260 /* No root yet, so this element must be the root. */
261 contextP->rootP = elemP;
262 contextP->currentP = elemP;
263 } else {
264 XMLRPC_ASSERT(contextP->currentP != NULL)do if (!(contextP->currentP != ((void*)0))) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c", 264); while (
0)
;
265
266 /* (We need to watch our error handling invariants
267 very carefully here. Read the docs for
268 xml_element_append_child.
269 */
270 xml_element_append_child(&contextP->env, contextP->currentP,
271 elemP);
272 if (!contextP->env.fault_occurred)
273 contextP->currentP = elemP;
274 }
275 if (contextP->env.fault_occurred)
276 xml_element_free(elemP);
277 }
278 if (contextP->env.fault_occurred) {
279 /* Having changed *contextP to reflect failure, we are responsible
280 for undoing everything that has been done so far in this
281 context.
282 */
283 if (contextP->rootP)
284 xml_element_free(contextP->rootP);
285 }
286 }
287}
288
289
290
291static void
292endElement(void * const userData,
293 XML_Char * const name ATTR_UNUSED__attribute__((__unused__))) {
294
295 parseContext * const contextP = userData;
1
'contextP' initialized here
296
297 XMLRPC_ASSERT(contextP != NULL)do if (!(contextP != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 297); while (0)
;
2
Within the expansion of the macro 'XMLRPC_ASSERT':
a
Assuming 'contextP' is equal to null
298 XMLRPC_ASSERT(name != NULL)do if (!(name != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 298); while (0)
;
299
300 if (!contextP->env.fault_occurred) {
3
Dereference of null pointer
301 /* I think Expat enforces these facts: */
302 XMLRPC_ASSERT(xmlrpc_streq(name, contextP->currentP->_name))do if (!(xmlrpc_streq(name, contextP->currentP->_name))
) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 302); while (0)
;
303 XMLRPC_ASSERT(contextP->currentP->_parent != NULL ||do if (!(contextP->currentP->_parent != ((void*)0) || contextP
->currentP == contextP->rootP)) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c", 304); while (
0)
304 contextP->currentP == contextP->rootP)do if (!(contextP->currentP->_parent != ((void*)0) || contextP
->currentP == contextP->rootP)) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c", 304); while (
0)
;
305
306 /* Add a trailing NUL to our cdata. */
307 xml_element_append_cdata(&contextP->env, contextP->currentP, "\0", 1);
308 if (!contextP->env.fault_occurred)
309 /* Pop our "stack" of elements. */
310 contextP->currentP = contextP->currentP->_parent;
311
312 if (contextP->env.fault_occurred) {
313 /* Having changed *contextP to reflect failure, we are responsible
314 for undoing everything that has been done so far in this
315 context.
316 */
317 if (contextP->rootP)
318 xml_element_free(contextP->rootP);
319 }
320 }
321}
322
323
324
325static void
326characterData(void * const userData,
327 XML_Char * const s,
328 int const len) {
329/*----------------------------------------------------------------------------
330 This is an Expat character data (cdata) handler. When an Expat
331 parser comes across cdata, he calls one of these with the cdata as
332 argument. He can call it multiple times for consecutive cdata.
333
334 We simply append the cdata to the cdata buffer for whatever XML
335 element the parser is presently parsing.
336-----------------------------------------------------------------------------*/
337 parseContext * const contextP = userData;
338
339 XMLRPC_ASSERT(contextP != NULL)do if (!(contextP != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 339); while (0)
;
340 XMLRPC_ASSERT(s != NULL)do if (!(s != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 340); while (0)
;
341 XMLRPC_ASSERT(len >= 0)do if (!(len >= 0)) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 341); while (0)
;
342
343 if (!contextP->env.fault_occurred) {
344 XMLRPC_ASSERT(contextP->currentP != NULL)do if (!(contextP->currentP != ((void*)0))) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c", 344); while (
0)
;
345
346 xml_element_append_cdata(&contextP->env, contextP->currentP, s, len);
347 }
348}
349
350
351
352static void
353createParser(xmlrpc_env * const envP,
354 parseContext * const contextP,
355 XML_Parser * const parserP) {
356/*----------------------------------------------------------------------------
357 Create an Expat parser to parse our XML.
358-----------------------------------------------------------------------------*/
359 XML_Parser parser;
360
361 parser = xmlrpc_XML_ParserCreate(NULL((void*)0));
362 if (parser == NULL((void*)0))
363 xmlrpc_faultf(envP, "Could not create expat parser");
364 else {
365 /* Initialize our parse context. */
366 xmlrpc_env_init(&contextP->env);
367 contextP->rootP = NULL((void*)0);
368 contextP->currentP = NULL((void*)0);
369
370 xmlrpc_XML_SetUserData(parser, contextP);
371 xmlrpc_XML_SetElementHandler(
372 parser,
373 (XML_StartElementHandler) startElement,
374 (XML_EndElementHandler) endElement);
375 xmlrpc_XML_SetCharacterDataHandler(
376 parser,
377 (XML_CharacterDataHandler) characterData);
378 }
379 *parserP = parser;
380}
381
382
383
384static void
385destroyParser(XML_Parser const parser,
386 parseContext * const contextP) {
387
388 xmlrpc_env_clean(&contextP->env);
389
390 xmlrpc_XML_ParserFree(parser);
391}
392
393
394
395void
396xml_parse(xmlrpc_env * const envP,
397 const char * const xmlData,
398 size_t const xmlDataLen,
399 xml_element ** const resultPP) {
400/*----------------------------------------------------------------------------
401 Parse the XML text 'xmlData', of length 'xmlDataLen'. Return the
402 description of the element that the XML text contains as *resultPP.
403-----------------------------------------------------------------------------*/
404 /*
405 This is an Expat driver.
406
407 We set up event-based parser handlers for Expat and set Expat loose
408 on the XML. Expat walks through the XML, calling our handlers along
409 the way. Our handlers build up the element description in our
410 'context' variable, so that when Expat is finished, our results are
411 in 'context' and we just have to pluck them out.
412
413 We should allow the user to specify the encoding in 'xmlData', but
414 we don't.
415 */
416 XML_Parser parser;
417 parseContext context;
418
419 XMLRPC_ASSERT_ENV_OK(envP)do if (!((envP) != ((void*)0) && (envP->fault_string
== ((void*)0)) && !(envP)->fault_occurred)) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c", 419); while (
0)
;
420 XMLRPC_ASSERT(xmlData != NULL)do if (!(xmlData != ((void*)0))) xmlrpc_assertion_failed("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c"
, 420); while (0)
;
421
422 createParser(envP, &context, &parser);
423
424 if (!envP->fault_occurred) {
425 bool ok;
426
427 ok = xmlrpc_XML_Parse(parser, xmlData, xmlDataLen, 1);
428 /* sets 'context', *envP */
429 if (!ok) {
430 /* Expat failed on its own to parse it -- this is not an error
431 that our handlers detected.
432 */
433 xmlrpc_env_set_fault(
434 envP, XMLRPC_PARSE_ERROR(-503),
435 xmlrpc_XML_GetErrorString(parser));
436 if (!context.env.fault_occurred) {
437 /* Have to clean up what our handlers built before Expat
438 barfed.
439 */
440 if (context.rootP)
441 xml_element_free(context.rootP);
442 }
443 } else {
444 /* Expat got through the XML OK, but when it called our handlers,
445 they might have detected a problem. They would have noted
446 such a problem in *contextP.
447 */
448 if (context.env.fault_occurred)
449 xmlrpc_env_set_fault_formatted(
450 envP, context.env.fault_code,
451 "XML doesn't parse. %s", context.env.fault_string);
452 else {
453 XMLRPC_ASSERT(context.rootP != NULL)do if (!(context.rootP != ((void*)0))) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c", 453); while (
0)
;
454 XMLRPC_ASSERT(context.currentP == NULL)do if (!(context.currentP == ((void*)0))) xmlrpc_assertion_failed
("../../../../libs/xmlrpc-c/src/xmlrpc_expat.c", 454); while (
0)
;
455
456 *resultPP = context.rootP;
457 }
458 }
459 destroyParser(parser, &context);
460 }
461}
462
463
464/* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
465**
466** Redistribution and use in source and binary forms, with or without
467** modification, are permitted provided that the following conditions
468** are met:
469** 1. Redistributions of source code must retain the above copyright
470** notice, this list of conditions and the following disclaimer.
471** 2. Redistributions in binary form must reproduce the above copyright
472** notice, this list of conditions and the following disclaimer in the
473** documentation and/or other materials provided with the distribution.
474** 3. The name of the author may not be used to endorse or promote products
475** derived from this software without specific prior written permission.
476**
477** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
478** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
479** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
480** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
481** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
482** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
483** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
484** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
485** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
486** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
487** SUCH DAMAGE. */