summaryrefslogtreecommitdiffstatshomepage
path: root/src/lib
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2007-12-17 15:19:59 +0000
committer Aaron Giles <aaron@aarongiles.com>2007-12-17 15:19:59 +0000
commit7b77f1218624ea26dbb2efd85a19f795f5d4e02e (patch)
tree19209304095572b4fd61c2a2d6a5aa75c4e471ad /src/lib
parent3da7f476068b3ffef713218ba2fc1bd5030f2c38 (diff)
Initial checkin of MAME 0.121.mame0121
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/expat/ascii.h85
-rw-r--r--src/lib/expat/asciitab.h36
-rw-r--r--src/lib/expat/expat.h1013
-rw-r--r--src/lib/expat/expat_external.h115
-rw-r--r--src/lib/expat/iasciitab.h37
-rw-r--r--src/lib/expat/intconfig.h19
-rw-r--r--src/lib/expat/internal.h73
-rw-r--r--src/lib/expat/latin1tab.h36
-rw-r--r--src/lib/expat/nametab.h150
-rw-r--r--src/lib/expat/utf8tab.h37
-rw-r--r--src/lib/expat/xmlparse.c6258
-rw-r--r--src/lib/expat/xmlrole.c1320
-rw-r--r--src/lib/expat/xmlrole.h114
-rw-r--r--src/lib/expat/xmltok.c1629
-rw-r--r--src/lib/expat/xmltok.h316
-rw-r--r--src/lib/expat/xmltok_impl.c1779
-rw-r--r--src/lib/expat/xmltok_impl.h46
-rw-r--r--src/lib/expat/xmltok_ns.c106
-rw-r--r--src/lib/lib.mak84
-rw-r--r--src/lib/util/astring.c596
-rw-r--r--src/lib/util/astring.h228
-rw-r--r--src/lib/util/avcomp.c840
-rw-r--r--src/lib/util/avcomp.h60
-rw-r--r--src/lib/util/aviio.c2744
-rw-r--r--src/lib/util/aviio.h123
-rw-r--r--src/lib/util/bitmap.c263
-rw-r--r--src/lib/util/bitmap.h169
-rw-r--r--src/lib/util/cdrom.c617
-rw-r--r--src/lib/util/cdrom.h139
-rw-r--r--src/lib/util/chd.c2860
-rw-r--r--src/lib/util/chd.h325
-rw-r--r--src/lib/util/corefile.c726
-rw-r--r--src/lib/util/corefile.h116
-rw-r--r--src/lib/util/corestr.c120
-rw-r--r--src/lib/util/corestr.h60
-rw-r--r--src/lib/util/coreutil.c102
-rw-r--r--src/lib/util/coreutil.h44
-rw-r--r--src/lib/util/harddisk.c170
-rw-r--r--src/lib/util/harddisk.h51
-rw-r--r--src/lib/util/huffman.c934
-rw-r--r--src/lib/util/huffman.h62
-rw-r--r--src/lib/util/jedparse.c435
-rw-r--r--src/lib/util/jedparse.h89
-rw-r--r--src/lib/util/md5.c239
-rw-r--r--src/lib/util/md5.h42
-rw-r--r--src/lib/util/options.c1133
-rw-r--r--src/lib/util/options.h216
-rw-r--r--src/lib/util/palette.c651
-rw-r--r--src/lib/util/palette.h259
-rw-r--r--src/lib/util/png.c1143
-rw-r--r--src/lib/util/png.h137
-rw-r--r--src/lib/util/pool.c614
-rw-r--r--src/lib/util/pool.h117
-rw-r--r--src/lib/util/sha1.c387
-rw-r--r--src/lib/util/sha1.h61
-rw-r--r--src/lib/util/unicode.c346
-rw-r--r--src/lib/util/unicode.h92
-rw-r--r--src/lib/util/unzip.c616
-rw-r--r--src/lib/util/unzip.h143
-rw-r--r--src/lib/util/xmlfile.c857
-rw-r--r--src/lib/util/xmlfile.h160
-rw-r--r--src/lib/zlib/Makefile154
-rw-r--r--src/lib/zlib/Makefile.in154
-rw-r--r--src/lib/zlib/adler32.c149
-rw-r--r--src/lib/zlib/compress.c79
-rw-r--r--src/lib/zlib/crc32.c423
-rw-r--r--src/lib/zlib/crc32.h441
-rw-r--r--src/lib/zlib/deflate.c1736
-rw-r--r--src/lib/zlib/deflate.h331
-rw-r--r--src/lib/zlib/example.c565
-rw-r--r--src/lib/zlib/gzio.c1026
-rw-r--r--src/lib/zlib/infback.c623
-rw-r--r--src/lib/zlib/inffast.c318
-rw-r--r--src/lib/zlib/inffast.h11
-rw-r--r--src/lib/zlib/inffixed.h94
-rw-r--r--src/lib/zlib/inflate.c1368
-rw-r--r--src/lib/zlib/inflate.h115
-rw-r--r--src/lib/zlib/inftrees.c329
-rw-r--r--src/lib/zlib/inftrees.h55
-rw-r--r--src/lib/zlib/minigzip.c322
-rw-r--r--src/lib/zlib/readme125
-rw-r--r--src/lib/zlib/trees.c1219
-rw-r--r--src/lib/zlib/trees.h128
-rw-r--r--src/lib/zlib/uncompr.c61
-rw-r--r--src/lib/zlib/zconf.h332
-rw-r--r--src/lib/zlib/zconf.in.h332
-rw-r--r--src/lib/zlib/zlib.h1357
-rw-r--r--src/lib/zlib/zutil.c318
-rw-r--r--src/lib/zlib/zutil.h269
89 files changed, 44773 insertions, 0 deletions
diff --git a/src/lib/expat/ascii.h b/src/lib/expat/ascii.h
new file mode 100644
index 00000000000..337e5bb7ea0
--- /dev/null
+++ b/src/lib/expat/ascii.h
@@ -0,0 +1,85 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#define ASCII_A 0x41
+#define ASCII_B 0x42
+#define ASCII_C 0x43
+#define ASCII_D 0x44
+#define ASCII_E 0x45
+#define ASCII_F 0x46
+#define ASCII_G 0x47
+#define ASCII_H 0x48
+#define ASCII_I 0x49
+#define ASCII_J 0x4A
+#define ASCII_K 0x4B
+#define ASCII_L 0x4C
+#define ASCII_M 0x4D
+#define ASCII_N 0x4E
+#define ASCII_O 0x4F
+#define ASCII_P 0x50
+#define ASCII_Q 0x51
+#define ASCII_R 0x52
+#define ASCII_S 0x53
+#define ASCII_T 0x54
+#define ASCII_U 0x55
+#define ASCII_V 0x56
+#define ASCII_W 0x57
+#define ASCII_X 0x58
+#define ASCII_Y 0x59
+#define ASCII_Z 0x5A
+
+#define ASCII_a 0x61
+#define ASCII_b 0x62
+#define ASCII_c 0x63
+#define ASCII_d 0x64
+#define ASCII_e 0x65
+#define ASCII_f 0x66
+#define ASCII_g 0x67
+#define ASCII_h 0x68
+#define ASCII_i 0x69
+#define ASCII_j 0x6A
+#define ASCII_k 0x6B
+#define ASCII_l 0x6C
+#define ASCII_m 0x6D
+#define ASCII_n 0x6E
+#define ASCII_o 0x6F
+#define ASCII_p 0x70
+#define ASCII_q 0x71
+#define ASCII_r 0x72
+#define ASCII_s 0x73
+#define ASCII_t 0x74
+#define ASCII_u 0x75
+#define ASCII_v 0x76
+#define ASCII_w 0x77
+#define ASCII_x 0x78
+#define ASCII_y 0x79
+#define ASCII_z 0x7A
+
+#define ASCII_0 0x30
+#define ASCII_1 0x31
+#define ASCII_2 0x32
+#define ASCII_3 0x33
+#define ASCII_4 0x34
+#define ASCII_5 0x35
+#define ASCII_6 0x36
+#define ASCII_7 0x37
+#define ASCII_8 0x38
+#define ASCII_9 0x39
+
+#define ASCII_TAB 0x09
+#define ASCII_SPACE 0x20
+#define ASCII_EXCL 0x21
+#define ASCII_QUOT 0x22
+#define ASCII_AMP 0x26
+#define ASCII_APOS 0x27
+#define ASCII_MINUS 0x2D
+#define ASCII_PERIOD 0x2E
+#define ASCII_COLON 0x3A
+#define ASCII_SEMI 0x3B
+#define ASCII_LT 0x3C
+#define ASCII_EQUALS 0x3D
+#define ASCII_GT 0x3E
+#define ASCII_LSQB 0x5B
+#define ASCII_RSQB 0x5D
+#define ASCII_UNDERSCORE 0x5F
diff --git a/src/lib/expat/asciitab.h b/src/lib/expat/asciitab.h
new file mode 100644
index 00000000000..79a15c28ca1
--- /dev/null
+++ b/src/lib/expat/asciitab.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
+/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
+/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
+/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
+/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
+/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
+/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
+/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
+/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
+/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
+/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/src/lib/expat/expat.h b/src/lib/expat/expat.h
new file mode 100644
index 00000000000..00ddbcee4ad
--- /dev/null
+++ b/src/lib/expat/expat.h
@@ -0,0 +1,1013 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef Expat_INCLUDED
+#define Expat_INCLUDED 1
+
+#ifdef __VMS
+/* 0 1 2 3 0 1 2 3
+ 1234567890123456789012345678901 1234567890123456789012345678901 */
+#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler
+#define XML_SetUnparsedEntityDeclHandler XML_SetUnparsedEntDeclHandler
+#define XML_SetStartNamespaceDeclHandler XML_SetStartNamespcDeclHandler
+#define XML_SetExternalEntityRefHandlerArg XML_SetExternalEntRefHandlerArg
+#endif
+
+#include <stdlib.h>
+#include "expat_external.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct XML_ParserStruct;
+typedef struct XML_ParserStruct *XML_Parser;
+
+/* Should this be defined using stdbool.h when C99 is available? */
+typedef unsigned char XML_Bool;
+#define XML_TRUE ((XML_Bool) 1)
+#define XML_FALSE ((XML_Bool) 0)
+
+/* The XML_Status enum gives the possible return values for several
+ API functions. The preprocessor #defines are included so this
+ stanza can be added to code that still needs to support older
+ versions of Expat 1.95.x:
+
+ #ifndef XML_STATUS_OK
+ #define XML_STATUS_OK 1
+ #define XML_STATUS_ERROR 0
+ #endif
+
+ Otherwise, the #define hackery is quite ugly and would have been
+ dropped.
+*/
+enum XML_Status {
+ XML_STATUS_ERROR = 0,
+#define XML_STATUS_ERROR XML_STATUS_ERROR
+ XML_STATUS_OK = 1,
+#define XML_STATUS_OK XML_STATUS_OK
+ XML_STATUS_SUSPENDED = 2
+#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED
+};
+
+enum XML_Error {
+ XML_ERROR_NONE,
+ XML_ERROR_NO_MEMORY,
+ XML_ERROR_SYNTAX,
+ XML_ERROR_NO_ELEMENTS,
+ XML_ERROR_INVALID_TOKEN,
+ XML_ERROR_UNCLOSED_TOKEN,
+ XML_ERROR_PARTIAL_CHAR,
+ XML_ERROR_TAG_MISMATCH,
+ XML_ERROR_DUPLICATE_ATTRIBUTE,
+ XML_ERROR_JUNK_AFTER_DOC_ELEMENT,
+ XML_ERROR_PARAM_ENTITY_REF,
+ XML_ERROR_UNDEFINED_ENTITY,
+ XML_ERROR_RECURSIVE_ENTITY_REF,
+ XML_ERROR_ASYNC_ENTITY,
+ XML_ERROR_BAD_CHAR_REF,
+ XML_ERROR_BINARY_ENTITY_REF,
+ XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF,
+ XML_ERROR_MISPLACED_XML_PI,
+ XML_ERROR_UNKNOWN_ENCODING,
+ XML_ERROR_INCORRECT_ENCODING,
+ XML_ERROR_UNCLOSED_CDATA_SECTION,
+ XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ XML_ERROR_NOT_STANDALONE,
+ XML_ERROR_UNEXPECTED_STATE,
+ XML_ERROR_ENTITY_DECLARED_IN_PE,
+ XML_ERROR_FEATURE_REQUIRES_XML_DTD,
+ XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING,
+ /* Added in 1.95.7. */
+ XML_ERROR_UNBOUND_PREFIX,
+ /* Added in 1.95.8. */
+ XML_ERROR_UNDECLARING_PREFIX,
+ XML_ERROR_INCOMPLETE_PE,
+ XML_ERROR_XML_DECL,
+ XML_ERROR_TEXT_DECL,
+ XML_ERROR_PUBLICID,
+ XML_ERROR_SUSPENDED,
+ XML_ERROR_NOT_SUSPENDED,
+ XML_ERROR_ABORTED,
+ XML_ERROR_FINISHED,
+ XML_ERROR_SUSPEND_PE,
+ /* Added in 2.0. */
+ XML_ERROR_RESERVED_PREFIX_XML,
+ XML_ERROR_RESERVED_PREFIX_XMLNS,
+ XML_ERROR_RESERVED_NAMESPACE_URI
+};
+
+enum XML_Content_Type {
+ XML_CTYPE_EMPTY = 1,
+ XML_CTYPE_ANY,
+ XML_CTYPE_MIXED,
+ XML_CTYPE_NAME,
+ XML_CTYPE_CHOICE,
+ XML_CTYPE_SEQ
+};
+
+enum XML_Content_Quant {
+ XML_CQUANT_NONE,
+ XML_CQUANT_OPT,
+ XML_CQUANT_REP,
+ XML_CQUANT_PLUS
+};
+
+/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be
+ XML_CQUANT_NONE, and the other fields will be zero or NULL.
+ If type == XML_CTYPE_MIXED, then quant will be NONE or REP and
+ numchildren will contain number of elements that may be mixed in
+ and children point to an array of XML_Content cells that will be
+ all of XML_CTYPE_NAME type with no quantification.
+
+ If type == XML_CTYPE_NAME, then the name points to the name, and
+ the numchildren field will be zero and children will be NULL. The
+ quant fields indicates any quantifiers placed on the name.
+
+ CHOICE and SEQ will have name NULL, the number of children in
+ numchildren and children will point, recursively, to an array
+ of XML_Content cells.
+
+ The EMPTY, ANY, and MIXED types will only occur at top level.
+*/
+
+typedef struct XML_cp XML_Content;
+
+struct XML_cp {
+ enum XML_Content_Type type;
+ enum XML_Content_Quant quant;
+ XML_Char * name;
+ unsigned int numchildren;
+ XML_Content * children;
+};
+
+
+/* This is called for an element declaration. See above for
+ description of the model argument. It's the caller's responsibility
+ to free model when finished with it.
+*/
+typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData,
+ const XML_Char *name,
+ XML_Content *model);
+
+XMLPARSEAPI(void)
+XML_SetElementDeclHandler(XML_Parser parser,
+ XML_ElementDeclHandler eldecl);
+
+/* The Attlist declaration handler is called for *each* attribute. So
+ a single Attlist declaration with multiple attributes declared will
+ generate multiple calls to this handler. The "default" parameter
+ may be NULL in the case of the "#IMPLIED" or "#REQUIRED"
+ keyword. The "isrequired" parameter will be true and the default
+ value will be NULL in the case of "#REQUIRED". If "isrequired" is
+ true and default is non-NULL, then this is a "#FIXED" default.
+*/
+typedef void (XMLCALL *XML_AttlistDeclHandler) (
+ void *userData,
+ const XML_Char *elname,
+ const XML_Char *attname,
+ const XML_Char *att_type,
+ const XML_Char *dflt,
+ int isrequired);
+
+XMLPARSEAPI(void)
+XML_SetAttlistDeclHandler(XML_Parser parser,
+ XML_AttlistDeclHandler attdecl);
+
+/* The XML declaration handler is called for *both* XML declarations
+ and text declarations. The way to distinguish is that the version
+ parameter will be NULL for text declarations. The encoding
+ parameter may be NULL for XML declarations. The standalone
+ parameter will be -1, 0, or 1 indicating respectively that there
+ was no standalone parameter in the declaration, that it was given
+ as no, or that it was given as yes.
+*/
+typedef void (XMLCALL *XML_XmlDeclHandler) (void *userData,
+ const XML_Char *version,
+ const XML_Char *encoding,
+ int standalone);
+
+XMLPARSEAPI(void)
+XML_SetXmlDeclHandler(XML_Parser parser,
+ XML_XmlDeclHandler xmldecl);
+
+
+typedef struct {
+ void *(*malloc_fcn)(size_t size);
+ void *(*realloc_fcn)(void *ptr, size_t size);
+ void (*free_fcn)(void *ptr);
+} XML_Memory_Handling_Suite;
+
+/* Constructs a new parser; encoding is the encoding specified by the
+ external protocol or NULL if there is none specified.
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ParserCreate(const XML_Char *encoding);
+
+/* Constructs a new parser and namespace processor. Element type
+ names and attribute names that belong to a namespace will be
+ expanded; unprefixed attribute names are never expanded; unprefixed
+ element type names are expanded only if there is a default
+ namespace. The expanded name is the concatenation of the namespace
+ URI, the namespace separator character, and the local part of the
+ name. If the namespace separator is '\0' then the namespace URI
+ and the local part will be concatenated without any separator.
+ It is a programming error to use the separator '\0' with namespace
+ triplets (see XML_SetReturnNSTriplet).
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator);
+
+
+/* Constructs a new parser using the memory management suite referred to
+ by memsuite. If memsuite is NULL, then use the standard library memory
+ suite. If namespaceSeparator is non-NULL it creates a parser with
+ namespace processing as described above. The character pointed at
+ will serve as the namespace separator.
+
+ All further memory operations used for the created parser will come from
+ the given suite.
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ParserCreate_MM(const XML_Char *encoding,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *namespaceSeparator);
+
+/* Prepare a parser object to be re-used. This is particularly
+ valuable when memory allocation overhead is disproportionatly high,
+ such as when a large number of small documnents need to be parsed.
+ All handlers are cleared from the parser, except for the
+ unknownEncodingHandler. The parser's external state is re-initialized
+ except for the values of ns and ns_triplets.
+
+ Added in Expat 1.95.3.
+*/
+XMLPARSEAPI(XML_Bool)
+XML_ParserReset(XML_Parser parser, const XML_Char *encoding);
+
+/* atts is array of name/value pairs, terminated by 0;
+ names and values are 0 terminated.
+*/
+typedef void (XMLCALL *XML_StartElementHandler) (void *userData,
+ const XML_Char *name,
+ const XML_Char **atts);
+
+typedef void (XMLCALL *XML_EndElementHandler) (void *userData,
+ const XML_Char *name);
+
+
+/* s is not 0 terminated. */
+typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData,
+ const XML_Char *s,
+ int len);
+
+/* target and data are 0 terminated */
+typedef void (XMLCALL *XML_ProcessingInstructionHandler) (
+ void *userData,
+ const XML_Char *target,
+ const XML_Char *data);
+
+/* data is 0 terminated */
+typedef void (XMLCALL *XML_CommentHandler) (void *userData,
+ const XML_Char *data);
+
+typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData);
+typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData);
+
+/* This is called for any characters in the XML document for which
+ there is no applicable handler. This includes both characters that
+ are part of markup which is of a kind that is not reported
+ (comments, markup declarations), or characters that are part of a
+ construct which could be reported but for which no handler has been
+ supplied. The characters are passed exactly as they were in the XML
+ document except that they will be encoded in UTF-8 or UTF-16.
+ Line boundaries are not normalized. Note that a byte order mark
+ character is not passed to the default handler. There are no
+ guarantees about how characters are divided between calls to the
+ default handler: for example, a comment might be split between
+ multiple calls.
+*/
+typedef void (XMLCALL *XML_DefaultHandler) (void *userData,
+ const XML_Char *s,
+ int len);
+
+/* This is called for the start of the DOCTYPE declaration, before
+ any DTD or internal subset is parsed.
+*/
+typedef void (XMLCALL *XML_StartDoctypeDeclHandler) (
+ void *userData,
+ const XML_Char *doctypeName,
+ const XML_Char *sysid,
+ const XML_Char *pubid,
+ int has_internal_subset);
+
+/* This is called for the start of the DOCTYPE declaration when the
+ closing > is encountered, but after processing any external
+ subset.
+*/
+typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData);
+
+/* This is called for entity declarations. The is_parameter_entity
+ argument will be non-zero if the entity is a parameter entity, zero
+ otherwise.
+
+ For internal entities (<!ENTITY foo "bar">), value will
+ be non-NULL and systemId, publicID, and notationName will be NULL.
+ The value string is NOT nul-terminated; the length is provided in
+ the value_length argument. Since it is legal to have zero-length
+ values, do not use this argument to test for internal entities.
+
+ For external entities, value will be NULL and systemId will be
+ non-NULL. The publicId argument will be NULL unless a public
+ identifier was provided. The notationName argument will have a
+ non-NULL value only for unparsed entity declarations.
+
+ Note that is_parameter_entity can't be changed to XML_Bool, since
+ that would break binary compatibility.
+*/
+typedef void (XMLCALL *XML_EntityDeclHandler) (
+ void *userData,
+ const XML_Char *entityName,
+ int is_parameter_entity,
+ const XML_Char *value,
+ int value_length,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId,
+ const XML_Char *notationName);
+
+XMLPARSEAPI(void)
+XML_SetEntityDeclHandler(XML_Parser parser,
+ XML_EntityDeclHandler handler);
+
+/* OBSOLETE -- OBSOLETE -- OBSOLETE
+ This handler has been superceded by the EntityDeclHandler above.
+ It is provided here for backward compatibility.
+
+ This is called for a declaration of an unparsed (NDATA) entity.
+ The base argument is whatever was set by XML_SetBase. The
+ entityName, systemId and notationName arguments will never be
+ NULL. The other arguments may be.
+*/
+typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) (
+ void *userData,
+ const XML_Char *entityName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId,
+ const XML_Char *notationName);
+
+/* This is called for a declaration of notation. The base argument is
+ whatever was set by XML_SetBase. The notationName will never be
+ NULL. The other arguments can be.
+*/
+typedef void (XMLCALL *XML_NotationDeclHandler) (
+ void *userData,
+ const XML_Char *notationName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+/* When namespace processing is enabled, these are called once for
+ each namespace declaration. The call to the start and end element
+ handlers occur between the calls to the start and end namespace
+ declaration handlers. For an xmlns attribute, prefix will be
+ NULL. For an xmlns="" attribute, uri will be NULL.
+*/
+typedef void (XMLCALL *XML_StartNamespaceDeclHandler) (
+ void *userData,
+ const XML_Char *prefix,
+ const XML_Char *uri);
+
+typedef void (XMLCALL *XML_EndNamespaceDeclHandler) (
+ void *userData,
+ const XML_Char *prefix);
+
+/* This is called if the document is not standalone, that is, it has an
+ external subset or a reference to a parameter entity, but does not
+ have standalone="yes". If this handler returns XML_STATUS_ERROR,
+ then processing will not continue, and the parser will return a
+ XML_ERROR_NOT_STANDALONE error.
+ If parameter entity parsing is enabled, then in addition to the
+ conditions above this handler will only be called if the referenced
+ entity was actually read.
+*/
+typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData);
+
+/* This is called for a reference to an external parsed general
+ entity. The referenced entity is not automatically parsed. The
+ application can parse it immediately or later using
+ XML_ExternalEntityParserCreate.
+
+ The parser argument is the parser parsing the entity containing the
+ reference; it can be passed as the parser argument to
+ XML_ExternalEntityParserCreate. The systemId argument is the
+ system identifier as specified in the entity declaration; it will
+ not be NULL.
+
+ The base argument is the system identifier that should be used as
+ the base for resolving systemId if systemId was relative; this is
+ set by XML_SetBase; it may be NULL.
+
+ The publicId argument is the public identifier as specified in the
+ entity declaration, or NULL if none was specified; the whitespace
+ in the public identifier will have been normalized as required by
+ the XML spec.
+
+ The context argument specifies the parsing context in the format
+ expected by the context argument to XML_ExternalEntityParserCreate;
+ context is valid only until the handler returns, so if the
+ referenced entity is to be parsed later, it must be copied.
+ context is NULL only when the entity is a parameter entity.
+
+ The handler should return XML_STATUS_ERROR if processing should not
+ continue because of a fatal error in the handling of the external
+ entity. In this case the calling parser will return an
+ XML_ERROR_EXTERNAL_ENTITY_HANDLING error.
+
+ Note that unlike other handlers the first argument is the parser,
+ not userData.
+*/
+typedef int (XMLCALL *XML_ExternalEntityRefHandler) (
+ XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+/* This is called in two situations:
+ 1) An entity reference is encountered for which no declaration
+ has been read *and* this is not an error.
+ 2) An internal entity reference is read, but not expanded, because
+ XML_SetDefaultHandler has been called.
+ Note: skipped parameter entities in declarations and skipped general
+ entities in attribute values cannot be reported, because
+ the event would be out of sync with the reporting of the
+ declarations or attribute values
+*/
+typedef void (XMLCALL *XML_SkippedEntityHandler) (
+ void *userData,
+ const XML_Char *entityName,
+ int is_parameter_entity);
+
+/* This structure is filled in by the XML_UnknownEncodingHandler to
+ provide information to the parser about encodings that are unknown
+ to the parser.
+
+ The map[b] member gives information about byte sequences whose
+ first byte is b.
+
+ If map[b] is c where c is >= 0, then b by itself encodes the
+ Unicode scalar value c.
+
+ If map[b] is -1, then the byte sequence is malformed.
+
+ If map[b] is -n, where n >= 2, then b is the first byte of an
+ n-byte sequence that encodes a single Unicode scalar value.
+
+ The data member will be passed as the first argument to the convert
+ function.
+
+ The convert function is used to convert multibyte sequences; s will
+ point to a n-byte sequence where map[(unsigned char)*s] == -n. The
+ convert function must return the Unicode scalar value represented
+ by this byte sequence or -1 if the byte sequence is malformed.
+
+ The convert function may be NULL if the encoding is a single-byte
+ encoding, that is if map[b] >= -1 for all bytes b.
+
+ When the parser is finished with the encoding, then if release is
+ not NULL, it will call release passing it the data member; once
+ release has been called, the convert function will not be called
+ again.
+
+ Expat places certain restrictions on the encodings that are supported
+ using this mechanism.
+
+ 1. Every ASCII character that can appear in a well-formed XML document,
+ other than the characters
+
+ $@\^`{}~
+
+ must be represented by a single byte, and that byte must be the
+ same byte that represents that character in ASCII.
+
+ 2. No character may require more than 4 bytes to encode.
+
+ 3. All characters encoded must have Unicode scalar values <=
+ 0xFFFF, (i.e., characters that would be encoded by surrogates in
+ UTF-16 are not allowed). Note that this restriction doesn't
+ apply to the built-in support for UTF-8 and UTF-16.
+
+ 4. No Unicode character may be encoded by more than one distinct
+ sequence of bytes.
+*/
+typedef struct {
+ int map[256];
+ void *data;
+ int (XMLCALL *convert)(void *data, const char *s);
+ void (XMLCALL *release)(void *data);
+} XML_Encoding;
+
+/* This is called for an encoding that is unknown to the parser.
+
+ The encodingHandlerData argument is that which was passed as the
+ second argument to XML_SetUnknownEncodingHandler.
+
+ The name argument gives the name of the encoding as specified in
+ the encoding declaration.
+
+ If the callback can provide information about the encoding, it must
+ fill in the XML_Encoding structure, and return XML_STATUS_OK.
+ Otherwise it must return XML_STATUS_ERROR.
+
+ If info does not describe a suitable encoding, then the parser will
+ return an XML_UNKNOWN_ENCODING error.
+*/
+typedef int (XMLCALL *XML_UnknownEncodingHandler) (
+ void *encodingHandlerData,
+ const XML_Char *name,
+ XML_Encoding *info);
+
+XMLPARSEAPI(void)
+XML_SetElementHandler(XML_Parser parser,
+ XML_StartElementHandler start,
+ XML_EndElementHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartElementHandler(XML_Parser parser,
+ XML_StartElementHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetEndElementHandler(XML_Parser parser,
+ XML_EndElementHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetCharacterDataHandler(XML_Parser parser,
+ XML_CharacterDataHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetProcessingInstructionHandler(XML_Parser parser,
+ XML_ProcessingInstructionHandler handler);
+XMLPARSEAPI(void)
+XML_SetCommentHandler(XML_Parser parser,
+ XML_CommentHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start,
+ XML_EndCdataSectionHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start);
+
+XMLPARSEAPI(void)
+XML_SetEndCdataSectionHandler(XML_Parser parser,
+ XML_EndCdataSectionHandler end);
+
+/* This sets the default handler and also inhibits expansion of
+ internal entities. These entity references will be passed to the
+ default handler, or to the skipped entity handler, if one is set.
+*/
+XMLPARSEAPI(void)
+XML_SetDefaultHandler(XML_Parser parser,
+ XML_DefaultHandler handler);
+
+/* This sets the default handler but does not inhibit expansion of
+ internal entities. The entity reference will not be passed to the
+ default handler.
+*/
+XMLPARSEAPI(void)
+XML_SetDefaultHandlerExpand(XML_Parser parser,
+ XML_DefaultHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetDoctypeDeclHandler(XML_Parser parser,
+ XML_StartDoctypeDeclHandler start,
+ XML_EndDoctypeDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartDoctypeDeclHandler(XML_Parser parser,
+ XML_StartDoctypeDeclHandler start);
+
+XMLPARSEAPI(void)
+XML_SetEndDoctypeDeclHandler(XML_Parser parser,
+ XML_EndDoctypeDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
+ XML_UnparsedEntityDeclHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetNotationDeclHandler(XML_Parser parser,
+ XML_NotationDeclHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start,
+ XML_EndNamespaceDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start);
+
+XMLPARSEAPI(void)
+XML_SetEndNamespaceDeclHandler(XML_Parser parser,
+ XML_EndNamespaceDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetNotStandaloneHandler(XML_Parser parser,
+ XML_NotStandaloneHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetExternalEntityRefHandler(XML_Parser parser,
+ XML_ExternalEntityRefHandler handler);
+
+/* If a non-NULL value for arg is specified here, then it will be
+ passed as the first argument to the external entity ref handler
+ instead of the parser object.
+*/
+XMLPARSEAPI(void)
+XML_SetExternalEntityRefHandlerArg(XML_Parser parser,
+ void *arg);
+
+XMLPARSEAPI(void)
+XML_SetSkippedEntityHandler(XML_Parser parser,
+ XML_SkippedEntityHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetUnknownEncodingHandler(XML_Parser parser,
+ XML_UnknownEncodingHandler handler,
+ void *encodingHandlerData);
+
+/* This can be called within a handler for a start element, end
+ element, processing instruction or character data. It causes the
+ corresponding markup to be passed to the default handler.
+*/
+XMLPARSEAPI(void)
+XML_DefaultCurrent(XML_Parser parser);
+
+/* If do_nst is non-zero, and namespace processing is in effect, and
+ a name has a prefix (i.e. an explicit namespace qualifier) then
+ that name is returned as a triplet in a single string separated by
+ the separator character specified when the parser was created: URI
+ + sep + local_name + sep + prefix.
+
+ If do_nst is zero, then namespace information is returned in the
+ default manner (URI + sep + local_name) whether or not the name
+ has a prefix.
+
+ Note: Calling XML_SetReturnNSTriplet after XML_Parse or
+ XML_ParseBuffer has no effect.
+*/
+
+XMLPARSEAPI(void)
+XML_SetReturnNSTriplet(XML_Parser parser, int do_nst);
+
+/* This value is passed as the userData argument to callbacks. */
+XMLPARSEAPI(void)
+XML_SetUserData(XML_Parser parser, void *userData);
+
+/* Returns the last value set by XML_SetUserData or NULL. */
+#define XML_GetUserData(parser) (*(void **)(parser))
+
+/* This is equivalent to supplying an encoding argument to
+ XML_ParserCreate. On success XML_SetEncoding returns non-zero,
+ zero otherwise.
+ Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer
+ has no effect and returns XML_STATUS_ERROR.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_SetEncoding(XML_Parser parser, const XML_Char *encoding);
+
+/* If this function is called, then the parser will be passed as the
+ first argument to callbacks instead of userData. The userData will
+ still be accessible using XML_GetUserData.
+*/
+XMLPARSEAPI(void)
+XML_UseParserAsHandlerArg(XML_Parser parser);
+
+/* If useDTD == XML_TRUE is passed to this function, then the parser
+ will assume that there is an external subset, even if none is
+ specified in the document. In such a case the parser will call the
+ externalEntityRefHandler with a value of NULL for the systemId
+ argument (the publicId and context arguments will be NULL as well).
+ Note: For the purpose of checking WFC: Entity Declared, passing
+ useDTD == XML_TRUE will make the parser behave as if the document
+ had a DTD with an external subset.
+ Note: If this function is called, then this must be done before
+ the first call to XML_Parse or XML_ParseBuffer, since it will
+ have no effect after that. Returns
+ XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING.
+ Note: If the document does not have a DOCTYPE declaration at all,
+ then startDoctypeDeclHandler and endDoctypeDeclHandler will not
+ be called, despite an external subset being parsed.
+ Note: If XML_DTD is not defined when Expat is compiled, returns
+ XML_ERROR_FEATURE_REQUIRES_XML_DTD.
+*/
+XMLPARSEAPI(enum XML_Error)
+XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD);
+
+
+/* Sets the base to be used for resolving relative URIs in system
+ identifiers in declarations. Resolving relative identifiers is
+ left to the application: this value will be passed through as the
+ base argument to the XML_ExternalEntityRefHandler,
+ XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base
+ argument will be copied. Returns XML_STATUS_ERROR if out of memory,
+ XML_STATUS_OK otherwise.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_SetBase(XML_Parser parser, const XML_Char *base);
+
+XMLPARSEAPI(const XML_Char *)
+XML_GetBase(XML_Parser parser);
+
+/* Returns the number of the attribute/value pairs passed in last call
+ to the XML_StartElementHandler that were specified in the start-tag
+ rather than defaulted. Each attribute/value pair counts as 2; thus
+ this correspondds to an index into the atts array passed to the
+ XML_StartElementHandler.
+*/
+XMLPARSEAPI(int)
+XML_GetSpecifiedAttributeCount(XML_Parser parser);
+
+/* Returns the index of the ID attribute passed in the last call to
+ XML_StartElementHandler, or -1 if there is no ID attribute. Each
+ attribute/value pair counts as 2; thus this correspondds to an
+ index into the atts array passed to the XML_StartElementHandler.
+*/
+XMLPARSEAPI(int)
+XML_GetIdAttributeIndex(XML_Parser parser);
+
+/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is
+ detected. The last call to XML_Parse must have isFinal true; len
+ may be zero for this call (or any other).
+
+ Though the return values for these functions has always been
+ described as a Boolean value, the implementation, at least for the
+ 1.95.x series, has always returned exactly one of the XML_Status
+ values.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_Parse(XML_Parser parser, const char *s, int len, int isFinal);
+
+XMLPARSEAPI(void *)
+XML_GetBuffer(XML_Parser parser, int len);
+
+XMLPARSEAPI(enum XML_Status)
+XML_ParseBuffer(XML_Parser parser, int len, int isFinal);
+
+/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return.
+ Must be called from within a call-back handler, except when aborting
+ (resumable = 0) an already suspended parser. Some call-backs may
+ still follow because they would otherwise get lost. Examples:
+ - endElementHandler() for empty elements when stopped in
+ startElementHandler(),
+ - endNameSpaceDeclHandler() when stopped in endElementHandler(),
+ and possibly others.
+
+ Can be called from most handlers, including DTD related call-backs,
+ except when parsing an external parameter entity and resumable != 0.
+ Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise.
+ Possible error codes:
+ - XML_ERROR_SUSPENDED: when suspending an already suspended parser.
+ - XML_ERROR_FINISHED: when the parser has already finished.
+ - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE.
+
+ When resumable != 0 (true) then parsing is suspended, that is,
+ XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED.
+ Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer()
+ return XML_STATUS_ERROR with error code XML_ERROR_ABORTED.
+
+ *Note*:
+ This will be applied to the current parser instance only, that is, if
+ there is a parent parser then it will continue parsing when the
+ externalEntityRefHandler() returns. It is up to the implementation of
+ the externalEntityRefHandler() to call XML_StopParser() on the parent
+ parser (recursively), if one wants to stop parsing altogether.
+
+ When suspended, parsing can be resumed by calling XML_ResumeParser().
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_StopParser(XML_Parser parser, XML_Bool resumable);
+
+/* Resumes parsing after it has been suspended with XML_StopParser().
+ Must not be called from within a handler call-back. Returns same
+ status codes as XML_Parse() or XML_ParseBuffer().
+ Additional error code XML_ERROR_NOT_SUSPENDED possible.
+
+ *Note*:
+ This must be called on the most deeply nested child parser instance
+ first, and on its parent parser only after the child parser has finished,
+ to be applied recursively until the document entity's parser is restarted.
+ That is, the parent parser will not resume by itself and it is up to the
+ application to call XML_ResumeParser() on it at the appropriate moment.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_ResumeParser(XML_Parser parser);
+
+enum XML_Parsing {
+ XML_INITIALIZED,
+ XML_PARSING,
+ XML_FINISHED,
+ XML_SUSPENDED
+};
+
+typedef struct {
+ enum XML_Parsing parsing;
+ XML_Bool finalBuffer;
+} XML_ParsingStatus;
+
+/* Returns status of parser with respect to being initialized, parsing,
+ finished, or suspended and processing the final buffer.
+ XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus,
+ XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED
+*/
+XMLPARSEAPI(void)
+XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status);
+
+/* Creates an XML_Parser object that can parse an external general
+ entity; context is a '\0'-terminated string specifying the parse
+ context; encoding is a '\0'-terminated string giving the name of
+ the externally specified encoding, or NULL if there is no
+ externally specified encoding. The context string consists of a
+ sequence of tokens separated by formfeeds (\f); a token consisting
+ of a name specifies that the general entity of the name is open; a
+ token of the form prefix=uri specifies the namespace for a
+ particular prefix; a token of the form =uri specifies the default
+ namespace. This can be called at any point after the first call to
+ an ExternalEntityRefHandler so longer as the parser has not yet
+ been freed. The new parser is completely independent and may
+ safely be used in a separate thread. The handlers and userData are
+ initialized from the parser argument. Returns NULL if out of memory.
+ Otherwise returns a new XML_Parser object.
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ExternalEntityParserCreate(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *encoding);
+
+enum XML_ParamEntityParsing {
+ XML_PARAM_ENTITY_PARSING_NEVER,
+ XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE,
+ XML_PARAM_ENTITY_PARSING_ALWAYS
+};
+
+/* Controls parsing of parameter entities (including the external DTD
+ subset). If parsing of parameter entities is enabled, then
+ references to external parameter entities (including the external
+ DTD subset) will be passed to the handler set with
+ XML_SetExternalEntityRefHandler. The context passed will be 0.
+
+ Unlike external general entities, external parameter entities can
+ only be parsed synchronously. If the external parameter entity is
+ to be parsed, it must be parsed during the call to the external
+ entity ref handler: the complete sequence of
+ XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and
+ XML_ParserFree calls must be made during this call. After
+ XML_ExternalEntityParserCreate has been called to create the parser
+ for the external parameter entity (context must be 0 for this
+ call), it is illegal to make any calls on the old parser until
+ XML_ParserFree has been called on the newly created parser.
+ If the library has been compiled without support for parameter
+ entity parsing (ie without XML_DTD being defined), then
+ XML_SetParamEntityParsing will return 0 if parsing of parameter
+ entities is requested; otherwise it will return non-zero.
+ Note: If XML_SetParamEntityParsing is called after XML_Parse or
+ XML_ParseBuffer, then it has no effect and will always return 0.
+*/
+XMLPARSEAPI(int)
+XML_SetParamEntityParsing(XML_Parser parser,
+ enum XML_ParamEntityParsing parsing);
+
+/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
+ XML_GetErrorCode returns information about the error.
+*/
+XMLPARSEAPI(enum XML_Error)
+XML_GetErrorCode(XML_Parser parser);
+
+/* These functions return information about the current parse
+ location. They may be called from any callback called to report
+ some parse event; in this case the location is the location of the
+ first of the sequence of characters that generated the event. When
+ called from callbacks generated by declarations in the document
+ prologue, the location identified isn't as neatly defined, but will
+ be within the relevant markup. When called outside of the callback
+ functions, the position indicated will be just past the last parse
+ event (regardless of whether there was an associated callback).
+
+ They may also be called after returning from a call to XML_Parse
+ or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then
+ the location is the location of the character at which the error
+ was detected; otherwise the location is the location of the last
+ parse event, as described above.
+*/
+XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser);
+XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser);
+XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser);
+
+/* Return the number of bytes in the current event.
+ Returns 0 if the event is in an internal entity.
+*/
+XMLPARSEAPI(int)
+XML_GetCurrentByteCount(XML_Parser parser);
+
+/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets
+ the integer pointed to by offset to the offset within this buffer
+ of the current parse position, and sets the integer pointed to by size
+ to the size of this buffer (the number of input bytes). Otherwise
+ returns a NULL pointer. Also returns a NULL pointer if a parse isn't
+ active.
+
+ NOTE: The character pointer returned should not be used outside
+ the handler that makes the call.
+*/
+XMLPARSEAPI(const char *)
+XML_GetInputContext(XML_Parser parser,
+ int *offset,
+ int *size);
+
+/* For backwards compatibility with previous versions. */
+#define XML_GetErrorLineNumber XML_GetCurrentLineNumber
+#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber
+#define XML_GetErrorByteIndex XML_GetCurrentByteIndex
+
+/* Frees the content model passed to the element declaration handler */
+XMLPARSEAPI(void)
+XML_FreeContentModel(XML_Parser parser, XML_Content *model);
+
+/* Exposing the memory handling functions used in Expat */
+XMLPARSEAPI(void *)
+XML_MemMalloc(XML_Parser parser, size_t size);
+
+XMLPARSEAPI(void *)
+XML_MemRealloc(XML_Parser parser, void *ptr, size_t size);
+
+XMLPARSEAPI(void)
+XML_MemFree(XML_Parser parser, void *ptr);
+
+/* Frees memory used by the parser. */
+XMLPARSEAPI(void)
+XML_ParserFree(XML_Parser parser);
+
+/* Returns a string describing the error. */
+XMLPARSEAPI(const XML_LChar *)
+XML_ErrorString(enum XML_Error code);
+
+/* Return a string containing the version number of this expat */
+XMLPARSEAPI(const XML_LChar *)
+XML_ExpatVersion(void);
+
+typedef struct {
+ int major;
+ int minor;
+ int micro;
+} XML_Expat_Version;
+
+/* Return an XML_Expat_Version structure containing numeric version
+ number information for this version of expat.
+*/
+XMLPARSEAPI(XML_Expat_Version)
+XML_ExpatVersionInfo(void);
+
+/* Added in Expat 1.95.5. */
+enum XML_FeatureEnum {
+ XML_FEATURE_END = 0,
+ XML_FEATURE_UNICODE,
+ XML_FEATURE_UNICODE_WCHAR_T,
+ XML_FEATURE_DTD,
+ XML_FEATURE_CONTEXT_BYTES,
+ XML_FEATURE_MIN_SIZE,
+ XML_FEATURE_SIZEOF_XML_CHAR,
+ XML_FEATURE_SIZEOF_XML_LCHAR,
+ XML_FEATURE_NS
+ /* Additional features must be added to the end of this enum. */
+};
+
+typedef struct {
+ enum XML_FeatureEnum feature;
+ const XML_LChar *name;
+ long int value;
+} XML_Feature;
+
+XMLPARSEAPI(const XML_Feature *)
+XML_GetFeatureList(void);
+
+
+/* Expat follows the GNU/Linux convention of odd number minor version for
+ beta/development releases and even number minor version for stable
+ releases. Micro is bumped with each release, and set to 0 with each
+ change to major or minor version.
+*/
+#define XML_MAJOR_VERSION 2
+#define XML_MINOR_VERSION 0
+#define XML_MICRO_VERSION 0
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not Expat_INCLUDED */
diff --git a/src/lib/expat/expat_external.h b/src/lib/expat/expat_external.h
new file mode 100644
index 00000000000..99c5b922cbf
--- /dev/null
+++ b/src/lib/expat/expat_external.h
@@ -0,0 +1,115 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef Expat_External_INCLUDED
+#define Expat_External_INCLUDED 1
+
+/* External API definitions */
+
+#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
+#define XML_USE_MSC_EXTENSIONS 1
+#endif
+
+/* Expat tries very hard to make the API boundary very specifically
+ defined. There are two macros defined to control this boundary;
+ each of these can be defined before including this header to
+ achieve some different behavior, but doing so it not recommended or
+ tested frequently.
+
+ XMLCALL - The calling convention to use for all calls across the
+ "library boundary." This will default to cdecl, and
+ try really hard to tell the compiler that's what we
+ want.
+
+ XMLIMPORT - Whatever magic is needed to note that a function is
+ to be imported from a dynamically loaded library
+ (.dll, .so, or .sl, depending on your platform).
+
+ The XMLCALL macro was added in Expat 1.95.7. The only one which is
+ expected to be directly useful in client code is XMLCALL.
+
+ Note that on at least some Unix versions, the Expat library must be
+ compiled with the cdecl calling convention as the default since
+ system headers may assume the cdecl convention.
+*/
+#ifndef XMLCALL
+#if defined(XML_USE_MSC_EXTENSIONS)
+#define XMLCALL __cdecl
+#elif defined(__GNUC__) && defined(__i386)
+#define XMLCALL __attribute__((cdecl))
+#else
+/* For any platform which uses this definition and supports more than
+ one calling convention, we need to extend this definition to
+ declare the convention used on that platform, if it's possible to
+ do so.
+
+ If this is the case for your platform, please file a bug report
+ with information on how to identify your platform via the C
+ pre-processor and how to specify the same calling convention as the
+ platform's malloc() implementation.
+*/
+#define XMLCALL
+#endif
+#endif /* not defined XMLCALL */
+
+
+#if !defined(XML_STATIC) && !defined(XMLIMPORT)
+#ifndef XML_BUILDING_EXPAT
+/* using Expat from an application */
+
+#ifdef XML_USE_MSC_EXTENSIONS
+#define XMLIMPORT __declspec(dllimport)
+#endif
+
+#endif
+#endif /* not defined XML_STATIC */
+
+
+/* If we didn't define it above, define it away: */
+#ifndef XMLIMPORT
+#define XMLIMPORT
+#endif
+
+
+#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef XML_UNICODE_WCHAR_T
+#define XML_UNICODE
+#endif
+
+#ifdef XML_UNICODE /* Information is UTF-16 encoded. */
+#ifdef XML_UNICODE_WCHAR_T
+typedef wchar_t XML_Char;
+typedef wchar_t XML_LChar;
+#else
+typedef unsigned short XML_Char;
+typedef char XML_LChar;
+#endif /* XML_UNICODE_WCHAR_T */
+#else /* Information is UTF-8 encoded. */
+typedef char XML_Char;
+typedef char XML_LChar;
+#endif /* XML_UNICODE */
+
+#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
+#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
+typedef __int64 XML_Index;
+typedef unsigned __int64 XML_Size;
+#else
+typedef long long XML_Index;
+typedef unsigned long long XML_Size;
+#endif
+#else
+typedef long XML_Index;
+typedef unsigned long XML_Size;
+#endif /* XML_LARGE_SIZE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not Expat_External_INCLUDED */
diff --git a/src/lib/expat/iasciitab.h b/src/lib/expat/iasciitab.h
new file mode 100644
index 00000000000..24a1d5ccc9a
--- /dev/null
+++ b/src/lib/expat/iasciitab.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
+/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
+/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML,
+/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
+/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
+/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
+/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
+/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
+/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
+/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
+/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
+/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/src/lib/expat/intconfig.h b/src/lib/expat/intconfig.h
new file mode 100644
index 00000000000..88092e6a006
--- /dev/null
+++ b/src/lib/expat/intconfig.h
@@ -0,0 +1,19 @@
+#ifndef INTCONFIG_H
+#define INTCONFIG_H
+
+#include <stdlib.h>
+#include <string.h>
+
+#define XML_NS 1
+#define XML_DTD 1
+#define XML_CONTEXT_BYTES 1024
+
+#ifdef USE_LSB
+#define BYTEORDER 1234
+#else
+#define BYTEORDER 4321
+#endif
+
+#define HAVE_MEMMOVE
+
+#endif
diff --git a/src/lib/expat/internal.h b/src/lib/expat/internal.h
new file mode 100644
index 00000000000..ff056c659cd
--- /dev/null
+++ b/src/lib/expat/internal.h
@@ -0,0 +1,73 @@
+/* internal.h
+
+ Internal definitions used by Expat. This is not needed to compile
+ client code.
+
+ The following calling convention macros are defined for frequently
+ called functions:
+
+ FASTCALL - Used for those internal functions that have a simple
+ body and a low number of arguments and local variables.
+
+ PTRCALL - Used for functions called though function pointers.
+
+ PTRFASTCALL - Like PTRCALL, but for low number of arguments.
+
+ inline - Used for selected internal functions for which inlining
+ may improve performance on some platforms.
+
+ Note: Use of these macros is based on judgement, not hard rules,
+ and therefore subject to change.
+*/
+
+#if defined(__GNUC__) && defined(__i386__)
+/* We'll use this version by default only where we know it helps.
+
+ regparm() generates warnings on Solaris boxes. See SF bug #692878.
+
+ Instability reported with egcs on a RedHat Linux 7.3.
+ Let's comment out:
+ #define FASTCALL __attribute__((stdcall, regparm(3)))
+ and let's try this:
+*/
+#define FASTCALL __attribute__((regparm(3)))
+#define PTRFASTCALL __attribute__((regparm(3)))
+#endif
+
+/* Using __fastcall seems to have an unexpected negative effect under
+ MS VC++, especially for function pointers, so we won't use it for
+ now on that platform. It may be reconsidered for a future release
+ if it can be made more effective.
+ Likely reason: __fastcall on Windows is like stdcall, therefore
+ the compiler cannot perform stack optimizations for call clusters.
+*/
+
+/* Make sure all of these are defined if they aren't already. */
+
+#ifndef FASTCALL
+#define FASTCALL
+#endif
+
+#ifndef PTRCALL
+#define PTRCALL
+#endif
+
+#ifndef PTRFASTCALL
+#define PTRFASTCALL
+#endif
+
+#ifndef XML_MIN_SIZE
+#if !defined(__cplusplus) && !defined(inline)
+#ifdef __GNUC__
+#define inline __inline
+#endif /* __GNUC__ */
+#endif
+#endif /* XML_MIN_SIZE */
+
+#ifdef __cplusplus
+#define inline inline
+#else
+#ifndef inline
+#define inline
+#endif
+#endif
diff --git a/src/lib/expat/latin1tab.h b/src/lib/expat/latin1tab.h
new file mode 100644
index 00000000000..53c25d76b26
--- /dev/null
+++ b/src/lib/expat/latin1tab.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
+/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME,
+/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
+/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
diff --git a/src/lib/expat/nametab.h b/src/lib/expat/nametab.h
new file mode 100644
index 00000000000..b05e62c77a6
--- /dev/null
+++ b/src/lib/expat/nametab.h
@@ -0,0 +1,150 @@
+static const unsigned namingBitmap[] = {
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0x00000000, 0x04000000, 0x87FFFFFE, 0x07FFFFFE,
+0x00000000, 0x00000000, 0xFF7FFFFF, 0xFF7FFFFF,
+0xFFFFFFFF, 0x7FF3FFFF, 0xFFFFFDFE, 0x7FFFFFFF,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFE00F, 0xFC31FFFF,
+0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
+0xFFFFFFFF, 0xF80001FF, 0x00000003, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFD740, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
+0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
+0xFFFF0003, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
+0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
+0x0000007F, 0x00000000, 0xFFFF0000, 0x000707FF,
+0x00000000, 0x07FFFFFE, 0x000007FE, 0xFFFE0000,
+0xFFFFFFFF, 0x7CFFFFFF, 0x002F7FFF, 0x00000060,
+0xFFFFFFE0, 0x23FFFFFF, 0xFF000000, 0x00000003,
+0xFFF99FE0, 0x03C5FDFF, 0xB0000000, 0x00030003,
+0xFFF987E0, 0x036DFDFF, 0x5E000000, 0x001C0000,
+0xFFFBAFE0, 0x23EDFDFF, 0x00000000, 0x00000001,
+0xFFF99FE0, 0x23CDFDFF, 0xB0000000, 0x00000003,
+0xD63DC7E0, 0x03BFC718, 0x00000000, 0x00000000,
+0xFFFDDFE0, 0x03EFFDFF, 0x00000000, 0x00000003,
+0xFFFDDFE0, 0x03EFFDFF, 0x40000000, 0x00000003,
+0xFFFDDFE0, 0x03FFFDFF, 0x00000000, 0x00000003,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFE, 0x000D7FFF, 0x0000003F, 0x00000000,
+0xFEF02596, 0x200D6CAE, 0x0000001F, 0x00000000,
+0x00000000, 0x00000000, 0xFFFFFEFF, 0x000003FF,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0xFFFFFFFF, 0xFFFF003F, 0x007FFFFF,
+0x0007DAED, 0x50000000, 0x82315001, 0x002C62AB,
+0x40000000, 0xF580C900, 0x00000007, 0x02010800,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0x0FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x03FFFFFF,
+0x3F3FFFFF, 0xFFFFFFFF, 0xAAFF3F3F, 0x3FFFFFFF,
+0xFFFFFFFF, 0x5FDFFFFF, 0x0FCF1FDC, 0x1FDC1FFF,
+0x00000000, 0x00004C40, 0x00000000, 0x00000000,
+0x00000007, 0x00000000, 0x00000000, 0x00000000,
+0x00000080, 0x000003FE, 0xFFFFFFFE, 0xFFFFFFFF,
+0x001FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x07FFFFFF,
+0xFFFFFFE0, 0x00001FFF, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0xFFFFFFFF, 0x0000003F, 0x00000000, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+0xFFFFFFFF, 0x0000000F, 0x00000000, 0x00000000,
+0x00000000, 0x07FF6000, 0x87FFFFFE, 0x07FFFFFE,
+0x00000000, 0x00800000, 0xFF7FFFFF, 0xFF7FFFFF,
+0x00FFFFFF, 0x00000000, 0xFFFF0000, 0xFFFFFFFF,
+0xFFFFFFFF, 0xF80001FF, 0x00030003, 0x00000000,
+0xFFFFFFFF, 0xFFFFFFFF, 0x0000003F, 0x00000003,
+0xFFFFD7C0, 0xFFFFFFFB, 0x547F7FFF, 0x000FFFFD,
+0xFFFFDFFE, 0xFFFFFFFF, 0xDFFEFFFF, 0xFFFFFFFF,
+0xFFFF007B, 0xFFFFFFFF, 0xFFFF199F, 0x033FCFFF,
+0x00000000, 0xFFFE0000, 0x027FFFFF, 0xFFFFFFFE,
+0xFFFE007F, 0xBBFFFFFB, 0xFFFF0016, 0x000707FF,
+0x00000000, 0x07FFFFFE, 0x0007FFFF, 0xFFFF03FF,
+0xFFFFFFFF, 0x7CFFFFFF, 0xFFEF7FFF, 0x03FF3DFF,
+0xFFFFFFEE, 0xF3FFFFFF, 0xFF1E3FFF, 0x0000FFCF,
+0xFFF99FEE, 0xD3C5FDFF, 0xB080399F, 0x0003FFCF,
+0xFFF987E4, 0xD36DFDFF, 0x5E003987, 0x001FFFC0,
+0xFFFBAFEE, 0xF3EDFDFF, 0x00003BBF, 0x0000FFC1,
+0xFFF99FEE, 0xF3CDFDFF, 0xB0C0398F, 0x0000FFC3,
+0xD63DC7EC, 0xC3BFC718, 0x00803DC7, 0x0000FF80,
+0xFFFDDFEE, 0xC3EFFDFF, 0x00603DDF, 0x0000FFC3,
+0xFFFDDFEC, 0xC3EFFDFF, 0x40603DDF, 0x0000FFC3,
+0xFFFDDFEC, 0xC3FFFDFF, 0x00803DCF, 0x0000FFC3,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0xFFFFFFFE, 0x07FF7FFF, 0x03FF7FFF, 0x00000000,
+0xFEF02596, 0x3BFF6CAE, 0x03FF3F5F, 0x00000000,
+0x03000000, 0xC2A003FF, 0xFFFFFEFF, 0xFFFE03FF,
+0xFEBF0FDF, 0x02FE3FFF, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x00000000, 0x00000000,
+0x00000000, 0x00000000, 0x1FFF0000, 0x00000002,
+0x000000A0, 0x003EFFFE, 0xFFFFFFFE, 0xFFFFFFFF,
+0x661FFFFF, 0xFFFFFFFE, 0xFFFFFFFF, 0x77FFFFFF,
+};
+static const unsigned char nmstrtPages[] = {
+0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x00,
+0x00, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
+0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x15, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+static const unsigned char namePages[] = {
+0x19, 0x03, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x00,
+0x00, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
+0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x13,
+0x26, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x27, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x18,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
diff --git a/src/lib/expat/utf8tab.h b/src/lib/expat/utf8tab.h
new file mode 100644
index 00000000000..7bb3e77603f
--- /dev/null
+++ b/src/lib/expat/utf8tab.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+
+/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4,
+/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM,
diff --git a/src/lib/expat/xmlparse.c b/src/lib/expat/xmlparse.c
new file mode 100644
index 00000000000..ed9344ca8ff
--- /dev/null
+++ b/src/lib/expat/xmlparse.c
@@ -0,0 +1,6258 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#include <stddef.h>
+#include <string.h> /* memset(), memcpy() */
+#include <assert.h>
+
+#define XML_BUILDING_EXPAT 1
+
+#include "intconfig.h"
+
+#include "expat.h"
+
+#ifdef XML_UNICODE
+#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
+#define XmlConvert XmlUtf16Convert
+#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
+#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
+#define XmlEncode XmlUtf16Encode
+#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((unsigned long)s) & 1))
+typedef unsigned short ICHAR;
+#else
+#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
+#define XmlConvert XmlUtf8Convert
+#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
+#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
+#define XmlEncode XmlUtf8Encode
+#define MUST_CONVERT(enc, s) (!(enc)->isUtf8)
+typedef char ICHAR;
+#endif
+
+
+#ifndef XML_NS
+
+#define XmlInitEncodingNS XmlInitEncoding
+#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
+#undef XmlGetInternalEncodingNS
+#define XmlGetInternalEncodingNS XmlGetInternalEncoding
+#define XmlParseXmlDeclNS XmlParseXmlDecl
+
+#endif
+
+#ifdef XML_UNICODE
+
+#ifdef XML_UNICODE_WCHAR_T
+#define XML_T(x) (const wchar_t)x
+#define XML_L(x) L ## x
+#else
+#define XML_T(x) (const unsigned short)x
+#define XML_L(x) x
+#endif
+
+#else
+
+#define XML_T(x) x
+#define XML_L(x) x
+
+#endif
+
+/* Round up n to be a multiple of sz, where sz is a power of 2. */
+#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
+
+/* Handle the case where memmove() doesn't exist. */
+#ifndef HAVE_MEMMOVE
+#ifdef HAVE_BCOPY
+#define memmove(d,s,l) bcopy((s),(d),(l))
+#else
+#error memmove does not exist on this platform, nor is a substitute available
+#endif /* HAVE_BCOPY */
+#endif /* HAVE_MEMMOVE */
+
+#include "internal.h"
+#include "xmltok.h"
+#include "xmlrole.h"
+
+typedef const XML_Char *KEY;
+
+typedef struct {
+ KEY name;
+} NAMED;
+
+typedef struct {
+ NAMED **v;
+ unsigned char power;
+ size_t size;
+ size_t used;
+ const XML_Memory_Handling_Suite *mem;
+} HASH_TABLE;
+
+/* Basic character hash algorithm, taken from Python's string hash:
+ h = h * 1000003 ^ character, the constant being a prime number.
+
+*/
+#ifdef XML_UNICODE
+#define CHAR_HASH(h, c) \
+ (((h) * 0xF4243) ^ (unsigned short)(c))
+#else
+#define CHAR_HASH(h, c) \
+ (((h) * 0xF4243) ^ (unsigned char)(c))
+#endif
+
+/* For probing (after a collision) we need a step size relative prime
+ to the hash table size, which is a power of 2. We use double-hashing,
+ since we can calculate a second hash value cheaply by taking those bits
+ of the first hash value that were discarded (masked out) when the table
+ index was calculated: index = hash & mask, where mask = table->size - 1.
+ We limit the maximum step size to table->size / 4 (mask >> 2) and make
+ it odd, since odd numbers are always relative prime to a power of 2.
+*/
+#define SECOND_HASH(hash, mask, power) \
+ ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2))
+#define PROBE_STEP(hash, mask, power) \
+ ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
+
+typedef struct {
+ NAMED **p;
+ NAMED **end;
+} HASH_TABLE_ITER;
+
+#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */
+#define INIT_DATA_BUF_SIZE 1024
+#define INIT_ATTS_SIZE 16
+#define INIT_ATTS_VERSION 0xFFFFFFFF
+#define INIT_BLOCK_SIZE 1024
+#define INIT_BUFFER_SIZE 1024
+
+#define EXPAND_SPARE 24
+
+typedef struct binding {
+ struct prefix *prefix;
+ struct binding *nextTagBinding;
+ struct binding *prevPrefixBinding;
+ const struct attribute_id *attId;
+ XML_Char *uri;
+ int uriLen;
+ int uriAlloc;
+} BINDING;
+
+typedef struct prefix {
+ const XML_Char *name;
+ BINDING *binding;
+} PREFIX;
+
+typedef struct {
+ const XML_Char *str;
+ const XML_Char *localPart;
+ const XML_Char *prefix;
+ int strLen;
+ int uriLen;
+ int prefixLen;
+} TAG_NAME;
+
+/* TAG represents an open element.
+ The name of the element is stored in both the document and API
+ encodings. The memory buffer 'buf' is a separately-allocated
+ memory area which stores the name. During the XML_Parse()/
+ XMLParseBuffer() when the element is open, the memory for the 'raw'
+ version of the name (in the document encoding) is shared with the
+ document buffer. If the element is open across calls to
+ XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to
+ contain the 'raw' name as well.
+
+ A parser re-uses these structures, maintaining a list of allocated
+ TAG objects in a free list.
+*/
+typedef struct tag {
+ struct tag *parent; /* parent of this element */
+ const char *rawName; /* tagName in the original encoding */
+ int rawNameLength;
+ TAG_NAME name; /* tagName in the API encoding */
+ char *buf; /* buffer for name components */
+ char *bufEnd; /* end of the buffer */
+ BINDING *bindings;
+} TAG;
+
+typedef struct {
+ const XML_Char *name;
+ const XML_Char *textPtr;
+ int textLen; /* length in XML_Chars */
+ int processed; /* # of processed bytes - when suspended */
+ const XML_Char *systemId;
+ const XML_Char *base;
+ const XML_Char *publicId;
+ const XML_Char *notation;
+ XML_Bool open;
+ XML_Bool is_param;
+ XML_Bool is_internal; /* true if declared in internal subset outside PE */
+} ENTITY;
+
+typedef struct {
+ enum XML_Content_Type type;
+ enum XML_Content_Quant quant;
+ const XML_Char * name;
+ int firstchild;
+ int lastchild;
+ int childcnt;
+ int nextsib;
+} CONTENT_SCAFFOLD;
+
+#define INIT_SCAFFOLD_ELEMENTS 32
+
+typedef struct block {
+ struct block *next;
+ int size;
+ XML_Char s[1];
+} BLOCK;
+
+typedef struct {
+ BLOCK *blocks;
+ BLOCK *freeBlocks;
+ const XML_Char *end;
+ XML_Char *ptr;
+ XML_Char *start;
+ const XML_Memory_Handling_Suite *mem;
+} STRING_POOL;
+
+/* The XML_Char before the name is used to determine whether
+ an attribute has been specified. */
+typedef struct attribute_id {
+ XML_Char *name;
+ PREFIX *prefix;
+ XML_Bool maybeTokenized;
+ XML_Bool xmlns;
+} ATTRIBUTE_ID;
+
+typedef struct {
+ const ATTRIBUTE_ID *id;
+ XML_Bool isCdata;
+ const XML_Char *value;
+} DEFAULT_ATTRIBUTE;
+
+typedef struct {
+ unsigned long version;
+ unsigned long hash;
+ const XML_Char *uriName;
+} NS_ATT;
+
+typedef struct {
+ const XML_Char *name;
+ PREFIX *prefix;
+ const ATTRIBUTE_ID *idAtt;
+ int nDefaultAtts;
+ int allocDefaultAtts;
+ DEFAULT_ATTRIBUTE *defaultAtts;
+} ELEMENT_TYPE;
+
+typedef struct {
+ HASH_TABLE generalEntities;
+ HASH_TABLE elementTypes;
+ HASH_TABLE attributeIds;
+ HASH_TABLE prefixes;
+ STRING_POOL pool;
+ STRING_POOL entityValuePool;
+ /* false once a parameter entity reference has been skipped */
+ XML_Bool keepProcessing;
+ /* true once an internal or external PE reference has been encountered;
+ this includes the reference to an external subset */
+ XML_Bool hasParamEntityRefs;
+ XML_Bool standalone;
+#ifdef XML_DTD
+ /* indicates if external PE has been read */
+ XML_Bool paramEntityRead;
+ HASH_TABLE paramEntities;
+#endif /* XML_DTD */
+ PREFIX defaultPrefix;
+ /* === scaffolding for building content model === */
+ XML_Bool in_eldecl;
+ CONTENT_SCAFFOLD *scaffold;
+ unsigned contentStringLen;
+ unsigned scaffSize;
+ unsigned scaffCount;
+ int scaffLevel;
+ int *scaffIndex;
+} DTD;
+
+typedef struct open_internal_entity {
+ const char *internalEventPtr;
+ const char *internalEventEndPtr;
+ struct open_internal_entity *next;
+ ENTITY *entity;
+ int startTagLevel;
+ XML_Bool betweenDecl; /* WFC: PE Between Declarations */
+} OPEN_INTERNAL_ENTITY;
+
+typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr);
+
+static Processor prologProcessor;
+static Processor prologInitProcessor;
+static Processor contentProcessor;
+static Processor cdataSectionProcessor;
+#ifdef XML_DTD
+static Processor ignoreSectionProcessor;
+static Processor externalParEntProcessor;
+static Processor externalParEntInitProcessor;
+static Processor entityValueProcessor;
+static Processor entityValueInitProcessor;
+#endif /* XML_DTD */
+static Processor epilogProcessor;
+static Processor errorProcessor;
+static Processor externalEntityInitProcessor;
+static Processor externalEntityInitProcessor2;
+static Processor externalEntityInitProcessor3;
+static Processor externalEntityContentProcessor;
+static Processor internalEntityProcessor;
+
+static enum XML_Error
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);
+static enum XML_Error
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
+ const char *s, const char *next);
+static enum XML_Error
+initializeEncoding(XML_Parser parser);
+static enum XML_Error
+doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
+ const char *end, int tok, const char *next, const char **nextPtr,
+ XML_Bool haveMore);
+static enum XML_Error
+processInternalEntity(XML_Parser parser, ENTITY *entity,
+ XML_Bool betweenDecl);
+static enum XML_Error
+doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+ const char *start, const char *end, const char **endPtr,
+ XML_Bool haveMore);
+static enum XML_Error
+doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr,
+ const char *end, const char **nextPtr, XML_Bool haveMore);
+#ifdef XML_DTD
+static enum XML_Error
+doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr,
+ const char *end, const char **nextPtr, XML_Bool haveMore);
+#endif /* XML_DTD */
+
+static enum XML_Error
+storeAtts(XML_Parser parser, const ENCODING *, const char *s,
+ TAG_NAME *tagNamePtr, BINDING **bindingsPtr);
+static enum XML_Error
+addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
+ const XML_Char *uri, BINDING **bindingsPtr);
+static int
+defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
+ XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser);
+static enum XML_Error
+storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
+ const char *, const char *, STRING_POOL *);
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
+ const char *, const char *, STRING_POOL *);
+static ATTRIBUTE_ID *
+getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end);
+static int
+setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+static enum XML_Error
+storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end);
+static int
+reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end);
+static int
+reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end);
+static void
+reportDefault(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end);
+
+static const XML_Char * getContext(XML_Parser parser);
+static XML_Bool
+setContext(XML_Parser parser, const XML_Char *context);
+
+static void FASTCALL normalizePublicId(XML_Char *s);
+
+static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms);
+/* do not call if parentParser != NULL */
+static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
+static void
+dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
+static int
+dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);
+static int
+copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *);
+
+static NAMED *
+lookup(HASH_TABLE *table, KEY name, size_t createSize);
+static void FASTCALL
+hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms);
+static void FASTCALL hashTableClear(HASH_TABLE *);
+static void FASTCALL hashTableDestroy(HASH_TABLE *);
+static void FASTCALL
+hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
+static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *);
+
+static void FASTCALL
+poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms);
+static void FASTCALL poolClear(STRING_POOL *);
+static void FASTCALL poolDestroy(STRING_POOL *);
+static XML_Char *
+poolAppend(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end);
+static XML_Char *
+poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end);
+static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
+static const XML_Char * FASTCALL
+poolCopyString(STRING_POOL *pool, const XML_Char *s);
+static const XML_Char *
+poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n);
+static const XML_Char * FASTCALL
+poolAppendString(STRING_POOL *pool, const XML_Char *s);
+
+static int FASTCALL nextScaffoldPart(XML_Parser parser);
+static XML_Content * build_model(XML_Parser parser);
+static ELEMENT_TYPE *
+getElementType(XML_Parser parser, const ENCODING *enc,
+ const char *ptr, const char *end);
+
+static XML_Parser
+parserCreate(const XML_Char *encodingName,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *nameSep,
+ DTD *dtd);
+static void
+parserInit(XML_Parser parser, const XML_Char *encodingName);
+
+#define poolStart(pool) ((pool)->start)
+#define poolEnd(pool) ((pool)->ptr)
+#define poolLength(pool) ((pool)->ptr - (pool)->start)
+#define poolChop(pool) ((void)--(pool->ptr))
+#define poolLastChar(pool) (((pool)->ptr)[-1])
+#define poolDiscard(pool) ((pool)->ptr = (pool)->start)
+#define poolFinish(pool) ((pool)->start = (pool)->ptr)
+#define poolAppendChar(pool, c) \
+ (((pool)->ptr == (pool)->end && !poolGrow(pool)) \
+ ? 0 \
+ : ((*((pool)->ptr)++ = c), 1))
+
+struct XML_ParserStruct {
+ /* The first member must be userData so that the XML_GetUserData
+ macro works. */
+ void *m_userData;
+ void *m_handlerArg;
+ char *m_buffer;
+ const XML_Memory_Handling_Suite m_mem;
+ /* first character to be parsed */
+ const char *m_bufferPtr;
+ /* past last character to be parsed */
+ char *m_bufferEnd;
+ /* allocated end of buffer */
+ const char *m_bufferLim;
+ XML_Index m_parseEndByteIndex;
+ const char *m_parseEndPtr;
+ XML_Char *m_dataBuf;
+ XML_Char *m_dataBufEnd;
+ XML_StartElementHandler m_startElementHandler;
+ XML_EndElementHandler m_endElementHandler;
+ XML_CharacterDataHandler m_characterDataHandler;
+ XML_ProcessingInstructionHandler m_processingInstructionHandler;
+ XML_CommentHandler m_commentHandler;
+ XML_StartCdataSectionHandler m_startCdataSectionHandler;
+ XML_EndCdataSectionHandler m_endCdataSectionHandler;
+ XML_DefaultHandler m_defaultHandler;
+ XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler;
+ XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler;
+ XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler;
+ XML_NotationDeclHandler m_notationDeclHandler;
+ XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler;
+ XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler;
+ XML_NotStandaloneHandler m_notStandaloneHandler;
+ XML_ExternalEntityRefHandler m_externalEntityRefHandler;
+ XML_Parser m_externalEntityRefHandlerArg;
+ XML_SkippedEntityHandler m_skippedEntityHandler;
+ XML_UnknownEncodingHandler m_unknownEncodingHandler;
+ XML_ElementDeclHandler m_elementDeclHandler;
+ XML_AttlistDeclHandler m_attlistDeclHandler;
+ XML_EntityDeclHandler m_entityDeclHandler;
+ XML_XmlDeclHandler m_xmlDeclHandler;
+ const ENCODING *m_encoding;
+ INIT_ENCODING m_initEncoding;
+ const ENCODING *m_internalEncoding;
+ const XML_Char *m_protocolEncodingName;
+ XML_Bool m_ns;
+ XML_Bool m_ns_triplets;
+ void *m_unknownEncodingMem;
+ void *m_unknownEncodingData;
+ void *m_unknownEncodingHandlerData;
+ void (XMLCALL *m_unknownEncodingRelease)(void *);
+ PROLOG_STATE m_prologState;
+ Processor *m_processor;
+ enum XML_Error m_errorCode;
+ const char *m_eventPtr;
+ const char *m_eventEndPtr;
+ const char *m_positionPtr;
+ OPEN_INTERNAL_ENTITY *m_openInternalEntities;
+ OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
+ XML_Bool m_defaultExpandInternalEntities;
+ int m_tagLevel;
+ ENTITY *m_declEntity;
+ const XML_Char *m_doctypeName;
+ const XML_Char *m_doctypeSysid;
+ const XML_Char *m_doctypePubid;
+ const XML_Char *m_declAttributeType;
+ const XML_Char *m_declNotationName;
+ const XML_Char *m_declNotationPublicId;
+ ELEMENT_TYPE *m_declElementType;
+ ATTRIBUTE_ID *m_declAttributeId;
+ XML_Bool m_declAttributeIsCdata;
+ XML_Bool m_declAttributeIsId;
+ DTD *m_dtd;
+ const XML_Char *m_curBase;
+ TAG *m_tagStack;
+ TAG *m_freeTagList;
+ BINDING *m_inheritedBindings;
+ BINDING *m_freeBindingList;
+ int m_attsSize;
+ int m_nSpecifiedAtts;
+ int m_idAttIndex;
+ ATTRIBUTE *m_atts;
+ NS_ATT *m_nsAtts;
+ unsigned long m_nsAttsVersion;
+ unsigned char m_nsAttsPower;
+ POSITION m_position;
+ STRING_POOL m_tempPool;
+ STRING_POOL m_temp2Pool;
+ char *m_groupConnector;
+ unsigned int m_groupSize;
+ XML_Char m_namespaceSeparator;
+ XML_Parser m_parentParser;
+ XML_ParsingStatus m_parsingStatus;
+#ifdef XML_DTD
+ XML_Bool m_isParamEntity;
+ XML_Bool m_useForeignDTD;
+ enum XML_ParamEntityParsing m_paramEntityParsing;
+#endif
+};
+
+#define MALLOC(s) (parser->m_mem.malloc_fcn((s)))
+#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s)))
+#define FREE(p) (parser->m_mem.free_fcn((p)))
+
+#define userData (parser->m_userData)
+#define handlerArg (parser->m_handlerArg)
+#define startElementHandler (parser->m_startElementHandler)
+#define endElementHandler (parser->m_endElementHandler)
+#define characterDataHandler (parser->m_characterDataHandler)
+#define processingInstructionHandler \
+ (parser->m_processingInstructionHandler)
+#define commentHandler (parser->m_commentHandler)
+#define startCdataSectionHandler \
+ (parser->m_startCdataSectionHandler)
+#define endCdataSectionHandler (parser->m_endCdataSectionHandler)
+#define defaultHandler (parser->m_defaultHandler)
+#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler)
+#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler)
+#define unparsedEntityDeclHandler \
+ (parser->m_unparsedEntityDeclHandler)
+#define notationDeclHandler (parser->m_notationDeclHandler)
+#define startNamespaceDeclHandler \
+ (parser->m_startNamespaceDeclHandler)
+#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler)
+#define notStandaloneHandler (parser->m_notStandaloneHandler)
+#define externalEntityRefHandler \
+ (parser->m_externalEntityRefHandler)
+#define externalEntityRefHandlerArg \
+ (parser->m_externalEntityRefHandlerArg)
+#define internalEntityRefHandler \
+ (parser->m_internalEntityRefHandler)
+#define skippedEntityHandler (parser->m_skippedEntityHandler)
+#define unknownEncodingHandler (parser->m_unknownEncodingHandler)
+#define elementDeclHandler (parser->m_elementDeclHandler)
+#define attlistDeclHandler (parser->m_attlistDeclHandler)
+#define entityDeclHandler (parser->m_entityDeclHandler)
+#define xmlDeclHandler (parser->m_xmlDeclHandler)
+#define encoding (parser->m_encoding)
+#define initEncoding (parser->m_initEncoding)
+#define internalEncoding (parser->m_internalEncoding)
+#define unknownEncodingMem (parser->m_unknownEncodingMem)
+#define unknownEncodingData (parser->m_unknownEncodingData)
+#define unknownEncodingHandlerData \
+ (parser->m_unknownEncodingHandlerData)
+#define unknownEncodingRelease (parser->m_unknownEncodingRelease)
+#define protocolEncodingName (parser->m_protocolEncodingName)
+#define ns (parser->m_ns)
+#define ns_triplets (parser->m_ns_triplets)
+#define prologState (parser->m_prologState)
+#define processor (parser->m_processor)
+#define errorCode (parser->m_errorCode)
+#define eventPtr (parser->m_eventPtr)
+#define eventEndPtr (parser->m_eventEndPtr)
+#define positionPtr (parser->m_positionPtr)
+#define position (parser->m_position)
+#define openInternalEntities (parser->m_openInternalEntities)
+#define freeInternalEntities (parser->m_freeInternalEntities)
+#define defaultExpandInternalEntities \
+ (parser->m_defaultExpandInternalEntities)
+#define tagLevel (parser->m_tagLevel)
+#define buffer (parser->m_buffer)
+#define bufferPtr (parser->m_bufferPtr)
+#define bufferEnd (parser->m_bufferEnd)
+#define parseEndByteIndex (parser->m_parseEndByteIndex)
+#define parseEndPtr (parser->m_parseEndPtr)
+#define bufferLim (parser->m_bufferLim)
+#define dataBuf (parser->m_dataBuf)
+#define dataBufEnd (parser->m_dataBufEnd)
+#define _dtd (parser->m_dtd)
+#define curBase (parser->m_curBase)
+#define declEntity (parser->m_declEntity)
+#define doctypeName (parser->m_doctypeName)
+#define doctypeSysid (parser->m_doctypeSysid)
+#define doctypePubid (parser->m_doctypePubid)
+#define declAttributeType (parser->m_declAttributeType)
+#define declNotationName (parser->m_declNotationName)
+#define declNotationPublicId (parser->m_declNotationPublicId)
+#define declElementType (parser->m_declElementType)
+#define declAttributeId (parser->m_declAttributeId)
+#define declAttributeIsCdata (parser->m_declAttributeIsCdata)
+#define declAttributeIsId (parser->m_declAttributeIsId)
+#define freeTagList (parser->m_freeTagList)
+#define freeBindingList (parser->m_freeBindingList)
+#define inheritedBindings (parser->m_inheritedBindings)
+#define tagStack (parser->m_tagStack)
+#define atts (parser->m_atts)
+#define attsSize (parser->m_attsSize)
+#define nSpecifiedAtts (parser->m_nSpecifiedAtts)
+#define idAttIndex (parser->m_idAttIndex)
+#define nsAtts (parser->m_nsAtts)
+#define nsAttsVersion (parser->m_nsAttsVersion)
+#define nsAttsPower (parser->m_nsAttsPower)
+#define tempPool (parser->m_tempPool)
+#define temp2Pool (parser->m_temp2Pool)
+#define groupConnector (parser->m_groupConnector)
+#define groupSize (parser->m_groupSize)
+#define namespaceSeparator (parser->m_namespaceSeparator)
+#define parentParser (parser->m_parentParser)
+#define ps_parsing (parser->m_parsingStatus.parsing)
+#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer)
+#ifdef XML_DTD
+#define isParamEntity (parser->m_isParamEntity)
+#define useForeignDTD (parser->m_useForeignDTD)
+#define paramEntityParsing (parser->m_paramEntityParsing)
+#endif /* XML_DTD */
+
+XML_Parser XMLCALL
+XML_ParserCreate(const XML_Char *encodingName)
+{
+ return XML_ParserCreate_MM(encodingName, NULL, NULL);
+}
+
+XML_Parser XMLCALL
+XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep)
+{
+ XML_Char tmp[2];
+ *tmp = nsSep;
+ return XML_ParserCreate_MM(encodingName, NULL, tmp);
+}
+
+static const XML_Char implicitContext[] = {
+ 'x', 'm', 'l', '=', 'h', 't', 't', 'p', ':', '/', '/',
+ 'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/',
+ 'X', 'M', 'L', '/', '1', '9', '9', '8', '/',
+ 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0'
+};
+
+XML_Parser XMLCALL
+XML_ParserCreate_MM(const XML_Char *encodingName,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *nameSep)
+{
+ XML_Parser parser = parserCreate(encodingName, memsuite, nameSep, NULL);
+ if (parser != NULL && ns) {
+ /* implicit context only set for root parser, since child
+ parsers (i.e. external entity parsers) will inherit it
+ */
+ if (!setContext(parser, implicitContext)) {
+ XML_ParserFree(parser);
+ return NULL;
+ }
+ }
+ return parser;
+}
+
+static XML_Parser
+parserCreate(const XML_Char *encodingName,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *nameSep,
+ DTD *dtd)
+{
+ XML_Parser parser;
+
+ if (memsuite) {
+ XML_Memory_Handling_Suite *mtemp;
+ parser = (XML_Parser)
+ memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
+ if (parser != NULL) {
+ mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
+ mtemp->malloc_fcn = memsuite->malloc_fcn;
+ mtemp->realloc_fcn = memsuite->realloc_fcn;
+ mtemp->free_fcn = memsuite->free_fcn;
+ }
+ }
+ else {
+ XML_Memory_Handling_Suite *mtemp;
+ parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct));
+ if (parser != NULL) {
+ mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
+ mtemp->malloc_fcn = malloc;
+ mtemp->realloc_fcn = realloc;
+ mtemp->free_fcn = free;
+ }
+ }
+
+ if (!parser)
+ return parser;
+
+ buffer = NULL;
+ bufferLim = NULL;
+
+ attsSize = INIT_ATTS_SIZE;
+ atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE));
+ if (atts == NULL) {
+ FREE(parser);
+ return NULL;
+ }
+ dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
+ if (dataBuf == NULL) {
+ FREE(atts);
+ FREE(parser);
+ return NULL;
+ }
+ dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
+
+ if (dtd)
+ _dtd = dtd;
+ else {
+ _dtd = dtdCreate(&parser->m_mem);
+ if (_dtd == NULL) {
+ FREE(dataBuf);
+ FREE(atts);
+ FREE(parser);
+ return NULL;
+ }
+ }
+
+ freeBindingList = NULL;
+ freeTagList = NULL;
+ freeInternalEntities = NULL;
+
+ groupSize = 0;
+ groupConnector = NULL;
+
+ unknownEncodingHandler = NULL;
+ unknownEncodingHandlerData = NULL;
+
+ namespaceSeparator = '!';
+ ns = XML_FALSE;
+ ns_triplets = XML_FALSE;
+
+ nsAtts = NULL;
+ nsAttsVersion = 0;
+ nsAttsPower = 0;
+
+ poolInit(&tempPool, &(parser->m_mem));
+ poolInit(&temp2Pool, &(parser->m_mem));
+ parserInit(parser, encodingName);
+
+ if (encodingName && !protocolEncodingName) {
+ XML_ParserFree(parser);
+ return NULL;
+ }
+
+ if (nameSep) {
+ ns = XML_TRUE;
+ internalEncoding = XmlGetInternalEncodingNS();
+ namespaceSeparator = *nameSep;
+ }
+ else {
+ internalEncoding = XmlGetInternalEncoding();
+ }
+
+ return parser;
+}
+
+static void
+parserInit(XML_Parser parser, const XML_Char *encodingName)
+{
+ processor = prologInitProcessor;
+ XmlPrologStateInit(&prologState);
+ protocolEncodingName = (encodingName != NULL
+ ? poolCopyString(&tempPool, encodingName)
+ : NULL);
+ curBase = NULL;
+ XmlInitEncoding(&initEncoding, &encoding, 0);
+ userData = NULL;
+ handlerArg = NULL;
+ startElementHandler = NULL;
+ endElementHandler = NULL;
+ characterDataHandler = NULL;
+ processingInstructionHandler = NULL;
+ commentHandler = NULL;
+ startCdataSectionHandler = NULL;
+ endCdataSectionHandler = NULL;
+ defaultHandler = NULL;
+ startDoctypeDeclHandler = NULL;
+ endDoctypeDeclHandler = NULL;
+ unparsedEntityDeclHandler = NULL;
+ notationDeclHandler = NULL;
+ startNamespaceDeclHandler = NULL;
+ endNamespaceDeclHandler = NULL;
+ notStandaloneHandler = NULL;
+ externalEntityRefHandler = NULL;
+ externalEntityRefHandlerArg = parser;
+ skippedEntityHandler = NULL;
+ elementDeclHandler = NULL;
+ attlistDeclHandler = NULL;
+ entityDeclHandler = NULL;
+ xmlDeclHandler = NULL;
+ bufferPtr = buffer;
+ bufferEnd = buffer;
+ parseEndByteIndex = 0;
+ parseEndPtr = NULL;
+ declElementType = NULL;
+ declAttributeId = NULL;
+ declEntity = NULL;
+ doctypeName = NULL;
+ doctypeSysid = NULL;
+ doctypePubid = NULL;
+ declAttributeType = NULL;
+ declNotationName = NULL;
+ declNotationPublicId = NULL;
+ declAttributeIsCdata = XML_FALSE;
+ declAttributeIsId = XML_FALSE;
+ memset(&position, 0, sizeof(POSITION));
+ errorCode = XML_ERROR_NONE;
+ eventPtr = NULL;
+ eventEndPtr = NULL;
+ positionPtr = NULL;
+ openInternalEntities = NULL;
+ defaultExpandInternalEntities = XML_TRUE;
+ tagLevel = 0;
+ tagStack = NULL;
+ inheritedBindings = NULL;
+ nSpecifiedAtts = 0;
+ unknownEncodingMem = NULL;
+ unknownEncodingRelease = NULL;
+ unknownEncodingData = NULL;
+ parentParser = NULL;
+ ps_parsing = XML_INITIALIZED;
+#ifdef XML_DTD
+ isParamEntity = XML_FALSE;
+ useForeignDTD = XML_FALSE;
+ paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+#endif
+}
+
+/* moves list of bindings to freeBindingList */
+static void FASTCALL
+moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
+{
+ while (bindings) {
+ BINDING *b = bindings;
+ bindings = bindings->nextTagBinding;
+ b->nextTagBinding = freeBindingList;
+ freeBindingList = b;
+ }
+}
+
+XML_Bool XMLCALL
+XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
+{
+ TAG *tStk;
+ OPEN_INTERNAL_ENTITY *openEntityList;
+ if (parentParser)
+ return XML_FALSE;
+ /* move tagStack to freeTagList */
+ tStk = tagStack;
+ while (tStk) {
+ TAG *tag = tStk;
+ tStk = tStk->parent;
+ tag->parent = freeTagList;
+ moveToFreeBindingList(parser, tag->bindings);
+ tag->bindings = NULL;
+ freeTagList = tag;
+ }
+ /* move openInternalEntities to freeInternalEntities */
+ openEntityList = openInternalEntities;
+ while (openEntityList) {
+ OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
+ openEntityList = openEntity->next;
+ openEntity->next = freeInternalEntities;
+ freeInternalEntities = openEntity;
+ }
+ moveToFreeBindingList(parser, inheritedBindings);
+ FREE(unknownEncodingMem);
+ if (unknownEncodingRelease)
+ unknownEncodingRelease(unknownEncodingData);
+ poolClear(&tempPool);
+ poolClear(&temp2Pool);
+ parserInit(parser, encodingName);
+ dtdReset(_dtd, &parser->m_mem);
+ return setContext(parser, implicitContext);
+}
+
+enum XML_Status XMLCALL
+XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
+{
+ /* Block after XML_Parse()/XML_ParseBuffer() has been called.
+ XXX There's no way for the caller to determine which of the
+ XXX possible error cases caused the XML_STATUS_ERROR return.
+ */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return XML_STATUS_ERROR;
+ if (encodingName == NULL)
+ protocolEncodingName = NULL;
+ else {
+ protocolEncodingName = poolCopyString(&tempPool, encodingName);
+ if (!protocolEncodingName)
+ return XML_STATUS_ERROR;
+ }
+ return XML_STATUS_OK;
+}
+
+XML_Parser XMLCALL
+XML_ExternalEntityParserCreate(XML_Parser oldParser,
+ const XML_Char *context,
+ const XML_Char *encodingName)
+{
+ XML_Parser parser = oldParser;
+ DTD *newDtd = NULL;
+ DTD *oldDtd = _dtd;
+ XML_StartElementHandler oldStartElementHandler = startElementHandler;
+ XML_EndElementHandler oldEndElementHandler = endElementHandler;
+ XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler;
+ XML_ProcessingInstructionHandler oldProcessingInstructionHandler
+ = processingInstructionHandler;
+ XML_CommentHandler oldCommentHandler = commentHandler;
+ XML_StartCdataSectionHandler oldStartCdataSectionHandler
+ = startCdataSectionHandler;
+ XML_EndCdataSectionHandler oldEndCdataSectionHandler
+ = endCdataSectionHandler;
+ XML_DefaultHandler oldDefaultHandler = defaultHandler;
+ XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler
+ = unparsedEntityDeclHandler;
+ XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler;
+ XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler
+ = startNamespaceDeclHandler;
+ XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler
+ = endNamespaceDeclHandler;
+ XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler;
+ XML_ExternalEntityRefHandler oldExternalEntityRefHandler
+ = externalEntityRefHandler;
+ XML_SkippedEntityHandler oldSkippedEntityHandler = skippedEntityHandler;
+ XML_UnknownEncodingHandler oldUnknownEncodingHandler
+ = unknownEncodingHandler;
+ XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler;
+ XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler;
+ XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler;
+ XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler;
+ ELEMENT_TYPE * oldDeclElementType = declElementType;
+
+ void *oldUserData = userData;
+ void *oldHandlerArg = handlerArg;
+ XML_Bool oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
+ XML_Parser oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
+#ifdef XML_DTD
+ enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing;
+ int oldInEntityValue = prologState.inEntityValue;
+#endif
+ XML_Bool oldns_triplets = ns_triplets;
+
+#ifdef XML_DTD
+ if (!context)
+ newDtd = oldDtd;
+#endif /* XML_DTD */
+
+ /* Note that the magical uses of the pre-processor to make field
+ access look more like C++ require that `parser' be overwritten
+ here. This makes this function more painful to follow than it
+ would be otherwise.
+ */
+ if (ns) {
+ XML_Char tmp[2];
+ *tmp = namespaceSeparator;
+ parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
+ }
+ else {
+ parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
+ }
+
+ if (!parser)
+ return NULL;
+
+ startElementHandler = oldStartElementHandler;
+ endElementHandler = oldEndElementHandler;
+ characterDataHandler = oldCharacterDataHandler;
+ processingInstructionHandler = oldProcessingInstructionHandler;
+ commentHandler = oldCommentHandler;
+ startCdataSectionHandler = oldStartCdataSectionHandler;
+ endCdataSectionHandler = oldEndCdataSectionHandler;
+ defaultHandler = oldDefaultHandler;
+ unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
+ notationDeclHandler = oldNotationDeclHandler;
+ startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
+ endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
+ notStandaloneHandler = oldNotStandaloneHandler;
+ externalEntityRefHandler = oldExternalEntityRefHandler;
+ skippedEntityHandler = oldSkippedEntityHandler;
+ unknownEncodingHandler = oldUnknownEncodingHandler;
+ elementDeclHandler = oldElementDeclHandler;
+ attlistDeclHandler = oldAttlistDeclHandler;
+ entityDeclHandler = oldEntityDeclHandler;
+ xmlDeclHandler = oldXmlDeclHandler;
+ declElementType = oldDeclElementType;
+ userData = oldUserData;
+ if (oldUserData == oldHandlerArg)
+ handlerArg = userData;
+ else
+ handlerArg = parser;
+ if (oldExternalEntityRefHandlerArg != oldParser)
+ externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
+ defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
+ ns_triplets = oldns_triplets;
+ parentParser = oldParser;
+#ifdef XML_DTD
+ paramEntityParsing = oldParamEntityParsing;
+ prologState.inEntityValue = oldInEntityValue;
+ if (context) {
+#endif /* XML_DTD */
+ if (!dtdCopy(_dtd, oldDtd, &parser->m_mem)
+ || !setContext(parser, context)) {
+ XML_ParserFree(parser);
+ return NULL;
+ }
+ processor = externalEntityInitProcessor;
+#ifdef XML_DTD
+ }
+ else {
+ /* The DTD instance referenced by _dtd is shared between the document's
+ root parser and external PE parsers, therefore one does not need to
+ call setContext. In addition, one also *must* not call setContext,
+ because this would overwrite existing prefix->binding pointers in
+ _dtd with ones that get destroyed with the external PE parser.
+ This would leave those prefixes with dangling pointers.
+ */
+ isParamEntity = XML_TRUE;
+ XmlPrologStateInitExternalEntity(&prologState);
+ processor = externalParEntInitProcessor;
+ }
+#endif /* XML_DTD */
+ return parser;
+}
+
+static void FASTCALL
+destroyBindings(BINDING *bindings, XML_Parser parser)
+{
+ for (;;) {
+ BINDING *b = bindings;
+ if (!b)
+ break;
+ bindings = b->nextTagBinding;
+ FREE(b->uri);
+ FREE(b);
+ }
+}
+
+void XMLCALL
+XML_ParserFree(XML_Parser parser)
+{
+ TAG *tagList;
+ OPEN_INTERNAL_ENTITY *entityList;
+ if (parser == NULL)
+ return;
+ /* free tagStack and freeTagList */
+ tagList = tagStack;
+ for (;;) {
+ TAG *p;
+ if (tagList == NULL) {
+ if (freeTagList == NULL)
+ break;
+ tagList = freeTagList;
+ freeTagList = NULL;
+ }
+ p = tagList;
+ tagList = tagList->parent;
+ FREE(p->buf);
+ destroyBindings(p->bindings, parser);
+ FREE(p);
+ }
+ /* free openInternalEntities and freeInternalEntities */
+ entityList = openInternalEntities;
+ for (;;) {
+ OPEN_INTERNAL_ENTITY *openEntity;
+ if (entityList == NULL) {
+ if (freeInternalEntities == NULL)
+ break;
+ entityList = freeInternalEntities;
+ freeInternalEntities = NULL;
+ }
+ openEntity = entityList;
+ entityList = entityList->next;
+ FREE(openEntity);
+ }
+
+ destroyBindings(freeBindingList, parser);
+ destroyBindings(inheritedBindings, parser);
+ poolDestroy(&tempPool);
+ poolDestroy(&temp2Pool);
+#ifdef XML_DTD
+ /* external parameter entity parsers share the DTD structure
+ parser->m_dtd with the root parser, so we must not destroy it
+ */
+ if (!isParamEntity && _dtd)
+#else
+ if (_dtd)
+#endif /* XML_DTD */
+ dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem);
+ FREE((void *)atts);
+ FREE(groupConnector);
+ FREE(buffer);
+ FREE(dataBuf);
+ FREE(nsAtts);
+ FREE(unknownEncodingMem);
+ if (unknownEncodingRelease)
+ unknownEncodingRelease(unknownEncodingData);
+ FREE(parser);
+}
+
+void XMLCALL
+XML_UseParserAsHandlerArg(XML_Parser parser)
+{
+ handlerArg = parser;
+}
+
+enum XML_Error XMLCALL
+XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
+{
+#ifdef XML_DTD
+ /* block after XML_Parse()/XML_ParseBuffer() has been called */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
+ useForeignDTD = useDTD;
+ return XML_ERROR_NONE;
+#else
+ return XML_ERROR_FEATURE_REQUIRES_XML_DTD;
+#endif
+}
+
+void XMLCALL
+XML_SetReturnNSTriplet(XML_Parser parser, int do_nst)
+{
+ /* block after XML_Parse()/XML_ParseBuffer() has been called */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return;
+ ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
+}
+
+void XMLCALL
+XML_SetUserData(XML_Parser parser, void *p)
+{
+ if (handlerArg == userData)
+ handlerArg = userData = p;
+ else
+ userData = p;
+}
+
+enum XML_Status XMLCALL
+XML_SetBase(XML_Parser parser, const XML_Char *p)
+{
+ if (p) {
+ p = poolCopyString(&_dtd->pool, p);
+ if (!p)
+ return XML_STATUS_ERROR;
+ curBase = p;
+ }
+ else
+ curBase = NULL;
+ return XML_STATUS_OK;
+}
+
+const XML_Char * XMLCALL
+XML_GetBase(XML_Parser parser)
+{
+ return curBase;
+}
+
+int XMLCALL
+XML_GetSpecifiedAttributeCount(XML_Parser parser)
+{
+ return nSpecifiedAtts;
+}
+
+int XMLCALL
+XML_GetIdAttributeIndex(XML_Parser parser)
+{
+ return idAttIndex;
+}
+
+void XMLCALL
+XML_SetElementHandler(XML_Parser parser,
+ XML_StartElementHandler start,
+ XML_EndElementHandler end)
+{
+ startElementHandler = start;
+ endElementHandler = end;
+}
+
+void XMLCALL
+XML_SetStartElementHandler(XML_Parser parser,
+ XML_StartElementHandler start) {
+ startElementHandler = start;
+}
+
+void XMLCALL
+XML_SetEndElementHandler(XML_Parser parser,
+ XML_EndElementHandler end) {
+ endElementHandler = end;
+}
+
+void XMLCALL
+XML_SetCharacterDataHandler(XML_Parser parser,
+ XML_CharacterDataHandler handler)
+{
+ characterDataHandler = handler;
+}
+
+void XMLCALL
+XML_SetProcessingInstructionHandler(XML_Parser parser,
+ XML_ProcessingInstructionHandler handler)
+{
+ processingInstructionHandler = handler;
+}
+
+void XMLCALL
+XML_SetCommentHandler(XML_Parser parser,
+ XML_CommentHandler handler)
+{
+ commentHandler = handler;
+}
+
+void XMLCALL
+XML_SetCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start,
+ XML_EndCdataSectionHandler end)
+{
+ startCdataSectionHandler = start;
+ endCdataSectionHandler = end;
+}
+
+void XMLCALL
+XML_SetStartCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start) {
+ startCdataSectionHandler = start;
+}
+
+void XMLCALL
+XML_SetEndCdataSectionHandler(XML_Parser parser,
+ XML_EndCdataSectionHandler end) {
+ endCdataSectionHandler = end;
+}
+
+void XMLCALL
+XML_SetDefaultHandler(XML_Parser parser,
+ XML_DefaultHandler handler)
+{
+ defaultHandler = handler;
+ defaultExpandInternalEntities = XML_FALSE;
+}
+
+void XMLCALL
+XML_SetDefaultHandlerExpand(XML_Parser parser,
+ XML_DefaultHandler handler)
+{
+ defaultHandler = handler;
+ defaultExpandInternalEntities = XML_TRUE;
+}
+
+void XMLCALL
+XML_SetDoctypeDeclHandler(XML_Parser parser,
+ XML_StartDoctypeDeclHandler start,
+ XML_EndDoctypeDeclHandler end)
+{
+ startDoctypeDeclHandler = start;
+ endDoctypeDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetStartDoctypeDeclHandler(XML_Parser parser,
+ XML_StartDoctypeDeclHandler start) {
+ startDoctypeDeclHandler = start;
+}
+
+void XMLCALL
+XML_SetEndDoctypeDeclHandler(XML_Parser parser,
+ XML_EndDoctypeDeclHandler end) {
+ endDoctypeDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
+ XML_UnparsedEntityDeclHandler handler)
+{
+ unparsedEntityDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetNotationDeclHandler(XML_Parser parser,
+ XML_NotationDeclHandler handler)
+{
+ notationDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start,
+ XML_EndNamespaceDeclHandler end)
+{
+ startNamespaceDeclHandler = start;
+ endNamespaceDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetStartNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start) {
+ startNamespaceDeclHandler = start;
+}
+
+void XMLCALL
+XML_SetEndNamespaceDeclHandler(XML_Parser parser,
+ XML_EndNamespaceDeclHandler end) {
+ endNamespaceDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetNotStandaloneHandler(XML_Parser parser,
+ XML_NotStandaloneHandler handler)
+{
+ notStandaloneHandler = handler;
+}
+
+void XMLCALL
+XML_SetExternalEntityRefHandler(XML_Parser parser,
+ XML_ExternalEntityRefHandler handler)
+{
+ externalEntityRefHandler = handler;
+}
+
+void XMLCALL
+XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
+{
+ if (arg)
+ externalEntityRefHandlerArg = (XML_Parser)arg;
+ else
+ externalEntityRefHandlerArg = parser;
+}
+
+void XMLCALL
+XML_SetSkippedEntityHandler(XML_Parser parser,
+ XML_SkippedEntityHandler handler)
+{
+ skippedEntityHandler = handler;
+}
+
+void XMLCALL
+XML_SetUnknownEncodingHandler(XML_Parser parser,
+ XML_UnknownEncodingHandler handler,
+ void *data)
+{
+ unknownEncodingHandler = handler;
+ unknownEncodingHandlerData = data;
+}
+
+void XMLCALL
+XML_SetElementDeclHandler(XML_Parser parser,
+ XML_ElementDeclHandler eldecl)
+{
+ elementDeclHandler = eldecl;
+}
+
+void XMLCALL
+XML_SetAttlistDeclHandler(XML_Parser parser,
+ XML_AttlistDeclHandler attdecl)
+{
+ attlistDeclHandler = attdecl;
+}
+
+void XMLCALL
+XML_SetEntityDeclHandler(XML_Parser parser,
+ XML_EntityDeclHandler handler)
+{
+ entityDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetXmlDeclHandler(XML_Parser parser,
+ XML_XmlDeclHandler handler) {
+ xmlDeclHandler = handler;
+}
+
+int XMLCALL
+XML_SetParamEntityParsing(XML_Parser parser,
+ enum XML_ParamEntityParsing peParsing)
+{
+ /* block after XML_Parse()/XML_ParseBuffer() has been called */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return 0;
+#ifdef XML_DTD
+ paramEntityParsing = peParsing;
+ return 1;
+#else
+ return peParsing == XML_PARAM_ENTITY_PARSING_NEVER;
+#endif
+}
+
+enum XML_Status XMLCALL
+XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
+{
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ errorCode = XML_ERROR_SUSPENDED;
+ return XML_STATUS_ERROR;
+ case XML_FINISHED:
+ errorCode = XML_ERROR_FINISHED;
+ return XML_STATUS_ERROR;
+ default:
+ ps_parsing = XML_PARSING;
+ }
+
+ if (len == 0) {
+ ps_finalBuffer = (XML_Bool)isFinal;
+ if (!isFinal)
+ return XML_STATUS_OK;
+ positionPtr = bufferPtr;
+ parseEndPtr = bufferEnd;
+
+ /* If data are left over from last buffer, and we now know that these
+ data are the final chunk of input, then we have to check them again
+ to detect errors based on that fact.
+ */
+ errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+
+ if (errorCode == XML_ERROR_NONE) {
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+ positionPtr = bufferPtr;
+ return XML_STATUS_SUSPENDED;
+ case XML_INITIALIZED:
+ case XML_PARSING:
+ ps_parsing = XML_FINISHED;
+ /* fall through */
+ default:
+ return XML_STATUS_OK;
+ }
+ }
+ eventEndPtr = eventPtr;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+#ifndef XML_CONTEXT_BYTES
+ else if (bufferPtr == bufferEnd) {
+ const char *end;
+ int nLeftOver;
+ enum XML_Error result;
+ parseEndByteIndex += len;
+ positionPtr = s;
+ ps_finalBuffer = (XML_Bool)isFinal;
+
+ errorCode = processor(parser, s, parseEndPtr = s + len, &end);
+
+ if (errorCode != XML_ERROR_NONE) {
+ eventEndPtr = eventPtr;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ else {
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ result = XML_STATUS_SUSPENDED;
+ break;
+ case XML_INITIALIZED:
+ case XML_PARSING:
+ result = XML_STATUS_OK;
+ if (isFinal) {
+ ps_parsing = XML_FINISHED;
+ return result;
+ }
+ }
+ }
+
+ XmlUpdatePosition(encoding, positionPtr, end, &position);
+ nLeftOver = s + len - end;
+ if (nLeftOver) {
+ if (buffer == NULL || nLeftOver > bufferLim - buffer) {
+ /* FIXME avoid integer overflow */
+ char *temp;
+ temp = (buffer == NULL
+ ? (char *)MALLOC(len * 2)
+ : (char *)REALLOC(buffer, len * 2));
+ if (temp == NULL) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return XML_STATUS_ERROR;
+ }
+ buffer = temp;
+ if (!buffer) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ eventPtr = eventEndPtr = NULL;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ bufferLim = buffer + len * 2;
+ }
+ memcpy(buffer, end, nLeftOver);
+ }
+ bufferPtr = buffer;
+ bufferEnd = buffer + nLeftOver;
+ positionPtr = bufferPtr;
+ parseEndPtr = bufferEnd;
+ eventPtr = bufferPtr;
+ eventEndPtr = bufferPtr;
+ return result;
+ }
+#endif /* not defined XML_CONTEXT_BYTES */
+ else {
+ void *buff = XML_GetBuffer(parser, len);
+ if (buff == NULL)
+ return XML_STATUS_ERROR;
+ else {
+ memcpy(buff, s, len);
+ return XML_ParseBuffer(parser, len, isFinal);
+ }
+ }
+}
+
+enum XML_Status XMLCALL
+XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
+{
+ const char *start;
+ enum XML_Status result = XML_STATUS_OK;
+
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ errorCode = XML_ERROR_SUSPENDED;
+ return XML_STATUS_ERROR;
+ case XML_FINISHED:
+ errorCode = XML_ERROR_FINISHED;
+ return XML_STATUS_ERROR;
+ default:
+ ps_parsing = XML_PARSING;
+ }
+
+ start = bufferPtr;
+ positionPtr = start;
+ bufferEnd += len;
+ parseEndPtr = bufferEnd;
+ parseEndByteIndex += len;
+ ps_finalBuffer = (XML_Bool)isFinal;
+
+ errorCode = processor(parser, start, parseEndPtr, &bufferPtr);
+
+ if (errorCode != XML_ERROR_NONE) {
+ eventEndPtr = eventPtr;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ else {
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ result = XML_STATUS_SUSPENDED;
+ break;
+ case XML_INITIALIZED:
+ case XML_PARSING:
+ if (isFinal) {
+ ps_parsing = XML_FINISHED;
+ return result;
+ }
+ default: ; /* should not happen */
+ }
+ }
+
+ XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+ positionPtr = bufferPtr;
+ return result;
+}
+
+void * XMLCALL
+XML_GetBuffer(XML_Parser parser, int len)
+{
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ errorCode = XML_ERROR_SUSPENDED;
+ return NULL;
+ case XML_FINISHED:
+ errorCode = XML_ERROR_FINISHED;
+ return NULL;
+ default: ;
+ }
+
+ if (len > bufferLim - bufferEnd) {
+ /* FIXME avoid integer overflow */
+ int neededSize = len + (int)(bufferEnd - bufferPtr);
+#ifdef XML_CONTEXT_BYTES
+ int keep = (int)(bufferPtr - buffer);
+
+ if (keep > XML_CONTEXT_BYTES)
+ keep = XML_CONTEXT_BYTES;
+ neededSize += keep;
+#endif /* defined XML_CONTEXT_BYTES */
+ if (neededSize <= bufferLim - buffer) {
+#ifdef XML_CONTEXT_BYTES
+ if (keep < bufferPtr - buffer) {
+ int offset = (int)(bufferPtr - buffer) - keep;
+ memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep);
+ bufferEnd -= offset;
+ bufferPtr -= offset;
+ }
+#else
+ memmove(buffer, bufferPtr, bufferEnd - bufferPtr);
+ bufferEnd = buffer + (bufferEnd - bufferPtr);
+ bufferPtr = buffer;
+#endif /* not defined XML_CONTEXT_BYTES */
+ }
+ else {
+ char *newBuf;
+ int bufferSize = (int)(bufferLim - bufferPtr);
+ if (bufferSize == 0)
+ bufferSize = INIT_BUFFER_SIZE;
+ do {
+ bufferSize *= 2;
+ } while (bufferSize < neededSize);
+ newBuf = (char *)MALLOC(bufferSize);
+ if (newBuf == 0) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return NULL;
+ }
+ bufferLim = newBuf + bufferSize;
+#ifdef XML_CONTEXT_BYTES
+ if (bufferPtr) {
+ int keep = (int)(bufferPtr - buffer);
+ if (keep > XML_CONTEXT_BYTES)
+ keep = XML_CONTEXT_BYTES;
+ memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep);
+ FREE(buffer);
+ buffer = newBuf;
+ bufferEnd = buffer + (bufferEnd - bufferPtr) + keep;
+ bufferPtr = buffer + keep;
+ }
+ else {
+ bufferEnd = newBuf + (bufferEnd - bufferPtr);
+ bufferPtr = buffer = newBuf;
+ }
+#else
+ if (bufferPtr) {
+ memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr);
+ FREE(buffer);
+ }
+ bufferEnd = newBuf + (bufferEnd - bufferPtr);
+ bufferPtr = buffer = newBuf;
+#endif /* not defined XML_CONTEXT_BYTES */
+ }
+ }
+ return bufferEnd;
+}
+
+enum XML_Status XMLCALL
+XML_StopParser(XML_Parser parser, XML_Bool resumable)
+{
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ if (resumable) {
+ errorCode = XML_ERROR_SUSPENDED;
+ return XML_STATUS_ERROR;
+ }
+ ps_parsing = XML_FINISHED;
+ break;
+ case XML_FINISHED:
+ errorCode = XML_ERROR_FINISHED;
+ return XML_STATUS_ERROR;
+ default:
+ if (resumable) {
+#ifdef XML_DTD
+ if (isParamEntity) {
+ errorCode = XML_ERROR_SUSPEND_PE;
+ return XML_STATUS_ERROR;
+ }
+#endif
+ ps_parsing = XML_SUSPENDED;
+ }
+ else
+ ps_parsing = XML_FINISHED;
+ }
+ return XML_STATUS_OK;
+}
+
+enum XML_Status XMLCALL
+XML_ResumeParser(XML_Parser parser)
+{
+ enum XML_Status result = XML_STATUS_OK;
+
+ if (ps_parsing != XML_SUSPENDED) {
+ errorCode = XML_ERROR_NOT_SUSPENDED;
+ return XML_STATUS_ERROR;
+ }
+ ps_parsing = XML_PARSING;
+
+ errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+
+ if (errorCode != XML_ERROR_NONE) {
+ eventEndPtr = eventPtr;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ else {
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ result = XML_STATUS_SUSPENDED;
+ break;
+ case XML_INITIALIZED:
+ case XML_PARSING:
+ if (ps_finalBuffer) {
+ ps_parsing = XML_FINISHED;
+ return result;
+ }
+ default: ;
+ }
+ }
+
+ XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+ positionPtr = bufferPtr;
+ return result;
+}
+
+void XMLCALL
+XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status)
+{
+ assert(status != NULL);
+ *status = parser->m_parsingStatus;
+}
+
+enum XML_Error XMLCALL
+XML_GetErrorCode(XML_Parser parser)
+{
+ return errorCode;
+}
+
+XML_Index XMLCALL
+XML_GetCurrentByteIndex(XML_Parser parser)
+{
+ if (eventPtr)
+ return parseEndByteIndex - (parseEndPtr - eventPtr);
+ return -1;
+}
+
+int XMLCALL
+XML_GetCurrentByteCount(XML_Parser parser)
+{
+ if (eventEndPtr && eventPtr)
+ return (int)(eventEndPtr - eventPtr);
+ return 0;
+}
+
+const char * XMLCALL
+XML_GetInputContext(XML_Parser parser, int *offset, int *size)
+{
+#ifdef XML_CONTEXT_BYTES
+ if (eventPtr && buffer) {
+ *offset = (int)(eventPtr - buffer);
+ *size = (int)(bufferEnd - buffer);
+ return buffer;
+ }
+#endif /* defined XML_CONTEXT_BYTES */
+ return (char *) 0;
+}
+
+XML_Size XMLCALL
+XML_GetCurrentLineNumber(XML_Parser parser)
+{
+ if (eventPtr && eventPtr >= positionPtr) {
+ XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+ positionPtr = eventPtr;
+ }
+ return position.lineNumber + 1;
+}
+
+XML_Size XMLCALL
+XML_GetCurrentColumnNumber(XML_Parser parser)
+{
+ if (eventPtr && eventPtr >= positionPtr) {
+ XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+ positionPtr = eventPtr;
+ }
+ return position.columnNumber;
+}
+
+void XMLCALL
+XML_FreeContentModel(XML_Parser parser, XML_Content *model)
+{
+ FREE(model);
+}
+
+void * XMLCALL
+XML_MemMalloc(XML_Parser parser, size_t size)
+{
+ return MALLOC(size);
+}
+
+void * XMLCALL
+XML_MemRealloc(XML_Parser parser, void *ptr, size_t size)
+{
+ return REALLOC(ptr, size);
+}
+
+void XMLCALL
+XML_MemFree(XML_Parser parser, void *ptr)
+{
+ FREE(ptr);
+}
+
+void XMLCALL
+XML_DefaultCurrent(XML_Parser parser)
+{
+ if (defaultHandler) {
+ if (openInternalEntities)
+ reportDefault(parser,
+ internalEncoding,
+ openInternalEntities->internalEventPtr,
+ openInternalEntities->internalEventEndPtr);
+ else
+ reportDefault(parser, encoding, eventPtr, eventEndPtr);
+ }
+}
+
+const XML_LChar * XMLCALL
+XML_ErrorString(enum XML_Error code)
+{
+ static const XML_LChar* const message[] = {
+ 0,
+ XML_L("out of memory"),
+ XML_L("syntax error"),
+ XML_L("no element found"),
+ XML_L("not well-formed (invalid token)"),
+ XML_L("unclosed token"),
+ XML_L("partial character"),
+ XML_L("mismatched tag"),
+ XML_L("duplicate attribute"),
+ XML_L("junk after document element"),
+ XML_L("illegal parameter entity reference"),
+ XML_L("undefined entity"),
+ XML_L("recursive entity reference"),
+ XML_L("asynchronous entity"),
+ XML_L("reference to invalid character number"),
+ XML_L("reference to binary entity"),
+ XML_L("reference to external entity in attribute"),
+ XML_L("XML or text declaration not at start of entity"),
+ XML_L("unknown encoding"),
+ XML_L("encoding specified in XML declaration is incorrect"),
+ XML_L("unclosed CDATA section"),
+ XML_L("error in processing external entity reference"),
+ XML_L("document is not standalone"),
+ XML_L("unexpected parser state - please send a bug report"),
+ XML_L("entity declared in parameter entity"),
+ XML_L("requested feature requires XML_DTD support in Expat"),
+ XML_L("cannot change setting once parsing has begun"),
+ XML_L("unbound prefix"),
+ XML_L("must not undeclare prefix"),
+ XML_L("incomplete markup in parameter entity"),
+ XML_L("XML declaration not well-formed"),
+ XML_L("text declaration not well-formed"),
+ XML_L("illegal character(s) in public id"),
+ XML_L("parser suspended"),
+ XML_L("parser not suspended"),
+ XML_L("parsing aborted"),
+ XML_L("parsing finished"),
+ XML_L("cannot suspend in external parameter entity"),
+ XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"),
+ XML_L("reserved prefix (xmlns) must not be declared or undeclared"),
+ XML_L("prefix must not be bound to one of the reserved namespace names")
+ };
+ if (code > 0 && code < sizeof(message)/sizeof(message[0]))
+ return message[code];
+ return NULL;
+}
+
+const XML_LChar * XMLCALL
+XML_ExpatVersion(void) {
+
+ /* V1 is used to string-ize the version number. However, it would
+ string-ize the actual version macro *names* unless we get them
+ substituted before being passed to V1. CPP is defined to expand
+ a macro, then rescan for more expansions. Thus, we use V2 to expand
+ the version macros, then CPP will expand the resulting V1() macro
+ with the correct numerals. */
+ /* ### I'm assuming cpp is portable in this respect... */
+
+#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c)
+#define V2(a,b,c) XML_L("expat_")V1(a,b,c)
+
+ return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION);
+
+#undef V1
+#undef V2
+}
+
+XML_Expat_Version XMLCALL
+XML_ExpatVersionInfo(void)
+{
+ XML_Expat_Version version;
+
+ version.major = XML_MAJOR_VERSION;
+ version.minor = XML_MINOR_VERSION;
+ version.micro = XML_MICRO_VERSION;
+
+ return version;
+}
+
+const XML_Feature * XMLCALL
+XML_GetFeatureList(void)
+{
+ static const XML_Feature features[] = {
+ {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
+ sizeof(XML_Char)},
+ {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+ sizeof(XML_LChar)},
+#ifdef XML_UNICODE
+ {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
+#endif
+#ifdef XML_UNICODE_WCHAR_T
+ {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
+#endif
+#ifdef XML_DTD
+ {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
+#endif
+#ifdef XML_CONTEXT_BYTES
+ {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
+ XML_CONTEXT_BYTES},
+#endif
+#ifdef XML_MIN_SIZE
+ {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
+#endif
+#ifdef XML_NS
+ {XML_FEATURE_NS, XML_L("XML_NS"), 0},
+#endif
+ {XML_FEATURE_END, NULL, 0}
+ };
+
+ return features;
+}
+
+/* Initially tag->rawName always points into the parse buffer;
+ for those TAG instances opened while the current parse buffer was
+ processed, and not yet closed, we need to store tag->rawName in a more
+ permanent location, since the parse buffer is about to be discarded.
+*/
+static XML_Bool
+storeRawNames(XML_Parser parser)
+{
+ TAG *tag = tagStack;
+ while (tag) {
+ int bufSize;
+ int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
+ char *rawNameBuf = tag->buf + nameLen;
+ /* Stop if already stored. Since tagStack is a stack, we can stop
+ at the first entry that has already been copied; everything
+ below it in the stack is already been accounted for in a
+ previous call to this function.
+ */
+ if (tag->rawName == rawNameBuf)
+ break;
+ /* For re-use purposes we need to ensure that the
+ size of tag->buf is a multiple of sizeof(XML_Char).
+ */
+ bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
+ if (bufSize > tag->bufEnd - tag->buf) {
+ char *temp = (char *)REALLOC(tag->buf, bufSize);
+ if (temp == NULL)
+ return XML_FALSE;
+ /* if tag->name.str points to tag->buf (only when namespace
+ processing is off) then we have to update it
+ */
+ if (tag->name.str == (XML_Char *)tag->buf)
+ tag->name.str = (XML_Char *)temp;
+ /* if tag->name.localPart is set (when namespace processing is on)
+ then update it as well, since it will always point into tag->buf
+ */
+ if (tag->name.localPart)
+ tag->name.localPart = (XML_Char *)temp + (tag->name.localPart -
+ (XML_Char *)tag->buf);
+ tag->buf = temp;
+ tag->bufEnd = temp + bufSize;
+ rawNameBuf = temp + nameLen;
+ }
+ memcpy(rawNameBuf, tag->rawName, tag->rawNameLength);
+ tag->rawName = rawNameBuf;
+ tag = tag->parent;
+ }
+ return XML_TRUE;
+}
+
+static enum XML_Error PTRCALL
+contentProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doContent(parser, 0, encoding, start, end,
+ endPtr, (XML_Bool)!ps_finalBuffer);
+ if (result == XML_ERROR_NONE) {
+ if (!storeRawNames(parser))
+ return XML_ERROR_NO_MEMORY;
+ }
+ return result;
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = initializeEncoding(parser);
+ if (result != XML_ERROR_NONE)
+ return result;
+ processor = externalEntityInitProcessor2;
+ return externalEntityInitProcessor2(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor2(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ const char *next = start; /* XmlContentTok doesn't always set the last arg */
+ int tok = XmlContentTok(encoding, start, end, &next);
+ switch (tok) {
+ case XML_TOK_BOM:
+ /* If we are at the end of the buffer, this would cause the next stage,
+ i.e. externalEntityInitProcessor3, to pass control directly to
+ doContent (by detecting XML_TOK_NONE) without processing any xml text
+ declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent.
+ */
+ if (next == end && !ps_finalBuffer) {
+ *endPtr = next;
+ return XML_ERROR_NONE;
+ }
+ start = next;
+ break;
+ case XML_TOK_PARTIAL:
+ if (!ps_finalBuffer) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ eventPtr = start;
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (!ps_finalBuffer) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ eventPtr = start;
+ return XML_ERROR_PARTIAL_CHAR;
+ }
+ processor = externalEntityInitProcessor3;
+ return externalEntityInitProcessor3(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor3(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ int tok;
+ const char *next = start; /* XmlContentTok doesn't always set the last arg */
+ eventPtr = start;
+ tok = XmlContentTok(encoding, start, end, &next);
+ eventEndPtr = next;
+
+ switch (tok) {
+ case XML_TOK_XML_DECL:
+ {
+ enum XML_Error result;
+ result = processXmlDecl(parser, 1, start, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *endPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default:
+ start = next;
+ }
+ }
+ break;
+ case XML_TOK_PARTIAL:
+ if (!ps_finalBuffer) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (!ps_finalBuffer) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ }
+ processor = externalEntityContentProcessor;
+ tagLevel = 1;
+ return externalEntityContentProcessor(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityContentProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doContent(parser, 1, encoding, start, end,
+ endPtr, (XML_Bool)!ps_finalBuffer);
+ if (result == XML_ERROR_NONE) {
+ if (!storeRawNames(parser))
+ return XML_ERROR_NO_MEMORY;
+ }
+ return result;
+}
+
+static enum XML_Error
+doContent(XML_Parser parser,
+ int startTagLevel,
+ const ENCODING *enc,
+ const char *s,
+ const char *end,
+ const char **nextPtr,
+ XML_Bool haveMore)
+{
+ /* save one level of indirection */
+ DTD * const dtd = _dtd;
+
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ *eventPP = s;
+
+ for (;;) {
+ const char *next = s; /* XmlContentTok doesn't always set the last arg */
+ int tok = XmlContentTok(enc, s, end, &next);
+ *eventEndPP = next;
+ switch (tok) {
+ case XML_TOK_TRAILING_CR:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ *eventEndPP = end;
+ if (characterDataHandler) {
+ XML_Char c = 0xA;
+ characterDataHandler(handlerArg, &c, 1);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, end);
+ /* We are at the end of the final buffer, should we check for
+ XML_SUSPENDED, XML_FINISHED?
+ */
+ if (startTagLevel == 0)
+ return XML_ERROR_NO_ELEMENTS;
+ if (tagLevel != startTagLevel)
+ return XML_ERROR_ASYNC_ENTITY;
+ *nextPtr = end;
+ return XML_ERROR_NONE;
+ case XML_TOK_NONE:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ if (startTagLevel > 0) {
+ if (tagLevel != startTagLevel)
+ return XML_ERROR_ASYNC_ENTITY;
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_NO_ELEMENTS;
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_ENTITY_REF:
+ {
+ const XML_Char *name;
+ ENTITY *entity;
+ XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (ch) {
+ if (characterDataHandler)
+ characterDataHandler(handlerArg, &ch, 1);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ name = poolStoreString(&dtd->pool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0);
+ poolDiscard(&dtd->pool);
+ /* First, determine if a check for an existing declaration is needed;
+ if yes, check that the entity exists, and that it is internal,
+ otherwise call the skipped entity or default handler.
+ */
+ if (!dtd->hasParamEntityRefs || dtd->standalone) {
+ if (!entity)
+ return XML_ERROR_UNDEFINED_ENTITY;
+ else if (!entity->is_internal)
+ return XML_ERROR_ENTITY_DECLARED_IN_PE;
+ }
+ else if (!entity) {
+ if (skippedEntityHandler)
+ skippedEntityHandler(handlerArg, name, 0);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ if (entity->open)
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
+ if (entity->notation)
+ return XML_ERROR_BINARY_ENTITY_REF;
+ if (entity->textPtr) {
+ enum XML_Error result;
+ if (!defaultExpandInternalEntities) {
+ if (skippedEntityHandler)
+ skippedEntityHandler(handlerArg, entity->name, 0);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ result = processInternalEntity(parser, entity, XML_FALSE);
+ if (result != XML_ERROR_NONE)
+ return result;
+ }
+ else if (externalEntityRefHandler) {
+ const XML_Char *context;
+ entity->open = XML_TRUE;
+ context = getContext(parser);
+ entity->open = XML_FALSE;
+ if (!context)
+ return XML_ERROR_NO_MEMORY;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ context,
+ entity->base,
+ entity->systemId,
+ entity->publicId))
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ poolDiscard(&tempPool);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ case XML_TOK_START_TAG_NO_ATTS:
+ /* fall through */
+ case XML_TOK_START_TAG_WITH_ATTS:
+ {
+ TAG *tag;
+ enum XML_Error result;
+ XML_Char *toPtr;
+ if (freeTagList) {
+ tag = freeTagList;
+ freeTagList = freeTagList->parent;
+ }
+ else {
+ tag = (TAG *)MALLOC(sizeof(TAG));
+ if (!tag)
+ return XML_ERROR_NO_MEMORY;
+ tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE);
+ if (!tag->buf) {
+ FREE(tag);
+ return XML_ERROR_NO_MEMORY;
+ }
+ tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
+ }
+ tag->bindings = NULL;
+ tag->parent = tagStack;
+ tagStack = tag;
+ tag->name.localPart = NULL;
+ tag->name.prefix = NULL;
+ tag->rawName = s + enc->minBytesPerChar;
+ tag->rawNameLength = XmlNameLength(enc, tag->rawName);
+ ++tagLevel;
+ {
+ const char *rawNameEnd = tag->rawName + tag->rawNameLength;
+ const char *fromPtr = tag->rawName;
+ toPtr = (XML_Char *)tag->buf;
+ for (;;) {
+ int bufSize;
+ int convLen;
+ XmlConvert(enc,
+ &fromPtr, rawNameEnd,
+ (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1);
+ convLen = (int)(toPtr - (XML_Char *)tag->buf);
+ if (fromPtr == rawNameEnd) {
+ tag->name.strLen = convLen;
+ break;
+ }
+ bufSize = (int)(tag->bufEnd - tag->buf) << 1;
+ {
+ char *temp = (char *)REALLOC(tag->buf, bufSize);
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ tag->buf = temp;
+ tag->bufEnd = temp + bufSize;
+ toPtr = (XML_Char *)temp + convLen;
+ }
+ }
+ }
+ tag->name.str = (XML_Char *)tag->buf;
+ *toPtr = XML_T('\0');
+ result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
+ if (result)
+ return result;
+ if (startElementHandler)
+ startElementHandler(handlerArg, tag->name.str,
+ (const XML_Char **)atts);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ poolClear(&tempPool);
+ break;
+ }
+ case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
+ /* fall through */
+ case XML_TOK_EMPTY_ELEMENT_WITH_ATTS:
+ {
+ const char *rawName = s + enc->minBytesPerChar;
+ enum XML_Error result;
+ BINDING *bindings = NULL;
+ XML_Bool noElmHandlers = XML_TRUE;
+ TAG_NAME name;
+ name.str = poolStoreString(&tempPool, enc, rawName,
+ rawName + XmlNameLength(enc, rawName));
+ if (!name.str)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ result = storeAtts(parser, enc, s, &name, &bindings);
+ if (result)
+ return result;
+ poolFinish(&tempPool);
+ if (startElementHandler) {
+ startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
+ noElmHandlers = XML_FALSE;
+ }
+ if (endElementHandler) {
+ if (startElementHandler)
+ *eventPP = *eventEndPP;
+ endElementHandler(handlerArg, name.str);
+ noElmHandlers = XML_FALSE;
+ }
+ if (noElmHandlers && defaultHandler)
+ reportDefault(parser, enc, s, next);
+ poolClear(&tempPool);
+ while (bindings) {
+ BINDING *b = bindings;
+ if (endNamespaceDeclHandler)
+ endNamespaceDeclHandler(handlerArg, b->prefix->name);
+ bindings = bindings->nextTagBinding;
+ b->nextTagBinding = freeBindingList;
+ freeBindingList = b;
+ b->prefix->binding = b->prevPrefixBinding;
+ }
+ }
+ if (tagLevel == 0)
+ return epilogProcessor(parser, next, end, nextPtr);
+ break;
+ case XML_TOK_END_TAG:
+ if (tagLevel == startTagLevel)
+ return XML_ERROR_ASYNC_ENTITY;
+ else {
+ int len;
+ const char *rawName;
+ TAG *tag = tagStack;
+ tagStack = tag->parent;
+ tag->parent = freeTagList;
+ freeTagList = tag;
+ rawName = s + enc->minBytesPerChar*2;
+ len = XmlNameLength(enc, rawName);
+ if (len != tag->rawNameLength
+ || memcmp(tag->rawName, rawName, len) != 0) {
+ *eventPP = rawName;
+ return XML_ERROR_TAG_MISMATCH;
+ }
+ --tagLevel;
+ if (endElementHandler) {
+ const XML_Char *localPart;
+ const XML_Char *prefix;
+ XML_Char *uri;
+ localPart = tag->name.localPart;
+ if (ns && localPart) {
+ /* localPart and prefix may have been overwritten in
+ tag->name.str, since this points to the binding->uri
+ buffer which gets re-used; so we have to add them again
+ */
+ uri = (XML_Char *)tag->name.str + tag->name.uriLen;
+ /* don't need to check for space - already done in storeAtts() */
+ while (*localPart) *uri++ = *localPart++;
+ prefix = (XML_Char *)tag->name.prefix;
+ if (ns_triplets && prefix) {
+ *uri++ = namespaceSeparator;
+ while (*prefix) *uri++ = *prefix++;
+ }
+ *uri = XML_T('\0');
+ }
+ endElementHandler(handlerArg, tag->name.str);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ while (tag->bindings) {
+ BINDING *b = tag->bindings;
+ if (endNamespaceDeclHandler)
+ endNamespaceDeclHandler(handlerArg, b->prefix->name);
+ tag->bindings = tag->bindings->nextTagBinding;
+ b->nextTagBinding = freeBindingList;
+ freeBindingList = b;
+ b->prefix->binding = b->prevPrefixBinding;
+ }
+ if (tagLevel == 0)
+ return epilogProcessor(parser, next, end, nextPtr);
+ }
+ break;
+ case XML_TOK_CHAR_REF:
+ {
+ int n = XmlCharRefNumber(enc, s);
+ if (n < 0)
+ return XML_ERROR_BAD_CHAR_REF;
+ if (characterDataHandler) {
+ XML_Char buf[XML_ENCODE_MAX];
+ characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ }
+ break;
+ case XML_TOK_XML_DECL:
+ return XML_ERROR_MISPLACED_XML_PI;
+ case XML_TOK_DATA_NEWLINE:
+ if (characterDataHandler) {
+ XML_Char c = 0xA;
+ characterDataHandler(handlerArg, &c, 1);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ case XML_TOK_CDATA_SECT_OPEN:
+ {
+ enum XML_Error result;
+ if (startCdataSectionHandler)
+ startCdataSectionHandler(handlerArg);
+#if 0
+ /* Suppose you doing a transformation on a document that involves
+ changing only the character data. You set up a defaultHandler
+ and a characterDataHandler. The defaultHandler simply copies
+ characters through. The characterDataHandler does the
+ transformation and writes the characters out escaping them as
+ necessary. This case will fail to work if we leave out the
+ following two lines (because & and < inside CDATA sections will
+ be incorrectly escaped).
+
+ However, now we have a start/endCdataSectionHandler, so it seems
+ easier to let the user deal with this.
+ */
+ else if (characterDataHandler)
+ characterDataHandler(handlerArg, dataBuf, 0);
+#endif
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
+ if (result != XML_ERROR_NONE)
+ return result;
+ else if (!next) {
+ processor = cdataSectionProcessor;
+ return result;
+ }
+ }
+ break;
+ case XML_TOK_TRAILING_RSQB:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ if (characterDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+ characterDataHandler(handlerArg, dataBuf,
+ (int)(dataPtr - (ICHAR *)dataBuf));
+ }
+ else
+ characterDataHandler(handlerArg,
+ (XML_Char *)s,
+ (int)((XML_Char *)end - (XML_Char *)s));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, end);
+ /* We are at the end of the final buffer, should we check for
+ XML_SUSPENDED, XML_FINISHED?
+ */
+ if (startTagLevel == 0) {
+ *eventPP = end;
+ return XML_ERROR_NO_ELEMENTS;
+ }
+ if (tagLevel != startTagLevel) {
+ *eventPP = end;
+ return XML_ERROR_ASYNC_ENTITY;
+ }
+ *nextPtr = end;
+ return XML_ERROR_NONE;
+ case XML_TOK_DATA_CHARS:
+ if (characterDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ for (;;) {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+ *eventEndPP = s;
+ characterDataHandler(handlerArg, dataBuf,
+ (int)(dataPtr - (ICHAR *)dataBuf));
+ if (s == next)
+ break;
+ *eventPP = s;
+ }
+ }
+ else
+ characterDataHandler(handlerArg,
+ (XML_Char *)s,
+ (int)((XML_Char *)next - (XML_Char *)s));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ case XML_TOK_PI:
+ if (!reportProcessingInstruction(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_COMMENT:
+ if (!reportComment(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ default:
+ if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ *eventPP = s = next;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default: ;
+ }
+ }
+ /* not reached */
+}
+
+/* Precondition: all arguments must be non-NULL;
+ Purpose:
+ - normalize attributes
+ - check attributes for well-formedness
+ - generate namespace aware attribute names (URI, prefix)
+ - build list of attributes for startElementHandler
+ - default attributes
+ - process namespace declarations (check and report them)
+ - generate namespace aware element name (URI, prefix)
+*/
+static enum XML_Error
+storeAtts(XML_Parser parser, const ENCODING *enc,
+ const char *attStr, TAG_NAME *tagNamePtr,
+ BINDING **bindingsPtr)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ ELEMENT_TYPE *elementType;
+ int nDefaultAtts;
+ const XML_Char **appAtts; /* the attribute list for the application */
+ int attIndex = 0;
+ int prefixLen;
+ int i;
+ int n;
+ XML_Char *uri;
+ int nPrefixes = 0;
+ BINDING *binding;
+ const XML_Char *localPart;
+
+ /* lookup the element type name */
+ elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, tagNamePtr->str,0);
+ if (!elementType) {
+ const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ elementType = (ELEMENT_TYPE *)lookup(&dtd->elementTypes, name,
+ sizeof(ELEMENT_TYPE));
+ if (!elementType)
+ return XML_ERROR_NO_MEMORY;
+ if (ns && !setElementTypePrefix(parser, elementType))
+ return XML_ERROR_NO_MEMORY;
+ }
+ nDefaultAtts = elementType->nDefaultAtts;
+
+ /* get the attributes from the tokenizer */
+ n = XmlGetAttributes(enc, attStr, attsSize, atts);
+ if (n + nDefaultAtts > attsSize) {
+ int oldAttsSize = attsSize;
+ ATTRIBUTE *temp;
+ attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
+ temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ atts = temp;
+ if (n > oldAttsSize)
+ XmlGetAttributes(enc, attStr, n, atts);
+ }
+
+ appAtts = (const XML_Char **)atts;
+ for (i = 0; i < n; i++) {
+ /* add the name and value to the attribute list */
+ ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name,
+ atts[i].name
+ + XmlNameLength(enc, atts[i].name));
+ if (!attId)
+ return XML_ERROR_NO_MEMORY;
+ /* Detect duplicate attributes by their QNames. This does not work when
+ namespace processing is turned on and different prefixes for the same
+ namespace are used. For this case we have a check further down.
+ */
+ if ((attId->name)[-1]) {
+ if (enc == encoding)
+ eventPtr = atts[i].name;
+ return XML_ERROR_DUPLICATE_ATTRIBUTE;
+ }
+ (attId->name)[-1] = 1;
+ appAtts[attIndex++] = attId->name;
+ if (!atts[i].normalized) {
+ enum XML_Error result;
+ XML_Bool isCdata = XML_TRUE;
+
+ /* figure out whether declared as other than CDATA */
+ if (attId->maybeTokenized) {
+ int j;
+ for (j = 0; j < nDefaultAtts; j++) {
+ if (attId == elementType->defaultAtts[j].id) {
+ isCdata = elementType->defaultAtts[j].isCdata;
+ break;
+ }
+ }
+ }
+
+ /* normalize the attribute value */
+ result = storeAttributeValue(parser, enc, isCdata,
+ atts[i].valuePtr, atts[i].valueEnd,
+ &tempPool);
+ if (result)
+ return result;
+ appAtts[attIndex] = poolStart(&tempPool);
+ poolFinish(&tempPool);
+ }
+ else {
+ /* the value did not need normalizing */
+ appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr,
+ atts[i].valueEnd);
+ if (appAtts[attIndex] == 0)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ }
+ /* handle prefixed attribute names */
+ if (attId->prefix) {
+ if (attId->xmlns) {
+ /* deal with namespace declarations here */
+ enum XML_Error result = addBinding(parser, attId->prefix, attId,
+ appAtts[attIndex], bindingsPtr);
+ if (result)
+ return result;
+ --attIndex;
+ }
+ else {
+ /* deal with other prefixed names later */
+ attIndex++;
+ nPrefixes++;
+ (attId->name)[-1] = 2;
+ }
+ }
+ else
+ attIndex++;
+ }
+
+ /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
+ nSpecifiedAtts = attIndex;
+ if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
+ for (i = 0; i < attIndex; i += 2)
+ if (appAtts[i] == elementType->idAtt->name) {
+ idAttIndex = i;
+ break;
+ }
+ }
+ else
+ idAttIndex = -1;
+
+ /* do attribute defaulting */
+ for (i = 0; i < nDefaultAtts; i++) {
+ const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i;
+ if (!(da->id->name)[-1] && da->value) {
+ if (da->id->prefix) {
+ if (da->id->xmlns) {
+ enum XML_Error result = addBinding(parser, da->id->prefix, da->id,
+ da->value, bindingsPtr);
+ if (result)
+ return result;
+ }
+ else {
+ (da->id->name)[-1] = 2;
+ nPrefixes++;
+ appAtts[attIndex++] = da->id->name;
+ appAtts[attIndex++] = da->value;
+ }
+ }
+ else {
+ (da->id->name)[-1] = 1;
+ appAtts[attIndex++] = da->id->name;
+ appAtts[attIndex++] = da->value;
+ }
+ }
+ }
+ appAtts[attIndex] = 0;
+
+ /* expand prefixed attribute names, check for duplicates,
+ and clear flags that say whether attributes were specified */
+ i = 0;
+ if (nPrefixes) {
+ int j; /* hash table index */
+ unsigned long version = nsAttsVersion;
+ int nsAttsSize = (int)1 << nsAttsPower;
+ /* size of hash table must be at least 2 * (# of prefixed attributes) */
+ if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */
+ NS_ATT *temp;
+ /* hash table size must also be a power of 2 and >= 8 */
+ while (nPrefixes >> nsAttsPower++);
+ if (nsAttsPower < 3)
+ nsAttsPower = 3;
+ nsAttsSize = (int)1 << nsAttsPower;
+ temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT));
+ if (!temp)
+ return XML_ERROR_NO_MEMORY;
+ nsAtts = temp;
+ version = 0; /* force re-initialization of nsAtts hash table */
+ }
+ /* using a version flag saves us from initializing nsAtts every time */
+ if (!version) { /* initialize version flags when version wraps around */
+ version = INIT_ATTS_VERSION;
+ for (j = nsAttsSize; j != 0; )
+ nsAtts[--j].version = version;
+ }
+ nsAttsVersion = --version;
+
+ /* expand prefixed names and check for duplicates */
+ for (; i < attIndex; i += 2) {
+ const XML_Char *s = appAtts[i];
+ if (s[-1] == 2) { /* prefixed */
+ ATTRIBUTE_ID *id;
+ const BINDING *b;
+ unsigned long uriHash = 0;
+ ((XML_Char *)s)[-1] = 0; /* clear flag */
+ id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, s, 0);
+ b = id->prefix->binding;
+ if (!b)
+ return XML_ERROR_UNBOUND_PREFIX;
+
+ /* as we expand the name we also calculate its hash value */
+ for (j = 0; j < b->uriLen; j++) {
+ const XML_Char c = b->uri[j];
+ if (!poolAppendChar(&tempPool, c))
+ return XML_ERROR_NO_MEMORY;
+ uriHash = CHAR_HASH(uriHash, c);
+ }
+ while (*s++ != XML_T(':'))
+ ;
+ do { /* copies null terminator */
+ const XML_Char c = *s;
+ if (!poolAppendChar(&tempPool, *s))
+ return XML_ERROR_NO_MEMORY;
+ uriHash = CHAR_HASH(uriHash, c);
+ } while (*s++);
+
+ { /* Check hash table for duplicate of expanded name (uriName).
+ Derived from code in lookup(HASH_TABLE *table, ...).
+ */
+ unsigned char step = 0;
+ unsigned long mask = nsAttsSize - 1;
+ j = uriHash & mask; /* index into hash table */
+ while (nsAtts[j].version == version) {
+ /* for speed we compare stored hash values first */
+ if (uriHash == nsAtts[j].hash) {
+ const XML_Char *s1 = poolStart(&tempPool);
+ const XML_Char *s2 = nsAtts[j].uriName;
+ /* s1 is null terminated, but not s2 */
+ for (; *s1 == *s2 && *s1 != 0; s1++, s2++);
+ if (*s1 == 0)
+ return XML_ERROR_DUPLICATE_ATTRIBUTE;
+ }
+ if (!step)
+ step = PROBE_STEP(uriHash, mask, nsAttsPower);
+ j < step ? (j += nsAttsSize - step) : (j -= step);
+ }
+ }
+
+ if (ns_triplets) { /* append namespace separator and prefix */
+ tempPool.ptr[-1] = namespaceSeparator;
+ s = b->prefix->name;
+ do {
+ if (!poolAppendChar(&tempPool, *s))
+ return XML_ERROR_NO_MEMORY;
+ } while (*s++);
+ }
+
+ /* store expanded name in attribute list */
+ s = poolStart(&tempPool);
+ poolFinish(&tempPool);
+ appAtts[i] = s;
+
+ /* fill empty slot with new version, uriName and hash value */
+ nsAtts[j].version = version;
+ nsAtts[j].hash = uriHash;
+ nsAtts[j].uriName = s;
+
+ if (!--nPrefixes) {
+ i += 2;
+ break;
+ }
+ }
+ else /* not prefixed */
+ ((XML_Char *)s)[-1] = 0; /* clear flag */
+ }
+ }
+ /* clear flags for the remaining attributes */
+ for (; i < attIndex; i += 2)
+ ((XML_Char *)(appAtts[i]))[-1] = 0;
+ for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
+ binding->attId->name[-1] = 0;
+
+ if (!ns)
+ return XML_ERROR_NONE;
+
+ /* expand the element type name */
+ if (elementType->prefix) {
+ binding = elementType->prefix->binding;
+ if (!binding)
+ return XML_ERROR_UNBOUND_PREFIX;
+ localPart = tagNamePtr->str;
+ while (*localPart++ != XML_T(':'))
+ ;
+ }
+ else if (dtd->defaultPrefix.binding) {
+ binding = dtd->defaultPrefix.binding;
+ localPart = tagNamePtr->str;
+ }
+ else
+ return XML_ERROR_NONE;
+ prefixLen = 0;
+ if (ns_triplets && binding->prefix->name) {
+ for (; binding->prefix->name[prefixLen++];)
+ ; /* prefixLen includes null terminator */
+ }
+ tagNamePtr->localPart = localPart;
+ tagNamePtr->uriLen = binding->uriLen;
+ tagNamePtr->prefix = binding->prefix->name;
+ tagNamePtr->prefixLen = prefixLen;
+ for (i = 0; localPart[i++];)
+ ; /* i includes null terminator */
+ n = i + binding->uriLen + prefixLen;
+ if (n > binding->uriAlloc) {
+ TAG *p;
+ uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char));
+ if (!uri)
+ return XML_ERROR_NO_MEMORY;
+ binding->uriAlloc = n + EXPAND_SPARE;
+ memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
+ for (p = tagStack; p; p = p->parent)
+ if (p->name.str == binding->uri)
+ p->name.str = uri;
+ FREE(binding->uri);
+ binding->uri = uri;
+ }
+ /* if namespaceSeparator != '\0' then uri includes it already */
+ uri = binding->uri + binding->uriLen;
+ memcpy(uri, localPart, i * sizeof(XML_Char));
+ /* we always have a namespace separator between localPart and prefix */
+ if (prefixLen) {
+ uri += i - 1;
+ *uri = namespaceSeparator; /* replace null terminator */
+ memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char));
+ }
+ tagNamePtr->str = binding->uri;
+ return XML_ERROR_NONE;
+}
+
+/* addBinding() overwrites the value of prefix->binding without checking.
+ Therefore one must keep track of the old value outside of addBinding().
+*/
+static enum XML_Error
+addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
+ const XML_Char *uri, BINDING **bindingsPtr)
+{
+ static const XML_Char xmlNamespace[] = {
+ 'h', 't', 't', 'p', ':', '/', '/',
+ 'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/',
+ 'X', 'M', 'L', '/', '1', '9', '9', '8', '/',
+ 'n', 'a', 'm', 'e', 's', 'p', 'a', 'c', 'e', '\0'
+ };
+ static const int xmlLen =
+ (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1;
+ static const XML_Char xmlnsNamespace[] = {
+ 'h', 't', 't', 'p', ':', '/', '/',
+ 'w', 'w', 'w', '.', 'w', '3', '.', 'o', 'r', 'g', '/',
+ '2', '0', '0', '0', '/', 'x', 'm', 'l', 'n', 's', '/', '\0'
+ };
+ static const int xmlnsLen =
+ (int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1;
+
+ XML_Bool mustBeXML = XML_FALSE;
+ XML_Bool isXML = XML_TRUE;
+ XML_Bool isXMLNS = XML_TRUE;
+
+ BINDING *b;
+ int len;
+
+ /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */
+ if (*uri == XML_T('\0') && prefix->name)
+ return XML_ERROR_UNDECLARING_PREFIX;
+
+ if (prefix->name
+ && prefix->name[0] == XML_T('x')
+ && prefix->name[1] == XML_T('m')
+ && prefix->name[2] == XML_T('l')) {
+
+ /* Not allowed to bind xmlns */
+ if (prefix->name[3] == XML_T('n')
+ && prefix->name[4] == XML_T('s')
+ && prefix->name[5] == XML_T('\0'))
+ return XML_ERROR_RESERVED_PREFIX_XMLNS;
+
+ if (prefix->name[3] == XML_T('\0'))
+ mustBeXML = XML_TRUE;
+ }
+
+ for (len = 0; uri[len]; len++) {
+ if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len]))
+ isXML = XML_FALSE;
+
+ if (!mustBeXML && isXMLNS
+ && (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
+ isXMLNS = XML_FALSE;
+ }
+ isXML = isXML && len == xmlLen;
+ isXMLNS = isXMLNS && len == xmlnsLen;
+
+ if (mustBeXML != isXML)
+ return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML
+ : XML_ERROR_RESERVED_NAMESPACE_URI;
+
+ if (isXMLNS)
+ return XML_ERROR_RESERVED_NAMESPACE_URI;
+
+ if (namespaceSeparator)
+ len++;
+ if (freeBindingList) {
+ b = freeBindingList;
+ if (len > b->uriAlloc) {
+ XML_Char *temp = (XML_Char *)REALLOC(b->uri,
+ sizeof(XML_Char) * (len + EXPAND_SPARE));
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ b->uri = temp;
+ b->uriAlloc = len + EXPAND_SPARE;
+ }
+ freeBindingList = b->nextTagBinding;
+ }
+ else {
+ b = (BINDING *)MALLOC(sizeof(BINDING));
+ if (!b)
+ return XML_ERROR_NO_MEMORY;
+ b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE));
+ if (!b->uri) {
+ FREE(b);
+ return XML_ERROR_NO_MEMORY;
+ }
+ b->uriAlloc = len + EXPAND_SPARE;
+ }
+ b->uriLen = len;
+ memcpy(b->uri, uri, len * sizeof(XML_Char));
+ if (namespaceSeparator)
+ b->uri[len - 1] = namespaceSeparator;
+ b->prefix = prefix;
+ b->attId = attId;
+ b->prevPrefixBinding = prefix->binding;
+ /* NULL binding when default namespace undeclared */
+ if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix)
+ prefix->binding = NULL;
+ else
+ prefix->binding = b;
+ b->nextTagBinding = *bindingsPtr;
+ *bindingsPtr = b;
+ /* if attId == NULL then we are not starting a namespace scope */
+ if (attId && startNamespaceDeclHandler)
+ startNamespaceDeclHandler(handlerArg, prefix->name,
+ prefix->binding ? uri : 0);
+ return XML_ERROR_NONE;
+}
+
+/* The idea here is to avoid using stack for each CDATA section when
+ the whole file is parsed with one call.
+*/
+static enum XML_Error PTRCALL
+cdataSectionProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doCdataSection(parser, encoding, &start, end,
+ endPtr, (XML_Bool)!ps_finalBuffer);
+ if (result != XML_ERROR_NONE)
+ return result;
+ if (start) {
+ if (parentParser) { /* we are parsing an external entity */
+ processor = externalEntityContentProcessor;
+ return externalEntityContentProcessor(parser, start, end, endPtr);
+ }
+ else {
+ processor = contentProcessor;
+ return contentProcessor(parser, start, end, endPtr);
+ }
+ }
+ return result;
+}
+
+/* startPtr gets set to non-null if the section is closed, and to null if
+ the section is not yet closed.
+*/
+static enum XML_Error
+doCdataSection(XML_Parser parser,
+ const ENCODING *enc,
+ const char **startPtr,
+ const char *end,
+ const char **nextPtr,
+ XML_Bool haveMore)
+{
+ const char *s = *startPtr;
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ *eventPP = s;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ *eventPP = s;
+ *startPtr = NULL;
+
+ for (;;) {
+ const char *next;
+ int tok = XmlCdataSectionTok(enc, s, end, &next);
+ *eventEndPP = next;
+ switch (tok) {
+ case XML_TOK_CDATA_SECT_CLOSE:
+ if (endCdataSectionHandler)
+ endCdataSectionHandler(handlerArg);
+#if 0
+ /* see comment under XML_TOK_CDATA_SECT_OPEN */
+ else if (characterDataHandler)
+ characterDataHandler(handlerArg, dataBuf, 0);
+#endif
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ *startPtr = next;
+ *nextPtr = next;
+ if (ps_parsing == XML_FINISHED)
+ return XML_ERROR_ABORTED;
+ else
+ return XML_ERROR_NONE;
+ case XML_TOK_DATA_NEWLINE:
+ if (characterDataHandler) {
+ XML_Char c = 0xA;
+ characterDataHandler(handlerArg, &c, 1);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ case XML_TOK_DATA_CHARS:
+ if (characterDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ for (;;) {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+ *eventEndPP = next;
+ characterDataHandler(handlerArg, dataBuf,
+ (int)(dataPtr - (ICHAR *)dataBuf));
+ if (s == next)
+ break;
+ *eventPP = s;
+ }
+ }
+ else
+ characterDataHandler(handlerArg,
+ (XML_Char *)s,
+ (int)((XML_Char *)next - (XML_Char *)s));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_PARTIAL:
+ case XML_TOK_NONE:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_CDATA_SECTION;
+ default:
+ *eventPP = next;
+ return XML_ERROR_UNEXPECTED_STATE;
+ }
+
+ *eventPP = s = next;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default: ;
+ }
+ }
+ /* not reached */
+}
+
+#ifdef XML_DTD
+
+/* The idea here is to avoid using stack for each IGNORE section when
+ the whole file is parsed with one call.
+*/
+static enum XML_Error PTRCALL
+ignoreSectionProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doIgnoreSection(parser, encoding, &start, end,
+ endPtr, (XML_Bool)!ps_finalBuffer);
+ if (result != XML_ERROR_NONE)
+ return result;
+ if (start) {
+ processor = prologProcessor;
+ return prologProcessor(parser, start, end, endPtr);
+ }
+ return result;
+}
+
+/* startPtr gets set to non-null is the section is closed, and to null
+ if the section is not yet closed.
+*/
+static enum XML_Error
+doIgnoreSection(XML_Parser parser,
+ const ENCODING *enc,
+ const char **startPtr,
+ const char *end,
+ const char **nextPtr,
+ XML_Bool haveMore)
+{
+ const char *next;
+ int tok;
+ const char *s = *startPtr;
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ *eventPP = s;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ *eventPP = s;
+ *startPtr = NULL;
+ tok = XmlIgnoreSectionTok(enc, s, end, &next);
+ *eventEndPP = next;
+ switch (tok) {
+ case XML_TOK_IGNORE_SECT:
+ if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ *startPtr = next;
+ *nextPtr = next;
+ if (ps_parsing == XML_FINISHED)
+ return XML_ERROR_ABORTED;
+ else
+ return XML_ERROR_NONE;
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_PARTIAL:
+ case XML_TOK_NONE:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */
+ default:
+ *eventPP = next;
+ return XML_ERROR_UNEXPECTED_STATE;
+ }
+ /* not reached */
+}
+
+#endif /* XML_DTD */
+
+static enum XML_Error
+initializeEncoding(XML_Parser parser)
+{
+ const char *s;
+#ifdef XML_UNICODE
+ char encodingBuf[128];
+ if (!protocolEncodingName)
+ s = NULL;
+ else {
+ int i;
+ for (i = 0; protocolEncodingName[i]; i++) {
+ if (i == sizeof(encodingBuf) - 1
+ || (protocolEncodingName[i] & ~0x7f) != 0) {
+ encodingBuf[0] = '\0';
+ break;
+ }
+ encodingBuf[i] = (char)protocolEncodingName[i];
+ }
+ encodingBuf[i] = '\0';
+ s = encodingBuf;
+ }
+#else
+ s = protocolEncodingName;
+#endif
+ if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s))
+ return XML_ERROR_NONE;
+ return handleUnknownEncoding(parser, protocolEncodingName);
+}
+
+static enum XML_Error
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
+ const char *s, const char *next)
+{
+ const char *encodingName = NULL;
+ const XML_Char *storedEncName = NULL;
+ const ENCODING *newEncoding = NULL;
+ const char *version = NULL;
+ const char *versionend;
+ const XML_Char *storedversion = NULL;
+ int standalone = -1;
+ if (!(ns
+ ? XmlParseXmlDeclNS
+ : XmlParseXmlDecl)(isGeneralTextEntity,
+ encoding,
+ s,
+ next,
+ &eventPtr,
+ &version,
+ &versionend,
+ &encodingName,
+ &newEncoding,
+ &standalone)) {
+ if (isGeneralTextEntity)
+ return XML_ERROR_TEXT_DECL;
+ else
+ return XML_ERROR_XML_DECL;
+ }
+ if (!isGeneralTextEntity && standalone == 1) {
+ _dtd->standalone = XML_TRUE;
+#ifdef XML_DTD
+ if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
+ paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+#endif /* XML_DTD */
+ }
+ if (xmlDeclHandler) {
+ if (encodingName != NULL) {
+ storedEncName = poolStoreString(&temp2Pool,
+ encoding,
+ encodingName,
+ encodingName
+ + XmlNameLength(encoding, encodingName));
+ if (!storedEncName)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&temp2Pool);
+ }
+ if (version) {
+ storedversion = poolStoreString(&temp2Pool,
+ encoding,
+ version,
+ versionend - encoding->minBytesPerChar);
+ if (!storedversion)
+ return XML_ERROR_NO_MEMORY;
+ }
+ xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, encoding, s, next);
+ if (protocolEncodingName == NULL) {
+ if (newEncoding) {
+ if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) {
+ eventPtr = encodingName;
+ return XML_ERROR_INCORRECT_ENCODING;
+ }
+ encoding = newEncoding;
+ }
+ else if (encodingName) {
+ enum XML_Error result;
+ if (!storedEncName) {
+ storedEncName = poolStoreString(
+ &temp2Pool, encoding, encodingName,
+ encodingName + XmlNameLength(encoding, encodingName));
+ if (!storedEncName)
+ return XML_ERROR_NO_MEMORY;
+ }
+ result = handleUnknownEncoding(parser, storedEncName);
+ poolClear(&temp2Pool);
+ if (result == XML_ERROR_UNKNOWN_ENCODING)
+ eventPtr = encodingName;
+ return result;
+ }
+ }
+
+ if (storedEncName || storedversion)
+ poolClear(&temp2Pool);
+
+ return XML_ERROR_NONE;
+}
+
+static enum XML_Error
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
+{
+ if (unknownEncodingHandler) {
+ XML_Encoding info;
+ int i;
+ for (i = 0; i < 256; i++)
+ info.map[i] = -1;
+ info.convert = NULL;
+ info.data = NULL;
+ info.release = NULL;
+ if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName,
+ &info)) {
+ ENCODING *enc;
+ unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding());
+ if (!unknownEncodingMem) {
+ if (info.release)
+ info.release(info.data);
+ return XML_ERROR_NO_MEMORY;
+ }
+ enc = (ns
+ ? XmlInitUnknownEncodingNS
+ : XmlInitUnknownEncoding)(unknownEncodingMem,
+ info.map,
+ info.convert,
+ info.data);
+ if (enc) {
+ unknownEncodingData = info.data;
+ unknownEncodingRelease = info.release;
+ encoding = enc;
+ return XML_ERROR_NONE;
+ }
+ }
+ if (info.release != NULL)
+ info.release(info.data);
+ }
+ return XML_ERROR_UNKNOWN_ENCODING;
+}
+
+static enum XML_Error PTRCALL
+prologInitProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ enum XML_Error result = initializeEncoding(parser);
+ if (result != XML_ERROR_NONE)
+ return result;
+ processor = prologProcessor;
+ return prologProcessor(parser, s, end, nextPtr);
+}
+
+#ifdef XML_DTD
+
+static enum XML_Error PTRCALL
+externalParEntInitProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ enum XML_Error result = initializeEncoding(parser);
+ if (result != XML_ERROR_NONE)
+ return result;
+
+ /* we know now that XML_Parse(Buffer) has been called,
+ so we consider the external parameter entity read */
+ _dtd->paramEntityRead = XML_TRUE;
+
+ if (prologState.inEntityValue) {
+ processor = entityValueInitProcessor;
+ return entityValueInitProcessor(parser, s, end, nextPtr);
+ }
+ else {
+ processor = externalParEntProcessor;
+ return externalParEntProcessor(parser, s, end, nextPtr);
+ }
+}
+
+static enum XML_Error PTRCALL
+entityValueInitProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ int tok;
+ const char *start = s;
+ const char *next = start;
+ eventPtr = start;
+
+ for (;;) {
+ tok = XmlPrologTok(encoding, start, end, &next);
+ eventEndPtr = next;
+ if (tok <= 0) {
+ if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_NONE: /* start == end */
+ default:
+ break;
+ }
+ /* found end of entity value - can store it now */
+ return storeEntityValue(parser, encoding, s, end);
+ }
+ else if (tok == XML_TOK_XML_DECL) {
+ enum XML_Error result;
+ result = processXmlDecl(parser, 0, start, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default:
+ *nextPtr = next;
+ }
+ /* stop scanning for text declaration - we found one */
+ processor = entityValueProcessor;
+ return entityValueProcessor(parser, next, end, nextPtr);
+ }
+ /* If we are at the end of the buffer, this would cause XmlPrologTok to
+ return XML_TOK_NONE on the next call, which would then cause the
+ function to exit with *nextPtr set to s - that is what we want for other
+ tokens, but not for the BOM - we would rather like to skip it;
+ then, when this routine is entered the next time, XmlPrologTok will
+ return XML_TOK_INVALID, since the BOM is still in the buffer
+ */
+ else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) {
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ }
+ start = next;
+ eventPtr = start;
+ }
+}
+
+static enum XML_Error PTRCALL
+externalParEntProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ const char *next = s;
+ int tok;
+
+ tok = XmlPrologTok(encoding, s, end, &next);
+ if (tok <= 0) {
+ if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_NONE: /* start == end */
+ default:
+ break;
+ }
+ }
+ /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM.
+ However, when parsing an external subset, doProlog will not accept a BOM
+ as valid, and report a syntax error, so we have to skip the BOM
+ */
+ else if (tok == XML_TOK_BOM) {
+ s = next;
+ tok = XmlPrologTok(encoding, s, end, &next);
+ }
+
+ processor = prologProcessor;
+ return doProlog(parser, encoding, s, end, tok, next,
+ nextPtr, (XML_Bool)!ps_finalBuffer);
+}
+
+static enum XML_Error PTRCALL
+entityValueProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ const char *start = s;
+ const char *next = s;
+ const ENCODING *enc = encoding;
+ int tok;
+
+ for (;;) {
+ tok = XmlPrologTok(enc, start, end, &next);
+ if (tok <= 0) {
+ if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_NONE: /* start == end */
+ default:
+ break;
+ }
+ /* found end of entity value - can store it now */
+ return storeEntityValue(parser, enc, s, end);
+ }
+ start = next;
+ }
+}
+
+#endif /* XML_DTD */
+
+static enum XML_Error PTRCALL
+prologProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ const char *next = s;
+ int tok = XmlPrologTok(encoding, s, end, &next);
+ return doProlog(parser, encoding, s, end, tok, next,
+ nextPtr, (XML_Bool)!ps_finalBuffer);
+}
+
+static enum XML_Error
+doProlog(XML_Parser parser,
+ const ENCODING *enc,
+ const char *s,
+ const char *end,
+ int tok,
+ const char *next,
+ const char **nextPtr,
+ XML_Bool haveMore)
+{
+#ifdef XML_DTD
+ static const XML_Char externalSubsetName[] = { '#' , '\0' };
+#endif /* XML_DTD */
+ static const XML_Char atypeCDATA[] = { 'C', 'D', 'A', 'T', 'A', '\0' };
+ static const XML_Char atypeID[] = { 'I', 'D', '\0' };
+ static const XML_Char atypeIDREF[] = { 'I', 'D', 'R', 'E', 'F', '\0' };
+ static const XML_Char atypeIDREFS[] = { 'I', 'D', 'R', 'E', 'F', 'S', '\0' };
+ static const XML_Char atypeENTITY[] = { 'E', 'N', 'T', 'I', 'T', 'Y', '\0' };
+ static const XML_Char atypeENTITIES[] =
+ { 'E', 'N', 'T', 'I', 'T', 'I', 'E', 'S', '\0' };
+ static const XML_Char atypeNMTOKEN[] = {
+ 'N', 'M', 'T', 'O', 'K', 'E', 'N', '\0' };
+ static const XML_Char atypeNMTOKENS[] = {
+ 'N', 'M', 'T', 'O', 'K', 'E', 'N', 'S', '\0' };
+ static const XML_Char notationPrefix[] = {
+ 'N', 'O', 'T', 'A', 'T', 'I', 'O', 'N', '(', '\0' };
+ static const XML_Char enumValueSep[] = { '|', '\0' };
+ static const XML_Char enumValueStart[] = { '(', '\0' };
+
+ /* save one level of indirection */
+ DTD * const dtd = _dtd;
+
+ const char **eventPP;
+ const char **eventEndPP;
+ enum XML_Content_Quant quant;
+
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+
+ for (;;) {
+ int role;
+ XML_Bool handleDefault = XML_TRUE;
+ *eventPP = s;
+ *eventEndPP = next;
+ if (tok <= 0) {
+ if (haveMore && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_NONE:
+#ifdef XML_DTD
+ /* for internal PE NOT referenced between declarations */
+ if (enc != encoding && !openInternalEntities->betweenDecl) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ /* WFC: PE Between Declarations - must check that PE contains
+ complete markup, not only for external PEs, but also for
+ internal PEs if the reference occurs between declarations.
+ */
+ if (isParamEntity || enc != encoding) {
+ if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc)
+ == XML_ROLE_ERROR)
+ return XML_ERROR_INCOMPLETE_PE;
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+#endif /* XML_DTD */
+ return XML_ERROR_NO_ELEMENTS;
+ default:
+ tok = -tok;
+ next = end;
+ break;
+ }
+ }
+ role = XmlTokenRole(&prologState, tok, s, next, enc);
+ switch (role) {
+ case XML_ROLE_XML_DECL:
+ {
+ enum XML_Error result = processXmlDecl(parser, 0, s, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ enc = encoding;
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_NAME:
+ if (startDoctypeDeclHandler) {
+ doctypeName = poolStoreString(&tempPool, enc, s, next);
+ if (!doctypeName)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ doctypePubid = NULL;
+ handleDefault = XML_FALSE;
+ }
+ doctypeSysid = NULL; /* always initialize to NULL */
+ break;
+ case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
+ if (startDoctypeDeclHandler) {
+ startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid,
+ doctypePubid, 1);
+ doctypeName = NULL;
+ poolClear(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ break;
+#ifdef XML_DTD
+ case XML_ROLE_TEXT_DECL:
+ {
+ enum XML_Error result = processXmlDecl(parser, 1, s, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ enc = encoding;
+ handleDefault = XML_FALSE;
+ }
+ break;
+#endif /* XML_DTD */
+ case XML_ROLE_DOCTYPE_PUBLIC_ID:
+#ifdef XML_DTD
+ useForeignDTD = XML_FALSE;
+ declEntity = (ENTITY *)lookup(&dtd->paramEntities,
+ externalSubsetName,
+ sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+#endif /* XML_DTD */
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (startDoctypeDeclHandler) {
+ XML_Char *tem;
+ if (!XmlIsPublicId(enc, s, next, eventPP))
+ return XML_ERROR_PUBLICID;
+ tem = poolStoreString(&tempPool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!tem)
+ return XML_ERROR_NO_MEMORY;
+ normalizePublicId(tem);
+ doctypePubid = tem;
+ poolFinish(&tempPool);
+ handleDefault = XML_FALSE;
+ goto alreadyChecked;
+ }
+ /* fall through */
+ case XML_ROLE_ENTITY_PUBLIC_ID:
+ if (!XmlIsPublicId(enc, s, next, eventPP))
+ return XML_ERROR_PUBLICID;
+ alreadyChecked:
+ if (dtd->keepProcessing && declEntity) {
+ XML_Char *tem = poolStoreString(&dtd->pool,
+ enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!tem)
+ return XML_ERROR_NO_MEMORY;
+ normalizePublicId(tem);
+ declEntity->publicId = tem;
+ poolFinish(&dtd->pool);
+ if (entityDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_CLOSE:
+ if (doctypeName) {
+ startDoctypeDeclHandler(handlerArg, doctypeName,
+ doctypeSysid, doctypePubid, 0);
+ poolClear(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ /* doctypeSysid will be non-NULL in the case of a previous
+ XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler
+ was not set, indicating an external subset
+ */
+#ifdef XML_DTD
+ if (doctypeSysid || useForeignDTD) {
+ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (paramEntityParsing && externalEntityRefHandler) {
+ ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities,
+ externalSubsetName,
+ sizeof(ENTITY));
+ if (!entity)
+ return XML_ERROR_NO_MEMORY;
+ if (useForeignDTD)
+ entity->base = curBase;
+ dtd->paramEntityRead = XML_FALSE;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ 0,
+ entity->base,
+ entity->systemId,
+ entity->publicId))
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ if (dtd->paramEntityRead) {
+ if (!dtd->standalone &&
+ notStandaloneHandler &&
+ !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+ }
+ /* if we didn't read the foreign DTD then this means that there
+ is no external subset and we must reset dtd->hasParamEntityRefs
+ */
+ else if (!doctypeSysid)
+ dtd->hasParamEntityRefs = hadParamEntityRefs;
+ /* end of DTD - no need to update dtd->keepProcessing */
+ }
+ useForeignDTD = XML_FALSE;
+ }
+#endif /* XML_DTD */
+ if (endDoctypeDeclHandler) {
+ endDoctypeDeclHandler(handlerArg);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_INSTANCE_START:
+#ifdef XML_DTD
+ /* if there is no DOCTYPE declaration then now is the
+ last chance to read the foreign DTD
+ */
+ if (useForeignDTD) {
+ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (paramEntityParsing && externalEntityRefHandler) {
+ ENTITY *entity = (ENTITY *)lookup(&dtd->paramEntities,
+ externalSubsetName,
+ sizeof(ENTITY));
+ if (!entity)
+ return XML_ERROR_NO_MEMORY;
+ entity->base = curBase;
+ dtd->paramEntityRead = XML_FALSE;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ 0,
+ entity->base,
+ entity->systemId,
+ entity->publicId))
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ if (dtd->paramEntityRead) {
+ if (!dtd->standalone &&
+ notStandaloneHandler &&
+ !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+ }
+ /* if we didn't read the foreign DTD then this means that there
+ is no external subset and we must reset dtd->hasParamEntityRefs
+ */
+ else
+ dtd->hasParamEntityRefs = hadParamEntityRefs;
+ /* end of DTD - no need to update dtd->keepProcessing */
+ }
+ }
+#endif /* XML_DTD */
+ processor = contentProcessor;
+ return contentProcessor(parser, s, end, nextPtr);
+ case XML_ROLE_ATTLIST_ELEMENT_NAME:
+ declElementType = getElementType(parser, enc, s, next);
+ if (!declElementType)
+ return XML_ERROR_NO_MEMORY;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_NAME:
+ declAttributeId = getAttributeId(parser, enc, s, next);
+ if (!declAttributeId)
+ return XML_ERROR_NO_MEMORY;
+ declAttributeIsCdata = XML_FALSE;
+ declAttributeType = NULL;
+ declAttributeIsId = XML_FALSE;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
+ declAttributeIsCdata = XML_TRUE;
+ declAttributeType = atypeCDATA;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_ID:
+ declAttributeIsId = XML_TRUE;
+ declAttributeType = atypeID;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_IDREF:
+ declAttributeType = atypeIDREF;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_IDREFS:
+ declAttributeType = atypeIDREFS;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_ENTITY:
+ declAttributeType = atypeENTITY;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES:
+ declAttributeType = atypeENTITIES;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN:
+ declAttributeType = atypeNMTOKEN;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS:
+ declAttributeType = atypeNMTOKENS;
+ checkAttListDeclHandler:
+ if (dtd->keepProcessing && attlistDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_ATTRIBUTE_ENUM_VALUE:
+ case XML_ROLE_ATTRIBUTE_NOTATION_VALUE:
+ if (dtd->keepProcessing && attlistDeclHandler) {
+ const XML_Char *prefix;
+ if (declAttributeType) {
+ prefix = enumValueSep;
+ }
+ else {
+ prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE
+ ? notationPrefix
+ : enumValueStart);
+ }
+ if (!poolAppendString(&tempPool, prefix))
+ return XML_ERROR_NO_MEMORY;
+ if (!poolAppend(&tempPool, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ declAttributeType = tempPool.start;
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
+ case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
+ if (dtd->keepProcessing) {
+ if (!defineAttribute(declElementType, declAttributeId,
+ declAttributeIsCdata, declAttributeIsId,
+ 0, parser))
+ return XML_ERROR_NO_MEMORY;
+ if (attlistDeclHandler && declAttributeType) {
+ if (*declAttributeType == XML_T('(')
+ || (*declAttributeType == XML_T('N')
+ && declAttributeType[1] == XML_T('O'))) {
+ /* Enumerated or Notation type */
+ if (!poolAppendChar(&tempPool, XML_T(')'))
+ || !poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_ERROR_NO_MEMORY;
+ declAttributeType = tempPool.start;
+ poolFinish(&tempPool);
+ }
+ *eventEndPP = s;
+ attlistDeclHandler(handlerArg, declElementType->name,
+ declAttributeId->name, declAttributeType,
+ 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
+ poolClear(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ }
+ break;
+ case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
+ case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
+ if (dtd->keepProcessing) {
+ const XML_Char *attVal;
+ enum XML_Error result =
+ storeAttributeValue(parser, enc, declAttributeIsCdata,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar,
+ &dtd->pool);
+ if (result)
+ return result;
+ attVal = poolStart(&dtd->pool);
+ poolFinish(&dtd->pool);
+ /* ID attributes aren't allowed to have a default */
+ if (!defineAttribute(declElementType, declAttributeId,
+ declAttributeIsCdata, XML_FALSE, attVal, parser))
+ return XML_ERROR_NO_MEMORY;
+ if (attlistDeclHandler && declAttributeType) {
+ if (*declAttributeType == XML_T('(')
+ || (*declAttributeType == XML_T('N')
+ && declAttributeType[1] == XML_T('O'))) {
+ /* Enumerated or Notation type */
+ if (!poolAppendChar(&tempPool, XML_T(')'))
+ || !poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_ERROR_NO_MEMORY;
+ declAttributeType = tempPool.start;
+ poolFinish(&tempPool);
+ }
+ *eventEndPP = s;
+ attlistDeclHandler(handlerArg, declElementType->name,
+ declAttributeId->name, declAttributeType,
+ attVal,
+ role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
+ poolClear(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ }
+ break;
+ case XML_ROLE_ENTITY_VALUE:
+ if (dtd->keepProcessing) {
+ enum XML_Error result = storeEntityValue(parser, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (declEntity) {
+ declEntity->textPtr = poolStart(&dtd->entityValuePool);
+ declEntity->textLen = (int)(poolLength(&dtd->entityValuePool));
+ poolFinish(&dtd->entityValuePool);
+ if (entityDeclHandler) {
+ *eventEndPP = s;
+ entityDeclHandler(handlerArg,
+ declEntity->name,
+ declEntity->is_param,
+ declEntity->textPtr,
+ declEntity->textLen,
+ curBase, 0, 0, 0);
+ handleDefault = XML_FALSE;
+ }
+ }
+ else
+ poolDiscard(&dtd->entityValuePool);
+ if (result != XML_ERROR_NONE)
+ return result;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_SYSTEM_ID:
+#ifdef XML_DTD
+ useForeignDTD = XML_FALSE;
+#endif /* XML_DTD */
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (startDoctypeDeclHandler) {
+ doctypeSysid = poolStoreString(&tempPool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (doctypeSysid == NULL)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+#ifdef XML_DTD
+ else
+ /* use externalSubsetName to make doctypeSysid non-NULL
+ for the case where no startDoctypeDeclHandler is set */
+ doctypeSysid = externalSubsetName;
+#endif /* XML_DTD */
+ if (!dtd->standalone
+#ifdef XML_DTD
+ && !paramEntityParsing
+#endif /* XML_DTD */
+ && notStandaloneHandler
+ && !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+#ifndef XML_DTD
+ break;
+#else /* XML_DTD */
+ if (!declEntity) {
+ declEntity = (ENTITY *)lookup(&dtd->paramEntities,
+ externalSubsetName,
+ sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+ declEntity->publicId = NULL;
+ }
+ /* fall through */
+#endif /* XML_DTD */
+ case XML_ROLE_ENTITY_SYSTEM_ID:
+ if (dtd->keepProcessing && declEntity) {
+ declEntity->systemId = poolStoreString(&dtd->pool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!declEntity->systemId)
+ return XML_ERROR_NO_MEMORY;
+ declEntity->base = curBase;
+ poolFinish(&dtd->pool);
+ if (entityDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_ENTITY_COMPLETE:
+ if (dtd->keepProcessing && declEntity && entityDeclHandler) {
+ *eventEndPP = s;
+ entityDeclHandler(handlerArg,
+ declEntity->name,
+ declEntity->is_param,
+ 0,0,
+ declEntity->base,
+ declEntity->systemId,
+ declEntity->publicId,
+ 0);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_ENTITY_NOTATION_NAME:
+ if (dtd->keepProcessing && declEntity) {
+ declEntity->notation = poolStoreString(&dtd->pool, enc, s, next);
+ if (!declEntity->notation)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&dtd->pool);
+ if (unparsedEntityDeclHandler) {
+ *eventEndPP = s;
+ unparsedEntityDeclHandler(handlerArg,
+ declEntity->name,
+ declEntity->base,
+ declEntity->systemId,
+ declEntity->publicId,
+ declEntity->notation);
+ handleDefault = XML_FALSE;
+ }
+ else if (entityDeclHandler) {
+ *eventEndPP = s;
+ entityDeclHandler(handlerArg,
+ declEntity->name,
+ 0,0,0,
+ declEntity->base,
+ declEntity->systemId,
+ declEntity->publicId,
+ declEntity->notation);
+ handleDefault = XML_FALSE;
+ }
+ }
+ break;
+ case XML_ROLE_GENERAL_ENTITY_NAME:
+ {
+ if (XmlPredefinedEntityName(enc, s, next)) {
+ declEntity = NULL;
+ break;
+ }
+ if (dtd->keepProcessing) {
+ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ declEntity = (ENTITY *)lookup(&dtd->generalEntities, name,
+ sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+ if (declEntity->name != name) {
+ poolDiscard(&dtd->pool);
+ declEntity = NULL;
+ }
+ else {
+ poolFinish(&dtd->pool);
+ declEntity->publicId = NULL;
+ declEntity->is_param = XML_FALSE;
+ /* if we have a parent parser or are reading an internal parameter
+ entity, then the entity declaration is not considered "internal"
+ */
+ declEntity->is_internal = !(parentParser || openInternalEntities);
+ if (entityDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ }
+ else {
+ poolDiscard(&dtd->pool);
+ declEntity = NULL;
+ }
+ }
+ break;
+ case XML_ROLE_PARAM_ENTITY_NAME:
+#ifdef XML_DTD
+ if (dtd->keepProcessing) {
+ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ declEntity = (ENTITY *)lookup(&dtd->paramEntities,
+ name, sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+ if (declEntity->name != name) {
+ poolDiscard(&dtd->pool);
+ declEntity = NULL;
+ }
+ else {
+ poolFinish(&dtd->pool);
+ declEntity->publicId = NULL;
+ declEntity->is_param = XML_TRUE;
+ /* if we have a parent parser or are reading an internal parameter
+ entity, then the entity declaration is not considered "internal"
+ */
+ declEntity->is_internal = !(parentParser || openInternalEntities);
+ if (entityDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ }
+ else {
+ poolDiscard(&dtd->pool);
+ declEntity = NULL;
+ }
+#else /* not XML_DTD */
+ declEntity = NULL;
+#endif /* XML_DTD */
+ break;
+ case XML_ROLE_NOTATION_NAME:
+ declNotationPublicId = NULL;
+ declNotationName = NULL;
+ if (notationDeclHandler) {
+ declNotationName = poolStoreString(&tempPool, enc, s, next);
+ if (!declNotationName)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_NOTATION_PUBLIC_ID:
+ if (!XmlIsPublicId(enc, s, next, eventPP))
+ return XML_ERROR_PUBLICID;
+ if (declNotationName) { /* means notationDeclHandler != NULL */
+ XML_Char *tem = poolStoreString(&tempPool,
+ enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!tem)
+ return XML_ERROR_NO_MEMORY;
+ normalizePublicId(tem);
+ declNotationPublicId = tem;
+ poolFinish(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_NOTATION_SYSTEM_ID:
+ if (declNotationName && notationDeclHandler) {
+ const XML_Char *systemId
+ = poolStoreString(&tempPool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!systemId)
+ return XML_ERROR_NO_MEMORY;
+ *eventEndPP = s;
+ notationDeclHandler(handlerArg,
+ declNotationName,
+ curBase,
+ systemId,
+ declNotationPublicId);
+ handleDefault = XML_FALSE;
+ }
+ poolClear(&tempPool);
+ break;
+ case XML_ROLE_NOTATION_NO_SYSTEM_ID:
+ if (declNotationPublicId && notationDeclHandler) {
+ *eventEndPP = s;
+ notationDeclHandler(handlerArg,
+ declNotationName,
+ curBase,
+ 0,
+ declNotationPublicId);
+ handleDefault = XML_FALSE;
+ }
+ poolClear(&tempPool);
+ break;
+ case XML_ROLE_ERROR:
+ switch (tok) {
+ case XML_TOK_PARAM_ENTITY_REF:
+ /* PE references in internal subset are
+ not allowed within declarations. */
+ return XML_ERROR_PARAM_ENTITY_REF;
+ case XML_TOK_XML_DECL:
+ return XML_ERROR_MISPLACED_XML_PI;
+ default:
+ return XML_ERROR_SYNTAX;
+ }
+#ifdef XML_DTD
+ case XML_ROLE_IGNORE_SECT:
+ {
+ enum XML_Error result;
+ if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ handleDefault = XML_FALSE;
+ result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore);
+ if (result != XML_ERROR_NONE)
+ return result;
+ else if (!next) {
+ processor = ignoreSectionProcessor;
+ return result;
+ }
+ }
+ break;
+#endif /* XML_DTD */
+ case XML_ROLE_GROUP_OPEN:
+ if (prologState.level >= groupSize) {
+ if (groupSize) {
+ char *temp = (char *)REALLOC(groupConnector, groupSize *= 2);
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ groupConnector = temp;
+ if (dtd->scaffIndex) {
+ int *temp = (int *)REALLOC(dtd->scaffIndex,
+ groupSize * sizeof(int));
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ dtd->scaffIndex = temp;
+ }
+ }
+ else {
+ groupConnector = (char *)MALLOC(groupSize = 32);
+ if (!groupConnector)
+ return XML_ERROR_NO_MEMORY;
+ }
+ }
+ groupConnector[prologState.level] = 0;
+ if (dtd->in_eldecl) {
+ int myindex = nextScaffoldPart(parser);
+ if (myindex < 0)
+ return XML_ERROR_NO_MEMORY;
+ dtd->scaffIndex[dtd->scaffLevel] = myindex;
+ dtd->scaffLevel++;
+ dtd->scaffold[myindex].type = XML_CTYPE_SEQ;
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_GROUP_SEQUENCE:
+ if (groupConnector[prologState.level] == '|')
+ return XML_ERROR_SYNTAX;
+ groupConnector[prologState.level] = ',';
+ if (dtd->in_eldecl && elementDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_GROUP_CHOICE:
+ if (groupConnector[prologState.level] == ',')
+ return XML_ERROR_SYNTAX;
+ if (dtd->in_eldecl
+ && !groupConnector[prologState.level]
+ && (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+ != XML_CTYPE_MIXED)
+ ) {
+ dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+ = XML_CTYPE_CHOICE;
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ groupConnector[prologState.level] = '|';
+ break;
+ case XML_ROLE_PARAM_ENTITY_REF:
+#ifdef XML_DTD
+ case XML_ROLE_INNER_PARAM_ENTITY_REF:
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (!paramEntityParsing)
+ dtd->keepProcessing = dtd->standalone;
+ else {
+ const XML_Char *name;
+ ENTITY *entity;
+ name = poolStoreString(&dtd->pool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0);
+ poolDiscard(&dtd->pool);
+ /* first, determine if a check for an existing declaration is needed;
+ if yes, check that the entity exists, and that it is internal,
+ otherwise call the skipped entity handler
+ */
+ if (prologState.documentEntity &&
+ (dtd->standalone
+ ? !openInternalEntities
+ : !dtd->hasParamEntityRefs)) {
+ if (!entity)
+ return XML_ERROR_UNDEFINED_ENTITY;
+ else if (!entity->is_internal)
+ return XML_ERROR_ENTITY_DECLARED_IN_PE;
+ }
+ else if (!entity) {
+ dtd->keepProcessing = dtd->standalone;
+ /* cannot report skipped entities in declarations */
+ if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) {
+ skippedEntityHandler(handlerArg, name, 1);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ }
+ if (entity->open)
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
+ if (entity->textPtr) {
+ enum XML_Error result;
+ XML_Bool betweenDecl =
+ (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
+ result = processInternalEntity(parser, entity, betweenDecl);
+ if (result != XML_ERROR_NONE)
+ return result;
+ handleDefault = XML_FALSE;
+ break;
+ }
+ if (externalEntityRefHandler) {
+ dtd->paramEntityRead = XML_FALSE;
+ entity->open = XML_TRUE;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ 0,
+ entity->base,
+ entity->systemId,
+ entity->publicId)) {
+ entity->open = XML_FALSE;
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ }
+ entity->open = XML_FALSE;
+ handleDefault = XML_FALSE;
+ if (!dtd->paramEntityRead) {
+ dtd->keepProcessing = dtd->standalone;
+ break;
+ }
+ }
+ else {
+ dtd->keepProcessing = dtd->standalone;
+ break;
+ }
+ }
+#endif /* XML_DTD */
+ if (!dtd->standalone &&
+ notStandaloneHandler &&
+ !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+ break;
+
+ /* Element declaration stuff */
+
+ case XML_ROLE_ELEMENT_NAME:
+ if (elementDeclHandler) {
+ declElementType = getElementType(parser, enc, s, next);
+ if (!declElementType)
+ return XML_ERROR_NO_MEMORY;
+ dtd->scaffLevel = 0;
+ dtd->scaffCount = 0;
+ dtd->in_eldecl = XML_TRUE;
+ handleDefault = XML_FALSE;
+ }
+ break;
+
+ case XML_ROLE_CONTENT_ANY:
+ case XML_ROLE_CONTENT_EMPTY:
+ if (dtd->in_eldecl) {
+ if (elementDeclHandler) {
+ XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content));
+ if (!content)
+ return XML_ERROR_NO_MEMORY;
+ content->quant = XML_CQUANT_NONE;
+ content->name = NULL;
+ content->numchildren = 0;
+ content->children = NULL;
+ content->type = ((role == XML_ROLE_CONTENT_ANY) ?
+ XML_CTYPE_ANY :
+ XML_CTYPE_EMPTY);
+ *eventEndPP = s;
+ elementDeclHandler(handlerArg, declElementType->name, content);
+ handleDefault = XML_FALSE;
+ }
+ dtd->in_eldecl = XML_FALSE;
+ }
+ break;
+
+ case XML_ROLE_CONTENT_PCDATA:
+ if (dtd->in_eldecl) {
+ dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+ = XML_CTYPE_MIXED;
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+
+ case XML_ROLE_CONTENT_ELEMENT:
+ quant = XML_CQUANT_NONE;
+ goto elementContent;
+ case XML_ROLE_CONTENT_ELEMENT_OPT:
+ quant = XML_CQUANT_OPT;
+ goto elementContent;
+ case XML_ROLE_CONTENT_ELEMENT_REP:
+ quant = XML_CQUANT_REP;
+ goto elementContent;
+ case XML_ROLE_CONTENT_ELEMENT_PLUS:
+ quant = XML_CQUANT_PLUS;
+ elementContent:
+ if (dtd->in_eldecl) {
+ ELEMENT_TYPE *el;
+ const XML_Char *name;
+ int nameLen;
+ const char *nxt = (quant == XML_CQUANT_NONE
+ ? next
+ : next - enc->minBytesPerChar);
+ int myindex = nextScaffoldPart(parser);
+ if (myindex < 0)
+ return XML_ERROR_NO_MEMORY;
+ dtd->scaffold[myindex].type = XML_CTYPE_NAME;
+ dtd->scaffold[myindex].quant = quant;
+ el = getElementType(parser, enc, s, nxt);
+ if (!el)
+ return XML_ERROR_NO_MEMORY;
+ name = el->name;
+ dtd->scaffold[myindex].name = name;
+ nameLen = 0;
+ for (; name[nameLen++]; );
+ dtd->contentStringLen += nameLen;
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+
+ case XML_ROLE_GROUP_CLOSE:
+ quant = XML_CQUANT_NONE;
+ goto closeGroup;
+ case XML_ROLE_GROUP_CLOSE_OPT:
+ quant = XML_CQUANT_OPT;
+ goto closeGroup;
+ case XML_ROLE_GROUP_CLOSE_REP:
+ quant = XML_CQUANT_REP;
+ goto closeGroup;
+ case XML_ROLE_GROUP_CLOSE_PLUS:
+ quant = XML_CQUANT_PLUS;
+ closeGroup:
+ if (dtd->in_eldecl) {
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ dtd->scaffLevel--;
+ dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant;
+ if (dtd->scaffLevel == 0) {
+ if (!handleDefault) {
+ XML_Content *model = build_model(parser);
+ if (!model)
+ return XML_ERROR_NO_MEMORY;
+ *eventEndPP = s;
+ elementDeclHandler(handlerArg, declElementType->name, model);
+ }
+ dtd->in_eldecl = XML_FALSE;
+ dtd->contentStringLen = 0;
+ }
+ }
+ break;
+ /* End element declaration stuff */
+
+ case XML_ROLE_PI:
+ if (!reportProcessingInstruction(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_COMMENT:
+ if (!reportComment(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_NONE:
+ switch (tok) {
+ case XML_TOK_BOM:
+ handleDefault = XML_FALSE;
+ break;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_NONE:
+ if (startDoctypeDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_ENTITY_NONE:
+ if (dtd->keepProcessing && entityDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_NOTATION_NONE:
+ if (notationDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_ATTLIST_NONE:
+ if (dtd->keepProcessing && attlistDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_ELEMENT_NONE:
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ } /* end of big switch */
+
+ if (handleDefault && defaultHandler)
+ reportDefault(parser, enc, s, next);
+
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default:
+ s = next;
+ tok = XmlPrologTok(enc, s, end, &next);
+ }
+ }
+ /* not reached */
+}
+
+static enum XML_Error PTRCALL
+epilogProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ processor = epilogProcessor;
+ eventPtr = s;
+ for (;;) {
+ const char *next = NULL;
+ int tok = XmlPrologTok(encoding, s, end, &next);
+ eventEndPtr = next;
+ switch (tok) {
+ /* report partial linebreak - it might be the last token */
+ case -XML_TOK_PROLOG_S:
+ if (defaultHandler) {
+ reportDefault(parser, encoding, s, next);
+ if (ps_parsing == XML_FINISHED)
+ return XML_ERROR_ABORTED;
+ }
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_TOK_NONE:
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ case XML_TOK_PROLOG_S:
+ if (defaultHandler)
+ reportDefault(parser, encoding, s, next);
+ break;
+ case XML_TOK_PI:
+ if (!reportProcessingInstruction(parser, encoding, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_COMMENT:
+ if (!reportComment(parser, encoding, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_INVALID:
+ eventPtr = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ if (!ps_finalBuffer) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (!ps_finalBuffer) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ default:
+ return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
+ }
+ eventPtr = s = next;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default: ;
+ }
+ }
+}
+
+static enum XML_Error
+processInternalEntity(XML_Parser parser, ENTITY *entity,
+ XML_Bool betweenDecl)
+{
+ const char *textStart, *textEnd;
+ const char *next;
+ enum XML_Error result;
+ OPEN_INTERNAL_ENTITY *openEntity;
+
+ if (freeInternalEntities) {
+ openEntity = freeInternalEntities;
+ freeInternalEntities = openEntity->next;
+ }
+ else {
+ openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY));
+ if (!openEntity)
+ return XML_ERROR_NO_MEMORY;
+ }
+ entity->open = XML_TRUE;
+ entity->processed = 0;
+ openEntity->next = openInternalEntities;
+ openInternalEntities = openEntity;
+ openEntity->entity = entity;
+ openEntity->startTagLevel = tagLevel;
+ openEntity->betweenDecl = betweenDecl;
+ openEntity->internalEventPtr = NULL;
+ openEntity->internalEventEndPtr = NULL;
+ textStart = (char *)entity->textPtr;
+ textEnd = (char *)(entity->textPtr + entity->textLen);
+
+#ifdef XML_DTD
+ if (entity->is_param) {
+ int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
+ result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+ next, &next, XML_FALSE);
+ }
+ else
+#endif /* XML_DTD */
+ result = doContent(parser, tagLevel, internalEncoding, textStart,
+ textEnd, &next, XML_FALSE);
+
+ if (result == XML_ERROR_NONE) {
+ if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+ entity->processed = (int)(next - textStart);
+ processor = internalEntityProcessor;
+ }
+ else {
+ entity->open = XML_FALSE;
+ openInternalEntities = openEntity->next;
+ /* put openEntity back in list of free instances */
+ openEntity->next = freeInternalEntities;
+ freeInternalEntities = openEntity;
+ }
+ }
+ return result;
+}
+
+static enum XML_Error PTRCALL
+internalEntityProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ ENTITY *entity;
+ const char *textStart, *textEnd;
+ const char *next;
+ enum XML_Error result;
+ OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities;
+ if (!openEntity)
+ return XML_ERROR_UNEXPECTED_STATE;
+
+ entity = openEntity->entity;
+ textStart = ((char *)entity->textPtr) + entity->processed;
+ textEnd = (char *)(entity->textPtr + entity->textLen);
+
+#ifdef XML_DTD
+ if (entity->is_param) {
+ int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
+ result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+ next, &next, XML_FALSE);
+ }
+ else
+#endif /* XML_DTD */
+ result = doContent(parser, openEntity->startTagLevel, internalEncoding,
+ textStart, textEnd, &next, XML_FALSE);
+
+ if (result != XML_ERROR_NONE)
+ return result;
+ else if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+ entity->processed = (int)(next - (char *)entity->textPtr);
+ return result;
+ }
+ else {
+ entity->open = XML_FALSE;
+ openInternalEntities = openEntity->next;
+ /* put openEntity back in list of free instances */
+ openEntity->next = freeInternalEntities;
+ freeInternalEntities = openEntity;
+ }
+
+#ifdef XML_DTD
+ if (entity->is_param) {
+ int tok;
+ processor = prologProcessor;
+ tok = XmlPrologTok(encoding, s, end, &next);
+ return doProlog(parser, encoding, s, end, tok, next, nextPtr,
+ (XML_Bool)!ps_finalBuffer);
+ }
+ else
+#endif /* XML_DTD */
+ {
+ processor = contentProcessor;
+ /* see externalEntityContentProcessor vs contentProcessor */
+ return doContent(parser, parentParser ? 1 : 0, encoding, s, end,
+ nextPtr, (XML_Bool)!ps_finalBuffer);
+ }
+}
+
+static enum XML_Error PTRCALL
+errorProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ return errorCode;
+}
+
+static enum XML_Error
+storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+ const char *ptr, const char *end,
+ STRING_POOL *pool)
+{
+ enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr,
+ end, pool);
+ if (result)
+ return result;
+ if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
+ poolChop(pool);
+ if (!poolAppendChar(pool, XML_T('\0')))
+ return XML_ERROR_NO_MEMORY;
+ return XML_ERROR_NONE;
+}
+
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+ const char *ptr, const char *end,
+ STRING_POOL *pool)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ for (;;) {
+ const char *next;
+ int tok = XmlAttributeValueTok(enc, ptr, end, &next);
+ switch (tok) {
+ case XML_TOK_NONE:
+ return XML_ERROR_NONE;
+ case XML_TOK_INVALID:
+ if (enc == encoding)
+ eventPtr = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_CHAR_REF:
+ {
+ XML_Char buf[XML_ENCODE_MAX];
+ int i;
+ int n = XmlCharRefNumber(enc, ptr);
+ if (n < 0) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_BAD_CHAR_REF;
+ }
+ if (!isCdata
+ && n == 0x20 /* space */
+ && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+ break;
+ n = XmlEncode(n, (ICHAR *)buf);
+ if (!n) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_BAD_CHAR_REF;
+ }
+ for (i = 0; i < n; i++) {
+ if (!poolAppendChar(pool, buf[i]))
+ return XML_ERROR_NO_MEMORY;
+ }
+ }
+ break;
+ case XML_TOK_DATA_CHARS:
+ if (!poolAppend(pool, enc, ptr, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_TRAILING_CR:
+ next = ptr + enc->minBytesPerChar;
+ /* fall through */
+ case XML_TOK_ATTRIBUTE_VALUE_S:
+ case XML_TOK_DATA_NEWLINE:
+ if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+ break;
+ if (!poolAppendChar(pool, 0x20))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_ENTITY_REF:
+ {
+ const XML_Char *name;
+ ENTITY *entity;
+ char checkEntityDecl;
+ XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
+ ptr + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (ch) {
+ if (!poolAppendChar(pool, ch))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ }
+ name = poolStoreString(&temp2Pool, enc,
+ ptr + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(&dtd->generalEntities, name, 0);
+ poolDiscard(&temp2Pool);
+ /* First, determine if a check for an existing declaration is needed;
+ if yes, check that the entity exists, and that it is internal.
+ */
+ if (pool == &dtd->pool) /* are we called from prolog? */
+ checkEntityDecl =
+#ifdef XML_DTD
+ prologState.documentEntity &&
+#endif /* XML_DTD */
+ (dtd->standalone
+ ? !openInternalEntities
+ : !dtd->hasParamEntityRefs);
+ else /* if (pool == &tempPool): we are called from content */
+ checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone;
+ if (checkEntityDecl) {
+ if (!entity)
+ return XML_ERROR_UNDEFINED_ENTITY;
+ else if (!entity->is_internal)
+ return XML_ERROR_ENTITY_DECLARED_IN_PE;
+ }
+ else if (!entity) {
+ /* Cannot report skipped entity here - see comments on
+ skippedEntityHandler.
+ if (skippedEntityHandler)
+ skippedEntityHandler(handlerArg, name, 0);
+ */
+ /* Cannot call the default handler because this would be
+ out of sync with the call to the startElementHandler.
+ if ((pool == &tempPool) && defaultHandler)
+ reportDefault(parser, enc, ptr, next);
+ */
+ break;
+ }
+ if (entity->open) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
+ }
+ if (entity->notation) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_BINARY_ENTITY_REF;
+ }
+ if (!entity->textPtr) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
+ }
+ else {
+ enum XML_Error result;
+ const XML_Char *textEnd = entity->textPtr + entity->textLen;
+ entity->open = XML_TRUE;
+ result = appendAttributeValue(parser, internalEncoding, isCdata,
+ (char *)entity->textPtr,
+ (char *)textEnd, pool);
+ entity->open = XML_FALSE;
+ if (result)
+ return result;
+ }
+ }
+ break;
+ default:
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_UNEXPECTED_STATE;
+ }
+ ptr = next;
+ }
+ /* not reached */
+}
+
+static enum XML_Error
+storeEntityValue(XML_Parser parser,
+ const ENCODING *enc,
+ const char *entityTextPtr,
+ const char *entityTextEnd)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ STRING_POOL *pool = &(dtd->entityValuePool);
+ enum XML_Error result = XML_ERROR_NONE;
+#ifdef XML_DTD
+ int oldInEntityValue = prologState.inEntityValue;
+ prologState.inEntityValue = 1;
+#endif /* XML_DTD */
+ /* never return Null for the value argument in EntityDeclHandler,
+ since this would indicate an external entity; therefore we
+ have to make sure that entityValuePool.start is not null */
+ if (!pool->blocks) {
+ if (!poolGrow(pool))
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ for (;;) {
+ const char *next;
+ int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
+ switch (tok) {
+ case XML_TOK_PARAM_ENTITY_REF:
+#ifdef XML_DTD
+ if (isParamEntity || enc != encoding) {
+ const XML_Char *name;
+ ENTITY *entity;
+ name = poolStoreString(&tempPool, enc,
+ entityTextPtr + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
+ }
+ entity = (ENTITY *)lookup(&dtd->paramEntities, name, 0);
+ poolDiscard(&tempPool);
+ if (!entity) {
+ /* not a well-formedness error - see XML 1.0: WFC Entity Declared */
+ /* cannot report skipped entity here - see comments on
+ skippedEntityHandler
+ if (skippedEntityHandler)
+ skippedEntityHandler(handlerArg, name, 0);
+ */
+ dtd->keepProcessing = dtd->standalone;
+ goto endEntityValue;
+ }
+ if (entity->open) {
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_RECURSIVE_ENTITY_REF;
+ goto endEntityValue;
+ }
+ if (entity->systemId) {
+ if (externalEntityRefHandler) {
+ dtd->paramEntityRead = XML_FALSE;
+ entity->open = XML_TRUE;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ 0,
+ entity->base,
+ entity->systemId,
+ entity->publicId)) {
+ entity->open = XML_FALSE;
+ result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ goto endEntityValue;
+ }
+ entity->open = XML_FALSE;
+ if (!dtd->paramEntityRead)
+ dtd->keepProcessing = dtd->standalone;
+ }
+ else
+ dtd->keepProcessing = dtd->standalone;
+ }
+ else {
+ entity->open = XML_TRUE;
+ result = storeEntityValue(parser,
+ internalEncoding,
+ (char *)entity->textPtr,
+ (char *)(entity->textPtr
+ + entity->textLen));
+ entity->open = XML_FALSE;
+ if (result)
+ goto endEntityValue;
+ }
+ break;
+ }
+#endif /* XML_DTD */
+ /* In the internal subset, PE references are not legal
+ within markup declarations, e.g entity values in this case. */
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_PARAM_ENTITY_REF;
+ goto endEntityValue;
+ case XML_TOK_NONE:
+ result = XML_ERROR_NONE;
+ goto endEntityValue;
+ case XML_TOK_ENTITY_REF:
+ case XML_TOK_DATA_CHARS:
+ if (!poolAppend(pool, enc, entityTextPtr, next)) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
+ }
+ break;
+ case XML_TOK_TRAILING_CR:
+ next = entityTextPtr + enc->minBytesPerChar;
+ /* fall through */
+ case XML_TOK_DATA_NEWLINE:
+ if (pool->end == pool->ptr && !poolGrow(pool)) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
+ }
+ *(pool->ptr)++ = 0xA;
+ break;
+ case XML_TOK_CHAR_REF:
+ {
+ XML_Char buf[XML_ENCODE_MAX];
+ int i;
+ int n = XmlCharRefNumber(enc, entityTextPtr);
+ if (n < 0) {
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_BAD_CHAR_REF;
+ goto endEntityValue;
+ }
+ n = XmlEncode(n, (ICHAR *)buf);
+ if (!n) {
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_BAD_CHAR_REF;
+ goto endEntityValue;
+ }
+ for (i = 0; i < n; i++) {
+ if (pool->end == pool->ptr && !poolGrow(pool)) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
+ }
+ *(pool->ptr)++ = buf[i];
+ }
+ }
+ break;
+ case XML_TOK_PARTIAL:
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_INVALID_TOKEN;
+ goto endEntityValue;
+ case XML_TOK_INVALID:
+ if (enc == encoding)
+ eventPtr = next;
+ result = XML_ERROR_INVALID_TOKEN;
+ goto endEntityValue;
+ default:
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_UNEXPECTED_STATE;
+ goto endEntityValue;
+ }
+ entityTextPtr = next;
+ }
+endEntityValue:
+#ifdef XML_DTD
+ prologState.inEntityValue = oldInEntityValue;
+#endif /* XML_DTD */
+ return result;
+}
+
+static void FASTCALL
+normalizeLines(XML_Char *s)
+{
+ XML_Char *p;
+ for (;; s++) {
+ if (*s == XML_T('\0'))
+ return;
+ if (*s == 0xD)
+ break;
+ }
+ p = s;
+ do {
+ if (*s == 0xD) {
+ *p++ = 0xA;
+ if (*++s == 0xA)
+ s++;
+ }
+ else
+ *p++ = *s++;
+ } while (*s);
+ *p = XML_T('\0');
+}
+
+static int
+reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end)
+{
+ const XML_Char *target;
+ XML_Char *data;
+ const char *tem;
+ if (!processingInstructionHandler) {
+ if (defaultHandler)
+ reportDefault(parser, enc, start, end);
+ return 1;
+ }
+ start += enc->minBytesPerChar * 2;
+ tem = start + XmlNameLength(enc, start);
+ target = poolStoreString(&tempPool, enc, start, tem);
+ if (!target)
+ return 0;
+ poolFinish(&tempPool);
+ data = poolStoreString(&tempPool, enc,
+ XmlSkipS(enc, tem),
+ end - enc->minBytesPerChar*2);
+ if (!data)
+ return 0;
+ normalizeLines(data);
+ processingInstructionHandler(handlerArg, target, data);
+ poolClear(&tempPool);
+ return 1;
+}
+
+static int
+reportComment(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end)
+{
+ XML_Char *data;
+ if (!commentHandler) {
+ if (defaultHandler)
+ reportDefault(parser, enc, start, end);
+ return 1;
+ }
+ data = poolStoreString(&tempPool,
+ enc,
+ start + enc->minBytesPerChar * 4,
+ end - enc->minBytesPerChar * 3);
+ if (!data)
+ return 0;
+ normalizeLines(data);
+ commentHandler(handlerArg, data);
+ poolClear(&tempPool);
+ return 1;
+}
+
+static void
+reportDefault(XML_Parser parser, const ENCODING *enc,
+ const char *s, const char *end)
+{
+ if (MUST_CONVERT(enc, s)) {
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ do {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+ *eventEndPP = s;
+ defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf));
+ *eventPP = s;
+ } while (s != end);
+ }
+ else
+ defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
+}
+
+
+static int
+defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
+ XML_Bool isId, const XML_Char *value, XML_Parser parser)
+{
+ DEFAULT_ATTRIBUTE *att;
+ if (value || isId) {
+ /* The handling of default attributes gets messed up if we have
+ a default which duplicates a non-default. */
+ int i;
+ for (i = 0; i < type->nDefaultAtts; i++)
+ if (attId == type->defaultAtts[i].id)
+ return 1;
+ if (isId && !type->idAtt && !attId->xmlns)
+ type->idAtt = attId;
+ }
+ if (type->nDefaultAtts == type->allocDefaultAtts) {
+ if (type->allocDefaultAtts == 0) {
+ type->allocDefaultAtts = 8;
+ type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts
+ * sizeof(DEFAULT_ATTRIBUTE));
+ if (!type->defaultAtts)
+ return 0;
+ }
+ else {
+ DEFAULT_ATTRIBUTE *temp;
+ int count = type->allocDefaultAtts * 2;
+ temp = (DEFAULT_ATTRIBUTE *)
+ REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE)));
+ if (temp == NULL)
+ return 0;
+ type->allocDefaultAtts = count;
+ type->defaultAtts = temp;
+ }
+ }
+ att = type->defaultAtts + type->nDefaultAtts;
+ att->id = attId;
+ att->value = value;
+ att->isCdata = isCdata;
+ if (!isCdata)
+ attId->maybeTokenized = XML_TRUE;
+ type->nDefaultAtts += 1;
+ return 1;
+}
+
+static int
+setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ const XML_Char *name;
+ for (name = elementType->name; *name; name++) {
+ if (*name == XML_T(':')) {
+ PREFIX *prefix;
+ const XML_Char *s;
+ for (s = elementType->name; s != name; s++) {
+ if (!poolAppendChar(&dtd->pool, *s))
+ return 0;
+ }
+ if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+ return 0;
+ prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool),
+ sizeof(PREFIX));
+ if (!prefix)
+ return 0;
+ if (prefix->name == poolStart(&dtd->pool))
+ poolFinish(&dtd->pool);
+ else
+ poolDiscard(&dtd->pool);
+ elementType->prefix = prefix;
+
+ }
+ }
+ return 1;
+}
+
+static ATTRIBUTE_ID *
+getAttributeId(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ ATTRIBUTE_ID *id;
+ const XML_Char *name;
+ if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+ return NULL;
+ name = poolStoreString(&dtd->pool, enc, start, end);
+ if (!name)
+ return NULL;
+ /* skip quotation mark - its storage will be re-used (like in name[-1]) */
+ ++name;
+ id = (ATTRIBUTE_ID *)lookup(&dtd->attributeIds, name, sizeof(ATTRIBUTE_ID));
+ if (!id)
+ return NULL;
+ if (id->name != name)
+ poolDiscard(&dtd->pool);
+ else {
+ poolFinish(&dtd->pool);
+ if (!ns)
+ ;
+ else if (name[0] == XML_T('x')
+ && name[1] == XML_T('m')
+ && name[2] == XML_T('l')
+ && name[3] == XML_T('n')
+ && name[4] == XML_T('s')
+ && (name[5] == XML_T('\0') || name[5] == XML_T(':'))) {
+ if (name[5] == XML_T('\0'))
+ id->prefix = &dtd->defaultPrefix;
+ else
+ id->prefix = (PREFIX *)lookup(&dtd->prefixes, name + 6, sizeof(PREFIX));
+ id->xmlns = XML_TRUE;
+ }
+ else {
+ int i;
+ for (i = 0; name[i]; i++) {
+ /* attributes without prefix are *not* in the default namespace */
+ if (name[i] == XML_T(':')) {
+ int j;
+ for (j = 0; j < i; j++) {
+ if (!poolAppendChar(&dtd->pool, name[j]))
+ return NULL;
+ }
+ if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+ return NULL;
+ id->prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&dtd->pool),
+ sizeof(PREFIX));
+ if (id->prefix->name == poolStart(&dtd->pool))
+ poolFinish(&dtd->pool);
+ else
+ poolDiscard(&dtd->pool);
+ break;
+ }
+ }
+ }
+ }
+ return id;
+}
+
+#define CONTEXT_SEP XML_T('\f')
+
+static const XML_Char *
+getContext(XML_Parser parser)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ HASH_TABLE_ITER iter;
+ XML_Bool needSep = XML_FALSE;
+
+ if (dtd->defaultPrefix.binding) {
+ int i;
+ int len;
+ if (!poolAppendChar(&tempPool, XML_T('=')))
+ return NULL;
+ len = dtd->defaultPrefix.binding->uriLen;
+ if (namespaceSeparator)
+ len--;
+ for (i = 0; i < len; i++)
+ if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i]))
+ return NULL;
+ needSep = XML_TRUE;
+ }
+
+ hashTableIterInit(&iter, &(dtd->prefixes));
+ for (;;) {
+ int i;
+ int len;
+ const XML_Char *s;
+ PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter);
+ if (!prefix)
+ break;
+ if (!prefix->binding)
+ continue;
+ if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ return NULL;
+ for (s = prefix->name; *s; s++)
+ if (!poolAppendChar(&tempPool, *s))
+ return NULL;
+ if (!poolAppendChar(&tempPool, XML_T('=')))
+ return NULL;
+ len = prefix->binding->uriLen;
+ if (namespaceSeparator)
+ len--;
+ for (i = 0; i < len; i++)
+ if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
+ return NULL;
+ needSep = XML_TRUE;
+ }
+
+
+ hashTableIterInit(&iter, &(dtd->generalEntities));
+ for (;;) {
+ const XML_Char *s;
+ ENTITY *e = (ENTITY *)hashTableIterNext(&iter);
+ if (!e)
+ break;
+ if (!e->open)
+ continue;
+ if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ return NULL;
+ for (s = e->name; *s; s++)
+ if (!poolAppendChar(&tempPool, *s))
+ return 0;
+ needSep = XML_TRUE;
+ }
+
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return NULL;
+ return tempPool.start;
+}
+
+static XML_Bool
+setContext(XML_Parser parser, const XML_Char *context)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ const XML_Char *s = context;
+
+ while (*context != XML_T('\0')) {
+ if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
+ ENTITY *e;
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_FALSE;
+ e = (ENTITY *)lookup(&dtd->generalEntities, poolStart(&tempPool), 0);
+ if (e)
+ e->open = XML_TRUE;
+ if (*s != XML_T('\0'))
+ s++;
+ context = s;
+ poolDiscard(&tempPool);
+ }
+ else if (*s == XML_T('=')) {
+ PREFIX *prefix;
+ if (poolLength(&tempPool) == 0)
+ prefix = &dtd->defaultPrefix;
+ else {
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_FALSE;
+ prefix = (PREFIX *)lookup(&dtd->prefixes, poolStart(&tempPool),
+ sizeof(PREFIX));
+ if (!prefix)
+ return XML_FALSE;
+ if (prefix->name == poolStart(&tempPool)) {
+ prefix->name = poolCopyString(&dtd->pool, prefix->name);
+ if (!prefix->name)
+ return XML_FALSE;
+ }
+ poolDiscard(&tempPool);
+ }
+ for (context = s + 1;
+ *context != CONTEXT_SEP && *context != XML_T('\0');
+ context++)
+ if (!poolAppendChar(&tempPool, *context))
+ return XML_FALSE;
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_FALSE;
+ if (addBinding(parser, prefix, NULL, poolStart(&tempPool),
+ &inheritedBindings) != XML_ERROR_NONE)
+ return XML_FALSE;
+ poolDiscard(&tempPool);
+ if (*context != XML_T('\0'))
+ ++context;
+ s = context;
+ }
+ else {
+ if (!poolAppendChar(&tempPool, *s))
+ return XML_FALSE;
+ s++;
+ }
+ }
+ return XML_TRUE;
+}
+
+static void FASTCALL
+normalizePublicId(XML_Char *publicId)
+{
+ XML_Char *p = publicId;
+ XML_Char *s;
+ for (s = publicId; *s; s++) {
+ switch (*s) {
+ case 0x20:
+ case 0xD:
+ case 0xA:
+ if (p != publicId && p[-1] != 0x20)
+ *p++ = 0x20;
+ break;
+ default:
+ *p++ = *s;
+ }
+ }
+ if (p != publicId && p[-1] == 0x20)
+ --p;
+ *p = XML_T('\0');
+}
+
+static DTD *
+dtdCreate(const XML_Memory_Handling_Suite *ms)
+{
+ DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD));
+ if (p == NULL)
+ return p;
+ poolInit(&(p->pool), ms);
+ poolInit(&(p->entityValuePool), ms);
+ hashTableInit(&(p->generalEntities), ms);
+ hashTableInit(&(p->elementTypes), ms);
+ hashTableInit(&(p->attributeIds), ms);
+ hashTableInit(&(p->prefixes), ms);
+#ifdef XML_DTD
+ p->paramEntityRead = XML_FALSE;
+ hashTableInit(&(p->paramEntities), ms);
+#endif /* XML_DTD */
+ p->defaultPrefix.name = NULL;
+ p->defaultPrefix.binding = NULL;
+
+ p->in_eldecl = XML_FALSE;
+ p->scaffIndex = NULL;
+ p->scaffold = NULL;
+ p->scaffLevel = 0;
+ p->scaffSize = 0;
+ p->scaffCount = 0;
+ p->contentStringLen = 0;
+
+ p->keepProcessing = XML_TRUE;
+ p->hasParamEntityRefs = XML_FALSE;
+ p->standalone = XML_FALSE;
+ return p;
+}
+
+static void
+dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms)
+{
+ HASH_TABLE_ITER iter;
+ hashTableIterInit(&iter, &(p->elementTypes));
+ for (;;) {
+ ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+ if (!e)
+ break;
+ if (e->allocDefaultAtts != 0)
+ ms->free_fcn(e->defaultAtts);
+ }
+ hashTableClear(&(p->generalEntities));
+#ifdef XML_DTD
+ p->paramEntityRead = XML_FALSE;
+ hashTableClear(&(p->paramEntities));
+#endif /* XML_DTD */
+ hashTableClear(&(p->elementTypes));
+ hashTableClear(&(p->attributeIds));
+ hashTableClear(&(p->prefixes));
+ poolClear(&(p->pool));
+ poolClear(&(p->entityValuePool));
+ p->defaultPrefix.name = NULL;
+ p->defaultPrefix.binding = NULL;
+
+ p->in_eldecl = XML_FALSE;
+
+ ms->free_fcn(p->scaffIndex);
+ p->scaffIndex = NULL;
+ ms->free_fcn(p->scaffold);
+ p->scaffold = NULL;
+
+ p->scaffLevel = 0;
+ p->scaffSize = 0;
+ p->scaffCount = 0;
+ p->contentStringLen = 0;
+
+ p->keepProcessing = XML_TRUE;
+ p->hasParamEntityRefs = XML_FALSE;
+ p->standalone = XML_FALSE;
+}
+
+static void
+dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms)
+{
+ HASH_TABLE_ITER iter;
+ hashTableIterInit(&iter, &(p->elementTypes));
+ for (;;) {
+ ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+ if (!e)
+ break;
+ if (e->allocDefaultAtts != 0)
+ ms->free_fcn(e->defaultAtts);
+ }
+ hashTableDestroy(&(p->generalEntities));
+#ifdef XML_DTD
+ hashTableDestroy(&(p->paramEntities));
+#endif /* XML_DTD */
+ hashTableDestroy(&(p->elementTypes));
+ hashTableDestroy(&(p->attributeIds));
+ hashTableDestroy(&(p->prefixes));
+ poolDestroy(&(p->pool));
+ poolDestroy(&(p->entityValuePool));
+ if (isDocEntity) {
+ ms->free_fcn(p->scaffIndex);
+ ms->free_fcn(p->scaffold);
+ }
+ ms->free_fcn(p);
+}
+
+/* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise.
+ The new DTD has already been initialized.
+*/
+static int
+dtdCopy(DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
+{
+ HASH_TABLE_ITER iter;
+
+ /* Copy the prefix table. */
+
+ hashTableIterInit(&iter, &(oldDtd->prefixes));
+ for (;;) {
+ const XML_Char *name;
+ const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter);
+ if (!oldP)
+ break;
+ name = poolCopyString(&(newDtd->pool), oldP->name);
+ if (!name)
+ return 0;
+ if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX)))
+ return 0;
+ }
+
+ hashTableIterInit(&iter, &(oldDtd->attributeIds));
+
+ /* Copy the attribute id table. */
+
+ for (;;) {
+ ATTRIBUTE_ID *newA;
+ const XML_Char *name;
+ const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter);
+
+ if (!oldA)
+ break;
+ /* Remember to allocate the scratch byte before the name. */
+ if (!poolAppendChar(&(newDtd->pool), XML_T('\0')))
+ return 0;
+ name = poolCopyString(&(newDtd->pool), oldA->name);
+ if (!name)
+ return 0;
+ ++name;
+ newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name,
+ sizeof(ATTRIBUTE_ID));
+ if (!newA)
+ return 0;
+ newA->maybeTokenized = oldA->maybeTokenized;
+ if (oldA->prefix) {
+ newA->xmlns = oldA->xmlns;
+ if (oldA->prefix == &oldDtd->defaultPrefix)
+ newA->prefix = &newDtd->defaultPrefix;
+ else
+ newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes),
+ oldA->prefix->name, 0);
+ }
+ }
+
+ /* Copy the element type table. */
+
+ hashTableIterInit(&iter, &(oldDtd->elementTypes));
+
+ for (;;) {
+ int i;
+ ELEMENT_TYPE *newE;
+ const XML_Char *name;
+ const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+ if (!oldE)
+ break;
+ name = poolCopyString(&(newDtd->pool), oldE->name);
+ if (!name)
+ return 0;
+ newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name,
+ sizeof(ELEMENT_TYPE));
+ if (!newE)
+ return 0;
+ if (oldE->nDefaultAtts) {
+ newE->defaultAtts = (DEFAULT_ATTRIBUTE *)
+ ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
+ if (!newE->defaultAtts) {
+ ms->free_fcn(newE);
+ return 0;
+ }
+ }
+ if (oldE->idAtt)
+ newE->idAtt = (ATTRIBUTE_ID *)
+ lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0);
+ newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
+ if (oldE->prefix)
+ newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes),
+ oldE->prefix->name, 0);
+ for (i = 0; i < newE->nDefaultAtts; i++) {
+ newE->defaultAtts[i].id = (ATTRIBUTE_ID *)
+ lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
+ newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
+ if (oldE->defaultAtts[i].value) {
+ newE->defaultAtts[i].value
+ = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value);
+ if (!newE->defaultAtts[i].value)
+ return 0;
+ }
+ else
+ newE->defaultAtts[i].value = NULL;
+ }
+ }
+
+ /* Copy the entity tables. */
+ if (!copyEntityTable(&(newDtd->generalEntities),
+ &(newDtd->pool),
+ &(oldDtd->generalEntities)))
+ return 0;
+
+#ifdef XML_DTD
+ if (!copyEntityTable(&(newDtd->paramEntities),
+ &(newDtd->pool),
+ &(oldDtd->paramEntities)))
+ return 0;
+ newDtd->paramEntityRead = oldDtd->paramEntityRead;
+#endif /* XML_DTD */
+
+ newDtd->keepProcessing = oldDtd->keepProcessing;
+ newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs;
+ newDtd->standalone = oldDtd->standalone;
+
+ /* Don't want deep copying for scaffolding */
+ newDtd->in_eldecl = oldDtd->in_eldecl;
+ newDtd->scaffold = oldDtd->scaffold;
+ newDtd->contentStringLen = oldDtd->contentStringLen;
+ newDtd->scaffSize = oldDtd->scaffSize;
+ newDtd->scaffLevel = oldDtd->scaffLevel;
+ newDtd->scaffIndex = oldDtd->scaffIndex;
+
+ return 1;
+} /* End dtdCopy */
+
+static int
+copyEntityTable(HASH_TABLE *newTable,
+ STRING_POOL *newPool,
+ const HASH_TABLE *oldTable)
+{
+ HASH_TABLE_ITER iter;
+ const XML_Char *cachedOldBase = NULL;
+ const XML_Char *cachedNewBase = NULL;
+
+ hashTableIterInit(&iter, oldTable);
+
+ for (;;) {
+ ENTITY *newE;
+ const XML_Char *name;
+ const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter);
+ if (!oldE)
+ break;
+ name = poolCopyString(newPool, oldE->name);
+ if (!name)
+ return 0;
+ newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY));
+ if (!newE)
+ return 0;
+ if (oldE->systemId) {
+ const XML_Char *tem = poolCopyString(newPool, oldE->systemId);
+ if (!tem)
+ return 0;
+ newE->systemId = tem;
+ if (oldE->base) {
+ if (oldE->base == cachedOldBase)
+ newE->base = cachedNewBase;
+ else {
+ cachedOldBase = oldE->base;
+ tem = poolCopyString(newPool, cachedOldBase);
+ if (!tem)
+ return 0;
+ cachedNewBase = newE->base = tem;
+ }
+ }
+ if (oldE->publicId) {
+ tem = poolCopyString(newPool, oldE->publicId);
+ if (!tem)
+ return 0;
+ newE->publicId = tem;
+ }
+ }
+ else {
+ const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr,
+ oldE->textLen);
+ if (!tem)
+ return 0;
+ newE->textPtr = tem;
+ newE->textLen = oldE->textLen;
+ }
+ if (oldE->notation) {
+ const XML_Char *tem = poolCopyString(newPool, oldE->notation);
+ if (!tem)
+ return 0;
+ newE->notation = tem;
+ }
+ newE->is_param = oldE->is_param;
+ newE->is_internal = oldE->is_internal;
+ }
+ return 1;
+}
+
+#define INIT_POWER 6
+
+static XML_Bool FASTCALL
+keyeq(KEY s1, KEY s2)
+{
+ for (; *s1 == *s2; s1++, s2++)
+ if (*s1 == 0)
+ return XML_TRUE;
+ return XML_FALSE;
+}
+
+static unsigned long FASTCALL
+hash(KEY s)
+{
+ unsigned long h = 0;
+ while (*s)
+ h = CHAR_HASH(h, *s++);
+ return h;
+}
+
+static NAMED *
+lookup(HASH_TABLE *table, KEY name, size_t createSize)
+{
+ size_t i;
+ if (table->size == 0) {
+ size_t tsize;
+ if (!createSize)
+ return NULL;
+ table->power = INIT_POWER;
+ /* table->size is a power of 2 */
+ table->size = (size_t)1 << INIT_POWER;
+ tsize = table->size * sizeof(NAMED *);
+ table->v = (NAMED **)table->mem->malloc_fcn(tsize);
+ if (!table->v) {
+ table->size = 0;
+ return NULL;
+ }
+ memset(table->v, 0, tsize);
+ i = hash(name) & ((unsigned long)table->size - 1);
+ }
+ else {
+ unsigned long h = hash(name);
+ unsigned long mask = (unsigned long)table->size - 1;
+ unsigned char step = 0;
+ i = h & mask;
+ while (table->v[i]) {
+ if (keyeq(name, table->v[i]->name))
+ return table->v[i];
+ if (!step)
+ step = PROBE_STEP(h, mask, table->power);
+ i < step ? (i += table->size - step) : (i -= step);
+ }
+ if (!createSize)
+ return NULL;
+
+ /* check for overflow (table is half full) */
+ if (table->used >> (table->power - 1)) {
+ unsigned char newPower = table->power + 1;
+ size_t newSize = (size_t)1 << newPower;
+ unsigned long newMask = (unsigned long)newSize - 1;
+ size_t tsize = newSize * sizeof(NAMED *);
+ NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize);
+ if (!newV)
+ return NULL;
+ memset(newV, 0, tsize);
+ for (i = 0; i < table->size; i++)
+ if (table->v[i]) {
+ unsigned long newHash = hash(table->v[i]->name);
+ size_t j = newHash & newMask;
+ step = 0;
+ while (newV[j]) {
+ if (!step)
+ step = PROBE_STEP(newHash, newMask, newPower);
+ j < step ? (j += newSize - step) : (j -= step);
+ }
+ newV[j] = table->v[i];
+ }
+ table->mem->free_fcn(table->v);
+ table->v = newV;
+ table->power = newPower;
+ table->size = newSize;
+ i = h & newMask;
+ step = 0;
+ while (table->v[i]) {
+ if (!step)
+ step = PROBE_STEP(h, newMask, newPower);
+ i < step ? (i += newSize - step) : (i -= step);
+ }
+ }
+ }
+ table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize);
+ if (!table->v[i])
+ return NULL;
+ memset(table->v[i], 0, createSize);
+ table->v[i]->name = name;
+ (table->used)++;
+ return table->v[i];
+}
+
+static void FASTCALL
+hashTableClear(HASH_TABLE *table)
+{
+ size_t i;
+ for (i = 0; i < table->size; i++) {
+ table->mem->free_fcn(table->v[i]);
+ table->v[i] = NULL;
+ }
+ table->used = 0;
+}
+
+static void FASTCALL
+hashTableDestroy(HASH_TABLE *table)
+{
+ size_t i;
+ for (i = 0; i < table->size; i++)
+ table->mem->free_fcn(table->v[i]);
+ table->mem->free_fcn(table->v);
+}
+
+static void FASTCALL
+hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms)
+{
+ p->power = 0;
+ p->size = 0;
+ p->used = 0;
+ p->v = NULL;
+ p->mem = ms;
+}
+
+static void FASTCALL
+hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table)
+{
+ iter->p = table->v;
+ iter->end = iter->p + table->size;
+}
+
+static NAMED * FASTCALL
+hashTableIterNext(HASH_TABLE_ITER *iter)
+{
+ while (iter->p != iter->end) {
+ NAMED *tem = *(iter->p)++;
+ if (tem)
+ return tem;
+ }
+ return NULL;
+}
+
+static void FASTCALL
+poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms)
+{
+ pool->blocks = NULL;
+ pool->freeBlocks = NULL;
+ pool->start = NULL;
+ pool->ptr = NULL;
+ pool->end = NULL;
+ pool->mem = ms;
+}
+
+static void FASTCALL
+poolClear(STRING_POOL *pool)
+{
+ if (!pool->freeBlocks)
+ pool->freeBlocks = pool->blocks;
+ else {
+ BLOCK *p = pool->blocks;
+ while (p) {
+ BLOCK *tem = p->next;
+ p->next = pool->freeBlocks;
+ pool->freeBlocks = p;
+ p = tem;
+ }
+ }
+ pool->blocks = NULL;
+ pool->start = NULL;
+ pool->ptr = NULL;
+ pool->end = NULL;
+}
+
+static void FASTCALL
+poolDestroy(STRING_POOL *pool)
+{
+ BLOCK *p = pool->blocks;
+ while (p) {
+ BLOCK *tem = p->next;
+ pool->mem->free_fcn(p);
+ p = tem;
+ }
+ p = pool->freeBlocks;
+ while (p) {
+ BLOCK *tem = p->next;
+ pool->mem->free_fcn(p);
+ p = tem;
+ }
+}
+
+static XML_Char *
+poolAppend(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end)
+{
+ if (!pool->ptr && !poolGrow(pool))
+ return NULL;
+ for (;;) {
+ XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
+ if (ptr == end)
+ break;
+ if (!poolGrow(pool))
+ return NULL;
+ }
+ return pool->start;
+}
+
+static const XML_Char * FASTCALL
+poolCopyString(STRING_POOL *pool, const XML_Char *s)
+{
+ do {
+ if (!poolAppendChar(pool, *s))
+ return NULL;
+ } while (*s++);
+ s = pool->start;
+ poolFinish(pool);
+ return s;
+}
+
+static const XML_Char *
+poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n)
+{
+ if (!pool->ptr && !poolGrow(pool))
+ return NULL;
+ for (; n > 0; --n, s++) {
+ if (!poolAppendChar(pool, *s))
+ return NULL;
+ }
+ s = pool->start;
+ poolFinish(pool);
+ return s;
+}
+
+static const XML_Char * FASTCALL
+poolAppendString(STRING_POOL *pool, const XML_Char *s)
+{
+ while (*s) {
+ if (!poolAppendChar(pool, *s))
+ return NULL;
+ s++;
+ }
+ return pool->start;
+}
+
+static XML_Char *
+poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end)
+{
+ if (!poolAppend(pool, enc, ptr, end))
+ return NULL;
+ if (pool->ptr == pool->end && !poolGrow(pool))
+ return NULL;
+ *(pool->ptr)++ = 0;
+ return pool->start;
+}
+
+static XML_Bool FASTCALL
+poolGrow(STRING_POOL *pool)
+{
+ if (pool->freeBlocks) {
+ if (pool->start == 0) {
+ pool->blocks = pool->freeBlocks;
+ pool->freeBlocks = pool->freeBlocks->next;
+ pool->blocks->next = NULL;
+ pool->start = pool->blocks->s;
+ pool->end = pool->start + pool->blocks->size;
+ pool->ptr = pool->start;
+ return XML_TRUE;
+ }
+ if (pool->end - pool->start < pool->freeBlocks->size) {
+ BLOCK *tem = pool->freeBlocks->next;
+ pool->freeBlocks->next = pool->blocks;
+ pool->blocks = pool->freeBlocks;
+ pool->freeBlocks = tem;
+ memcpy(pool->blocks->s, pool->start,
+ (pool->end - pool->start) * sizeof(XML_Char));
+ pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+ pool->start = pool->blocks->s;
+ pool->end = pool->start + pool->blocks->size;
+ return XML_TRUE;
+ }
+ }
+ if (pool->blocks && pool->start == pool->blocks->s) {
+ int blockSize = (int)(pool->end - pool->start)*2;
+ pool->blocks = (BLOCK *)
+ pool->mem->realloc_fcn(pool->blocks,
+ (offsetof(BLOCK, s)
+ + blockSize * sizeof(XML_Char)));
+ if (pool->blocks == NULL)
+ return XML_FALSE;
+ pool->blocks->size = blockSize;
+ pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+ pool->start = pool->blocks->s;
+ pool->end = pool->start + blockSize;
+ }
+ else {
+ BLOCK *tem;
+ int blockSize = (int)(pool->end - pool->start);
+ if (blockSize < INIT_BLOCK_SIZE)
+ blockSize = INIT_BLOCK_SIZE;
+ else
+ blockSize *= 2;
+ tem = (BLOCK *)pool->mem->malloc_fcn(offsetof(BLOCK, s)
+ + blockSize * sizeof(XML_Char));
+ if (!tem)
+ return XML_FALSE;
+ tem->size = blockSize;
+ tem->next = pool->blocks;
+ pool->blocks = tem;
+ if (pool->ptr != pool->start)
+ memcpy(tem->s, pool->start,
+ (pool->ptr - pool->start) * sizeof(XML_Char));
+ pool->ptr = tem->s + (pool->ptr - pool->start);
+ pool->start = tem->s;
+ pool->end = tem->s + blockSize;
+ }
+ return XML_TRUE;
+}
+
+static int FASTCALL
+nextScaffoldPart(XML_Parser parser)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ CONTENT_SCAFFOLD * me;
+ int next;
+
+ if (!dtd->scaffIndex) {
+ dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int));
+ if (!dtd->scaffIndex)
+ return -1;
+ dtd->scaffIndex[0] = 0;
+ }
+
+ if (dtd->scaffCount >= dtd->scaffSize) {
+ CONTENT_SCAFFOLD *temp;
+ if (dtd->scaffold) {
+ temp = (CONTENT_SCAFFOLD *)
+ REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
+ if (temp == NULL)
+ return -1;
+ dtd->scaffSize *= 2;
+ }
+ else {
+ temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS
+ * sizeof(CONTENT_SCAFFOLD));
+ if (temp == NULL)
+ return -1;
+ dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS;
+ }
+ dtd->scaffold = temp;
+ }
+ next = dtd->scaffCount++;
+ me = &dtd->scaffold[next];
+ if (dtd->scaffLevel) {
+ CONTENT_SCAFFOLD *parent = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel-1]];
+ if (parent->lastchild) {
+ dtd->scaffold[parent->lastchild].nextsib = next;
+ }
+ if (!parent->childcnt)
+ parent->firstchild = next;
+ parent->lastchild = next;
+ parent->childcnt++;
+ }
+ me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0;
+ return next;
+}
+
+static void
+build_node(XML_Parser parser,
+ int src_node,
+ XML_Content *dest,
+ XML_Content **contpos,
+ XML_Char **strpos)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ dest->type = dtd->scaffold[src_node].type;
+ dest->quant = dtd->scaffold[src_node].quant;
+ if (dest->type == XML_CTYPE_NAME) {
+ const XML_Char *src;
+ dest->name = *strpos;
+ src = dtd->scaffold[src_node].name;
+ for (;;) {
+ *(*strpos)++ = *src;
+ if (!*src)
+ break;
+ src++;
+ }
+ dest->numchildren = 0;
+ dest->children = NULL;
+ }
+ else {
+ unsigned int i;
+ int cn;
+ dest->numchildren = dtd->scaffold[src_node].childcnt;
+ dest->children = *contpos;
+ *contpos += dest->numchildren;
+ for (i = 0, cn = dtd->scaffold[src_node].firstchild;
+ i < dest->numchildren;
+ i++, cn = dtd->scaffold[cn].nextsib) {
+ build_node(parser, cn, &(dest->children[i]), contpos, strpos);
+ }
+ dest->name = NULL;
+ }
+}
+
+static XML_Content *
+build_model (XML_Parser parser)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ XML_Content *ret;
+ XML_Content *cpos;
+ XML_Char * str;
+ int allocsize = (dtd->scaffCount * sizeof(XML_Content)
+ + (dtd->contentStringLen * sizeof(XML_Char)));
+
+ ret = (XML_Content *)MALLOC(allocsize);
+ if (!ret)
+ return NULL;
+
+ str = (XML_Char *) (&ret[dtd->scaffCount]);
+ cpos = &ret[1];
+
+ build_node(parser, 0, ret, &cpos, &str);
+ return ret;
+}
+
+static ELEMENT_TYPE *
+getElementType(XML_Parser parser,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end);
+ ELEMENT_TYPE *ret;
+
+ if (!name)
+ return NULL;
+ ret = (ELEMENT_TYPE *) lookup(&dtd->elementTypes, name, sizeof(ELEMENT_TYPE));
+ if (!ret)
+ return NULL;
+ if (ret->name != name)
+ poolDiscard(&dtd->pool);
+ else {
+ poolFinish(&dtd->pool);
+ if (!setElementTypePrefix(parser, ret))
+ return NULL;
+ }
+ return ret;
+}
diff --git a/src/lib/expat/xmlrole.c b/src/lib/expat/xmlrole.c
new file mode 100644
index 00000000000..b0aff272432
--- /dev/null
+++ b/src/lib/expat/xmlrole.c
@@ -0,0 +1,1320 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#include <stddef.h>
+
+#include "intconfig.h"
+
+#include "expat_external.h"
+#include "internal.h"
+#include "xmlrole.h"
+#include "ascii.h"
+
+/* Doesn't check:
+
+ that ,| are not mixed in a model group
+ content of literals
+
+*/
+
+static const char KW_ANY[] = {
+ ASCII_A, ASCII_N, ASCII_Y, '\0' };
+static const char KW_ATTLIST[] = {
+ ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' };
+static const char KW_CDATA[] = {
+ ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+static const char KW_DOCTYPE[] = {
+ ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' };
+static const char KW_ELEMENT[] = {
+ ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' };
+static const char KW_EMPTY[] = {
+ ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' };
+static const char KW_ENTITIES[] = {
+ ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S,
+ '\0' };
+static const char KW_ENTITY[] = {
+ ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
+static const char KW_FIXED[] = {
+ ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' };
+static const char KW_ID[] = {
+ ASCII_I, ASCII_D, '\0' };
+static const char KW_IDREF[] = {
+ ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
+static const char KW_IDREFS[] = {
+ ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
+static const char KW_IGNORE[] = {
+ ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' };
+static const char KW_IMPLIED[] = {
+ ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' };
+static const char KW_INCLUDE[] = {
+ ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' };
+static const char KW_NDATA[] = {
+ ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+static const char KW_NMTOKEN[] = {
+ ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
+static const char KW_NMTOKENS[] = {
+ ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S,
+ '\0' };
+static const char KW_NOTATION[] =
+ { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N,
+ '\0' };
+static const char KW_PCDATA[] = {
+ ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+static const char KW_PUBLIC[] = {
+ ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' };
+static const char KW_REQUIRED[] = {
+ ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D,
+ '\0' };
+static const char KW_SYSTEM[] = {
+ ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' };
+
+#ifndef MIN_BYTES_PER_CHAR
+#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar)
+#endif
+
+#ifdef XML_DTD
+#define setTopLevel(state) \
+ ((state)->handler = ((state)->documentEntity \
+ ? internalSubset \
+ : externalSubset1))
+#else /* not XML_DTD */
+#define setTopLevel(state) ((state)->handler = internalSubset)
+#endif /* not XML_DTD */
+
+typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc);
+
+static PROLOG_HANDLER
+ prolog0, prolog1, prolog2,
+ doctype0, doctype1, doctype2, doctype3, doctype4, doctype5,
+ internalSubset,
+ entity0, entity1, entity2, entity3, entity4, entity5, entity6,
+ entity7, entity8, entity9, entity10,
+ notation0, notation1, notation2, notation3, notation4,
+ attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6,
+ attlist7, attlist8, attlist9,
+ element0, element1, element2, element3, element4, element5, element6,
+ element7,
+#ifdef XML_DTD
+ externalSubset0, externalSubset1,
+ condSect0, condSect1, condSect2,
+#endif /* XML_DTD */
+ declClose,
+ error;
+
+static int FASTCALL common(PROLOG_STATE *state, int tok);
+
+static int PTRCALL
+prolog0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ state->handler = prolog1;
+ return XML_ROLE_NONE;
+ case XML_TOK_XML_DECL:
+ state->handler = prolog1;
+ return XML_ROLE_XML_DECL;
+ case XML_TOK_PI:
+ state->handler = prolog1;
+ return XML_ROLE_PI;
+ case XML_TOK_COMMENT:
+ state->handler = prolog1;
+ return XML_ROLE_COMMENT;
+ case XML_TOK_BOM:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_OPEN:
+ if (!XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_DOCTYPE))
+ break;
+ state->handler = doctype0;
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_INSTANCE_START:
+ state->handler = error;
+ return XML_ROLE_INSTANCE_START;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+prolog1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_PI:
+ return XML_ROLE_PI;
+ case XML_TOK_COMMENT:
+ return XML_ROLE_COMMENT;
+ case XML_TOK_BOM:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_OPEN:
+ if (!XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_DOCTYPE))
+ break;
+ state->handler = doctype0;
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_INSTANCE_START:
+ state->handler = error;
+ return XML_ROLE_INSTANCE_START;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+prolog2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_PI:
+ return XML_ROLE_PI;
+ case XML_TOK_COMMENT:
+ return XML_ROLE_COMMENT;
+ case XML_TOK_INSTANCE_START:
+ state->handler = error;
+ return XML_ROLE_INSTANCE_START;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = doctype1;
+ return XML_ROLE_DOCTYPE_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = internalSubset;
+ return XML_ROLE_DOCTYPE_INTERNAL_SUBSET;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = prolog2;
+ return XML_ROLE_DOCTYPE_CLOSE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+ state->handler = doctype3;
+ return XML_ROLE_DOCTYPE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+ state->handler = doctype2;
+ return XML_ROLE_DOCTYPE_NONE;
+ }
+ break;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = doctype3;
+ return XML_ROLE_DOCTYPE_PUBLIC_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = doctype4;
+ return XML_ROLE_DOCTYPE_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = internalSubset;
+ return XML_ROLE_DOCTYPE_INTERNAL_SUBSET;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = prolog2;
+ return XML_ROLE_DOCTYPE_CLOSE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = prolog2;
+ return XML_ROLE_DOCTYPE_CLOSE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+internalSubset(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_OPEN:
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_ENTITY)) {
+ state->handler = entity0;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_ATTLIST)) {
+ state->handler = attlist0;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_ELEMENT)) {
+ state->handler = element0;
+ return XML_ROLE_ELEMENT_NONE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_NOTATION)) {
+ state->handler = notation0;
+ return XML_ROLE_NOTATION_NONE;
+ }
+ break;
+ case XML_TOK_PI:
+ return XML_ROLE_PI;
+ case XML_TOK_COMMENT:
+ return XML_ROLE_COMMENT;
+ case XML_TOK_PARAM_ENTITY_REF:
+ return XML_ROLE_PARAM_ENTITY_REF;
+ case XML_TOK_CLOSE_BRACKET:
+ state->handler = doctype5;
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_NONE:
+ return XML_ROLE_NONE;
+ }
+ return common(state, tok);
+}
+
+#ifdef XML_DTD
+
+static int PTRCALL
+externalSubset0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ state->handler = externalSubset1;
+ if (tok == XML_TOK_XML_DECL)
+ return XML_ROLE_TEXT_DECL;
+ return externalSubset1(state, tok, ptr, end, enc);
+}
+
+static int PTRCALL
+externalSubset1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_COND_SECT_OPEN:
+ state->handler = condSect0;
+ return XML_ROLE_NONE;
+ case XML_TOK_COND_SECT_CLOSE:
+ if (state->includeLevel == 0)
+ break;
+ state->includeLevel -= 1;
+ return XML_ROLE_NONE;
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_CLOSE_BRACKET:
+ break;
+ case XML_TOK_NONE:
+ if (state->includeLevel)
+ break;
+ return XML_ROLE_NONE;
+ default:
+ return internalSubset(state, tok, ptr, end, enc);
+ }
+ return common(state, tok);
+}
+
+#endif /* XML_DTD */
+
+static int PTRCALL
+entity0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_PERCENT:
+ state->handler = entity1;
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ state->handler = entity2;
+ return XML_ROLE_GENERAL_ENTITY_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ state->handler = entity7;
+ return XML_ROLE_PARAM_ENTITY_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+ state->handler = entity4;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+ state->handler = entity3;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ break;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ENTITY_NONE;
+ return XML_ROLE_ENTITY_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity4;
+ return XML_ROLE_ENTITY_PUBLIC_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity5;
+ return XML_ROLE_ENTITY_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return XML_ROLE_ENTITY_COMPLETE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) {
+ state->handler = entity6;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ break;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity6(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ENTITY_NONE;
+ return XML_ROLE_ENTITY_NOTATION_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity7(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+ state->handler = entity9;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+ state->handler = entity8;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ break;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ENTITY_NONE;
+ return XML_ROLE_ENTITY_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity8(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity9;
+ return XML_ROLE_ENTITY_PUBLIC_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity9(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity10;
+ return XML_ROLE_ENTITY_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity10(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return XML_ROLE_ENTITY_COMPLETE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_NAME:
+ state->handler = notation1;
+ return XML_ROLE_NOTATION_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+ state->handler = notation3;
+ return XML_ROLE_NOTATION_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+ state->handler = notation2;
+ return XML_ROLE_NOTATION_NONE;
+ }
+ break;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = notation4;
+ return XML_ROLE_NOTATION_PUBLIC_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_NOTATION_NONE;
+ return XML_ROLE_NOTATION_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_NOTATION_NONE;
+ return XML_ROLE_NOTATION_SYSTEM_ID;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return XML_ROLE_NOTATION_NO_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = attlist1;
+ return XML_ROLE_ATTLIST_ELEMENT_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = attlist2;
+ return XML_ROLE_ATTRIBUTE_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NAME:
+ {
+ static const char * const types[] = {
+ KW_CDATA,
+ KW_ID,
+ KW_IDREF,
+ KW_IDREFS,
+ KW_ENTITY,
+ KW_ENTITIES,
+ KW_NMTOKEN,
+ KW_NMTOKENS,
+ };
+ int i;
+ for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++)
+ if (XmlNameMatchesAscii(enc, ptr, end, types[i])) {
+ state->handler = attlist8;
+ return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i;
+ }
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) {
+ state->handler = attlist5;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ break;
+ case XML_TOK_OPEN_PAREN:
+ state->handler = attlist3;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NMTOKEN:
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = attlist4;
+ return XML_ROLE_ATTRIBUTE_ENUM_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->handler = attlist8;
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_OR:
+ state->handler = attlist3;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_OPEN_PAREN:
+ state->handler = attlist6;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist6(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NAME:
+ state->handler = attlist7;
+ return XML_ROLE_ATTRIBUTE_NOTATION_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist7(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->handler = attlist8;
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_OR:
+ state->handler = attlist6;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ return common(state, tok);
+}
+
+/* default value */
+static int PTRCALL
+attlist8(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_POUND_NAME:
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_IMPLIED)) {
+ state->handler = attlist1;
+ return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_REQUIRED)) {
+ state->handler = attlist1;
+ return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_FIXED)) {
+ state->handler = attlist9;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ break;
+ case XML_TOK_LITERAL:
+ state->handler = attlist1;
+ return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist9(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = attlist1;
+ return XML_ROLE_FIXED_ATTRIBUTE_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element1;
+ return XML_ROLE_ELEMENT_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_CONTENT_EMPTY;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_CONTENT_ANY;
+ }
+ break;
+ case XML_TOK_OPEN_PAREN:
+ state->handler = element2;
+ state->level = 1;
+ return XML_ROLE_GROUP_OPEN;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_POUND_NAME:
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_PCDATA)) {
+ state->handler = element3;
+ return XML_ROLE_CONTENT_PCDATA;
+ }
+ break;
+ case XML_TOK_OPEN_PAREN:
+ state->level = 2;
+ state->handler = element6;
+ return XML_ROLE_GROUP_OPEN;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT;
+ case XML_TOK_NAME_QUESTION:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_OPT;
+ case XML_TOK_NAME_ASTERISK:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_REP;
+ case XML_TOK_NAME_PLUS:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_PLUS;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element3(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_GROUP_CLOSE;
+ case XML_TOK_CLOSE_PAREN_ASTERISK:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_GROUP_CLOSE_REP;
+ case XML_TOK_OR:
+ state->handler = element4;
+ return XML_ROLE_ELEMENT_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element4(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element5;
+ return XML_ROLE_CONTENT_ELEMENT;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_CLOSE_PAREN_ASTERISK:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_GROUP_CLOSE_REP;
+ case XML_TOK_OR:
+ state->handler = element4;
+ return XML_ROLE_ELEMENT_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element6(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_OPEN_PAREN:
+ state->level += 1;
+ return XML_ROLE_GROUP_OPEN;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT;
+ case XML_TOK_NAME_QUESTION:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_OPT;
+ case XML_TOK_NAME_ASTERISK:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_REP;
+ case XML_TOK_NAME_PLUS:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_PLUS;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element7(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->level -= 1;
+ if (state->level == 0) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ }
+ return XML_ROLE_GROUP_CLOSE;
+ case XML_TOK_CLOSE_PAREN_ASTERISK:
+ state->level -= 1;
+ if (state->level == 0) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ }
+ return XML_ROLE_GROUP_CLOSE_REP;
+ case XML_TOK_CLOSE_PAREN_QUESTION:
+ state->level -= 1;
+ if (state->level == 0) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ }
+ return XML_ROLE_GROUP_CLOSE_OPT;
+ case XML_TOK_CLOSE_PAREN_PLUS:
+ state->level -= 1;
+ if (state->level == 0) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ }
+ return XML_ROLE_GROUP_CLOSE_PLUS;
+ case XML_TOK_COMMA:
+ state->handler = element6;
+ return XML_ROLE_GROUP_SEQUENCE;
+ case XML_TOK_OR:
+ state->handler = element6;
+ return XML_ROLE_GROUP_CHOICE;
+ }
+ return common(state, tok);
+}
+
+#ifdef XML_DTD
+
+static int PTRCALL
+condSect0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) {
+ state->handler = condSect1;
+ return XML_ROLE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) {
+ state->handler = condSect2;
+ return XML_ROLE_NONE;
+ }
+ break;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+condSect1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = externalSubset1;
+ state->includeLevel += 1;
+ return XML_ROLE_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+condSect2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = externalSubset1;
+ return XML_ROLE_IGNORE_SECT;
+ }
+ return common(state, tok);
+}
+
+#endif /* XML_DTD */
+
+static int PTRCALL
+declClose(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return state->role_none;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return state->role_none;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+error(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ return XML_ROLE_NONE;
+}
+
+static int FASTCALL
+common(PROLOG_STATE *state, int tok)
+{
+#ifdef XML_DTD
+ if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF)
+ return XML_ROLE_INNER_PARAM_ENTITY_REF;
+#endif
+ state->handler = error;
+ return XML_ROLE_ERROR;
+}
+
+void
+XmlPrologStateInit(PROLOG_STATE *state)
+{
+ state->handler = prolog0;
+#ifdef XML_DTD
+ state->documentEntity = 1;
+ state->includeLevel = 0;
+ state->inEntityValue = 0;
+#endif /* XML_DTD */
+}
+
+#ifdef XML_DTD
+
+void
+XmlPrologStateInitExternalEntity(PROLOG_STATE *state)
+{
+ state->handler = externalSubset0;
+ state->documentEntity = 0;
+ state->includeLevel = 0;
+}
+
+#endif /* XML_DTD */
diff --git a/src/lib/expat/xmlrole.h b/src/lib/expat/xmlrole.h
new file mode 100644
index 00000000000..4dd9f06f976
--- /dev/null
+++ b/src/lib/expat/xmlrole.h
@@ -0,0 +1,114 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef XmlRole_INCLUDED
+#define XmlRole_INCLUDED 1
+
+#ifdef __VMS
+/* 0 1 2 3 0 1 2 3
+ 1234567890123456789012345678901 1234567890123456789012345678901 */
+#define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt
+#endif
+
+#include "xmltok.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ XML_ROLE_ERROR = -1,
+ XML_ROLE_NONE = 0,
+ XML_ROLE_XML_DECL,
+ XML_ROLE_INSTANCE_START,
+ XML_ROLE_DOCTYPE_NONE,
+ XML_ROLE_DOCTYPE_NAME,
+ XML_ROLE_DOCTYPE_SYSTEM_ID,
+ XML_ROLE_DOCTYPE_PUBLIC_ID,
+ XML_ROLE_DOCTYPE_INTERNAL_SUBSET,
+ XML_ROLE_DOCTYPE_CLOSE,
+ XML_ROLE_GENERAL_ENTITY_NAME,
+ XML_ROLE_PARAM_ENTITY_NAME,
+ XML_ROLE_ENTITY_NONE,
+ XML_ROLE_ENTITY_VALUE,
+ XML_ROLE_ENTITY_SYSTEM_ID,
+ XML_ROLE_ENTITY_PUBLIC_ID,
+ XML_ROLE_ENTITY_COMPLETE,
+ XML_ROLE_ENTITY_NOTATION_NAME,
+ XML_ROLE_NOTATION_NONE,
+ XML_ROLE_NOTATION_NAME,
+ XML_ROLE_NOTATION_SYSTEM_ID,
+ XML_ROLE_NOTATION_NO_SYSTEM_ID,
+ XML_ROLE_NOTATION_PUBLIC_ID,
+ XML_ROLE_ATTRIBUTE_NAME,
+ XML_ROLE_ATTRIBUTE_TYPE_CDATA,
+ XML_ROLE_ATTRIBUTE_TYPE_ID,
+ XML_ROLE_ATTRIBUTE_TYPE_IDREF,
+ XML_ROLE_ATTRIBUTE_TYPE_IDREFS,
+ XML_ROLE_ATTRIBUTE_TYPE_ENTITY,
+ XML_ROLE_ATTRIBUTE_TYPE_ENTITIES,
+ XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN,
+ XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS,
+ XML_ROLE_ATTRIBUTE_ENUM_VALUE,
+ XML_ROLE_ATTRIBUTE_NOTATION_VALUE,
+ XML_ROLE_ATTLIST_NONE,
+ XML_ROLE_ATTLIST_ELEMENT_NAME,
+ XML_ROLE_IMPLIED_ATTRIBUTE_VALUE,
+ XML_ROLE_REQUIRED_ATTRIBUTE_VALUE,
+ XML_ROLE_DEFAULT_ATTRIBUTE_VALUE,
+ XML_ROLE_FIXED_ATTRIBUTE_VALUE,
+ XML_ROLE_ELEMENT_NONE,
+ XML_ROLE_ELEMENT_NAME,
+ XML_ROLE_CONTENT_ANY,
+ XML_ROLE_CONTENT_EMPTY,
+ XML_ROLE_CONTENT_PCDATA,
+ XML_ROLE_GROUP_OPEN,
+ XML_ROLE_GROUP_CLOSE,
+ XML_ROLE_GROUP_CLOSE_REP,
+ XML_ROLE_GROUP_CLOSE_OPT,
+ XML_ROLE_GROUP_CLOSE_PLUS,
+ XML_ROLE_GROUP_CHOICE,
+ XML_ROLE_GROUP_SEQUENCE,
+ XML_ROLE_CONTENT_ELEMENT,
+ XML_ROLE_CONTENT_ELEMENT_REP,
+ XML_ROLE_CONTENT_ELEMENT_OPT,
+ XML_ROLE_CONTENT_ELEMENT_PLUS,
+ XML_ROLE_PI,
+ XML_ROLE_COMMENT,
+#ifdef XML_DTD
+ XML_ROLE_TEXT_DECL,
+ XML_ROLE_IGNORE_SECT,
+ XML_ROLE_INNER_PARAM_ENTITY_REF,
+#endif /* XML_DTD */
+ XML_ROLE_PARAM_ENTITY_REF
+};
+
+typedef struct prolog_state {
+ int (PTRCALL *handler) (struct prolog_state *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc);
+ unsigned level;
+ int role_none;
+#ifdef XML_DTD
+ unsigned includeLevel;
+ int documentEntity;
+ int inEntityValue;
+#endif /* XML_DTD */
+} PROLOG_STATE;
+
+void XmlPrologStateInit(PROLOG_STATE *);
+#ifdef XML_DTD
+void XmlPrologStateInitExternalEntity(PROLOG_STATE *);
+#endif /* XML_DTD */
+
+#define XmlTokenRole(state, tok, ptr, end, enc) \
+ (((state)->handler)(state, tok, ptr, end, enc))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not XmlRole_INCLUDED */
diff --git a/src/lib/expat/xmltok.c b/src/lib/expat/xmltok.c
new file mode 100644
index 00000000000..3a7275adb25
--- /dev/null
+++ b/src/lib/expat/xmltok.c
@@ -0,0 +1,1629 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#include <stddef.h>
+
+#include "intconfig.h"
+
+#include "expat_external.h"
+#include "internal.h"
+#include "xmltok.h"
+#include "nametab.h"
+
+#ifdef XML_DTD
+#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok)
+#else
+#define IGNORE_SECTION_TOK_VTABLE /* as nothing */
+#endif
+
+#define VTABLE1 \
+ { PREFIX(prologTok), PREFIX(contentTok), \
+ PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \
+ { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \
+ PREFIX(sameName), \
+ PREFIX(nameMatchesAscii), \
+ PREFIX(nameLength), \
+ PREFIX(skipS), \
+ PREFIX(getAtts), \
+ PREFIX(charRefNumber), \
+ PREFIX(predefinedEntityName), \
+ PREFIX(updatePosition), \
+ PREFIX(isPublicId)
+
+#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16)
+
+#define UCS2_GET_NAMING(pages, hi, lo) \
+ (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F)))
+
+/* A 2 byte UTF-8 representation splits the characters 11 bits between
+ the bottom 5 and 6 bits of the bytes. We need 8 bits to index into
+ pages, 3 bits to add to that index and 5 bits to generate the mask.
+*/
+#define UTF8_GET_NAMING2(pages, byte) \
+ (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \
+ + ((((byte)[0]) & 3) << 1) \
+ + ((((byte)[1]) >> 5) & 1)] \
+ & (1 << (((byte)[1]) & 0x1F)))
+
+/* A 3 byte UTF-8 representation splits the characters 16 bits between
+ the bottom 4, 6 and 6 bits of the bytes. We need 8 bits to index
+ into pages, 3 bits to add to that index and 5 bits to generate the
+ mask.
+*/
+#define UTF8_GET_NAMING3(pages, byte) \
+ (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \
+ + ((((byte)[1]) >> 2) & 0xF)] \
+ << 3) \
+ + ((((byte)[1]) & 3) << 1) \
+ + ((((byte)[2]) >> 5) & 1)] \
+ & (1 << (((byte)[2]) & 0x1F)))
+
+#define UTF8_GET_NAMING(pages, p, n) \
+ ((n) == 2 \
+ ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
+ : ((n) == 3 \
+ ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \
+ : 0))
+
+/* Detection of invalid UTF-8 sequences is based on Table 3.1B
+ of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/
+ with the additional restriction of not allowing the Unicode
+ code points 0xFFFF and 0xFFFE (sequences EF,BF,BF and EF,BF,BE).
+ Implementation details:
+ (A & 0x80) == 0 means A < 0x80
+ and
+ (A & 0xC0) == 0xC0 means A > 0xBF
+*/
+
+#define UTF8_INVALID2(p) \
+ ((*p) < 0xC2 || ((p)[1] & 0x80) == 0 || ((p)[1] & 0xC0) == 0xC0)
+
+#define UTF8_INVALID3(p) \
+ (((p)[2] & 0x80) == 0 \
+ || \
+ ((*p) == 0xEF && (p)[1] == 0xBF \
+ ? \
+ (p)[2] > 0xBD \
+ : \
+ ((p)[2] & 0xC0) == 0xC0) \
+ || \
+ ((*p) == 0xE0 \
+ ? \
+ (p)[1] < 0xA0 || ((p)[1] & 0xC0) == 0xC0 \
+ : \
+ ((p)[1] & 0x80) == 0 \
+ || \
+ ((*p) == 0xED ? (p)[1] > 0x9F : ((p)[1] & 0xC0) == 0xC0)))
+
+#define UTF8_INVALID4(p) \
+ (((p)[3] & 0x80) == 0 || ((p)[3] & 0xC0) == 0xC0 \
+ || \
+ ((p)[2] & 0x80) == 0 || ((p)[2] & 0xC0) == 0xC0 \
+ || \
+ ((*p) == 0xF0 \
+ ? \
+ (p)[1] < 0x90 || ((p)[1] & 0xC0) == 0xC0 \
+ : \
+ ((p)[1] & 0x80) == 0 \
+ || \
+ ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0)))
+
+static int PTRFASTCALL
+isNever(const ENCODING *enc, const char *p)
+{
+ return 0;
+}
+
+static int PTRFASTCALL
+utf8_isName2(const ENCODING *enc, const char *p)
+{
+ return UTF8_GET_NAMING2(namePages, (const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isName3(const ENCODING *enc, const char *p)
+{
+ return UTF8_GET_NAMING3(namePages, (const unsigned char *)p);
+}
+
+#define utf8_isName4 isNever
+
+static int PTRFASTCALL
+utf8_isNmstrt2(const ENCODING *enc, const char *p)
+{
+ return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isNmstrt3(const ENCODING *enc, const char *p)
+{
+ return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p);
+}
+
+#define utf8_isNmstrt4 isNever
+
+static int PTRFASTCALL
+utf8_isInvalid2(const ENCODING *enc, const char *p)
+{
+ return UTF8_INVALID2((const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isInvalid3(const ENCODING *enc, const char *p)
+{
+ return UTF8_INVALID3((const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isInvalid4(const ENCODING *enc, const char *p)
+{
+ return UTF8_INVALID4((const unsigned char *)p);
+}
+
+struct normal_encoding {
+ ENCODING enc;
+ unsigned char type[256];
+#ifdef XML_MIN_SIZE
+ int (PTRFASTCALL *byteType)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNameMin)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *);
+ int (PTRFASTCALL *byteToAscii)(const ENCODING *, const char *);
+ int (PTRCALL *charMatches)(const ENCODING *, const char *, int);
+#endif /* XML_MIN_SIZE */
+ int (PTRFASTCALL *isName2)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isName3)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isName4)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isInvalid2)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isInvalid3)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isInvalid4)(const ENCODING *, const char *);
+};
+
+#define AS_NORMAL_ENCODING(enc) ((const struct normal_encoding *) (enc))
+
+#ifdef XML_MIN_SIZE
+
+#define STANDARD_VTABLE(E) \
+ E ## byteType, \
+ E ## isNameMin, \
+ E ## isNmstrtMin, \
+ E ## byteToAscii, \
+ E ## charMatches,
+
+#else
+
+#define STANDARD_VTABLE(E) /* as nothing */
+
+#endif
+
+#define NORMAL_VTABLE(E) \
+ E ## isName2, \
+ E ## isName3, \
+ E ## isName4, \
+ E ## isNmstrt2, \
+ E ## isNmstrt3, \
+ E ## isNmstrt4, \
+ E ## isInvalid2, \
+ E ## isInvalid3, \
+ E ## isInvalid4
+
+static int FASTCALL checkCharRefNumber(int);
+
+#include "xmltok_impl.h"
+#include "ascii.h"
+
+#ifdef XML_MIN_SIZE
+#define sb_isNameMin isNever
+#define sb_isNmstrtMin isNever
+#endif
+
+#ifdef XML_MIN_SIZE
+#define MINBPC(enc) ((enc)->minBytesPerChar)
+#else
+/* minimum bytes per character */
+#define MINBPC(enc) 1
+#endif
+
+#define SB_BYTE_TYPE(enc, p) \
+ (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)])
+
+#ifdef XML_MIN_SIZE
+static int PTRFASTCALL
+sb_byteType(const ENCODING *enc, const char *p)
+{
+ return SB_BYTE_TYPE(enc, p);
+}
+#define BYTE_TYPE(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->byteType(enc, p))
+#else
+#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p)
+#endif
+
+#ifdef XML_MIN_SIZE
+#define BYTE_TO_ASCII(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p))
+static int PTRFASTCALL
+sb_byteToAscii(const ENCODING *enc, const char *p)
+{
+ return *p;
+}
+#else
+#define BYTE_TO_ASCII(enc, p) (*(p))
+#endif
+
+#define IS_NAME_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isName ## n(enc, p))
+#define IS_NMSTRT_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isNmstrt ## n(enc, p))
+#define IS_INVALID_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isInvalid ## n(enc, p))
+
+#ifdef XML_MIN_SIZE
+#define IS_NAME_CHAR_MINBPC(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p))
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p))
+#else
+#define IS_NAME_CHAR_MINBPC(enc, p) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0)
+#endif
+
+#ifdef XML_MIN_SIZE
+#define CHAR_MATCHES(enc, p, c) \
+ (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c))
+static int PTRCALL
+sb_charMatches(const ENCODING *enc, const char *p, int c)
+{
+ return *p == c;
+}
+#else
+/* c is an ASCII character */
+#define CHAR_MATCHES(enc, p, c) (*(p) == c)
+#endif
+
+#define PREFIX(ident) normal_ ## ident
+#include "xmltok_impl.c"
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */
+ UTF8_cval1 = 0x00,
+ UTF8_cval2 = 0xc0,
+ UTF8_cval3 = 0xe0,
+ UTF8_cval4 = 0xf0
+};
+
+static void PTRCALL
+utf8_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ char *to;
+ const char *from;
+ if (fromLim - *fromP > toLim - *toP) {
+ /* Avoid copying partial characters. */
+ for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--)
+ if (((unsigned char)fromLim[-1] & 0xc0) != 0x80)
+ break;
+ }
+ for (to = *toP, from = *fromP; from != fromLim; from++, to++)
+ *to = *from;
+ *fromP = from;
+ *toP = to;
+}
+
+static void PTRCALL
+utf8_toUtf16(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim)
+{
+ unsigned short *to = *toP;
+ const char *from = *fromP;
+ while (from != fromLim && to != toLim) {
+ switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) {
+ case BT_LEAD2:
+ *to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f));
+ from += 2;
+ break;
+ case BT_LEAD3:
+ *to++ = (unsigned short)(((from[0] & 0xf) << 12)
+ | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f));
+ from += 3;
+ break;
+ case BT_LEAD4:
+ {
+ unsigned long n;
+ if (to + 1 == toLim)
+ goto after;
+ n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12)
+ | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f);
+ n -= 0x10000;
+ to[0] = (unsigned short)((n >> 10) | 0xD800);
+ to[1] = (unsigned short)((n & 0x3FF) | 0xDC00);
+ to += 2;
+ from += 4;
+ }
+ break;
+ default:
+ *to++ = *from++;
+ break;
+ }
+ }
+after:
+ *fromP = from;
+ *toP = to;
+}
+
+#ifdef XML_NS
+static const struct normal_encoding utf8_encoding_ns = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#include "asciitab.h"
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+#endif
+
+static const struct normal_encoding utf8_encoding = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_utf8_encoding_ns = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#include "iasciitab.h"
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+#endif
+
+static const struct normal_encoding internal_utf8_encoding = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+static void PTRCALL
+latin1_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ for (;;) {
+ unsigned char c;
+ if (*fromP == fromLim)
+ break;
+ c = (unsigned char)**fromP;
+ if (c & 0x80) {
+ if (toLim - *toP < 2)
+ break;
+ *(*toP)++ = (char)((c >> 6) | UTF8_cval2);
+ *(*toP)++ = (char)((c & 0x3f) | 0x80);
+ (*fromP)++;
+ }
+ else {
+ if (*toP == toLim)
+ break;
+ *(*toP)++ = *(*fromP)++;
+ }
+ }
+}
+
+static void PTRCALL
+latin1_toUtf16(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim)
+{
+ while (*fromP != fromLim && *toP != toLim)
+ *(*toP)++ = (unsigned char)*(*fromP)++;
+}
+
+#ifdef XML_NS
+
+static const struct normal_encoding latin1_encoding_ns = {
+ { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
+ {
+#include "asciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(sb_)
+};
+
+#endif
+
+static const struct normal_encoding latin1_encoding = {
+ { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(sb_)
+};
+
+static void PTRCALL
+ascii_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ while (*fromP != fromLim && *toP != toLim)
+ *(*toP)++ = *(*fromP)++;
+}
+
+#ifdef XML_NS
+
+static const struct normal_encoding ascii_encoding_ns = {
+ { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
+ {
+#include "asciitab.h"
+/* BT_NONXML == 0 */
+ },
+ STANDARD_VTABLE(sb_)
+};
+
+#endif
+
+static const struct normal_encoding ascii_encoding = {
+ { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+/* BT_NONXML == 0 */
+ },
+ STANDARD_VTABLE(sb_)
+};
+
+static int PTRFASTCALL
+unicode_byte_type(char hi, char lo)
+{
+ switch ((unsigned char)hi) {
+ case 0xD8: case 0xD9: case 0xDA: case 0xDB:
+ return BT_LEAD4;
+ case 0xDC: case 0xDD: case 0xDE: case 0xDF:
+ return BT_TRAIL;
+ case 0xFF:
+ switch ((unsigned char)lo) {
+ case 0xFF:
+ case 0xFE:
+ return BT_NONXML;
+ }
+ break;
+ }
+ return BT_NONASCII;
+}
+
+#define DEFINE_UTF16_TO_UTF8(E) \
+static void PTRCALL \
+E ## toUtf8(const ENCODING *enc, \
+ const char **fromP, const char *fromLim, \
+ char **toP, const char *toLim) \
+{ \
+ const char *from; \
+ for (from = *fromP; from != fromLim; from += 2) { \
+ int plane; \
+ unsigned char lo2; \
+ unsigned char lo = GET_LO(from); \
+ unsigned char hi = GET_HI(from); \
+ switch (hi) { \
+ case 0: \
+ if (lo < 0x80) { \
+ if (*toP == toLim) { \
+ *fromP = from; \
+ return; \
+ } \
+ *(*toP)++ = lo; \
+ break; \
+ } \
+ /* fall through */ \
+ case 0x1: case 0x2: case 0x3: \
+ case 0x4: case 0x5: case 0x6: case 0x7: \
+ if (toLim - *toP < 2) { \
+ *fromP = from; \
+ return; \
+ } \
+ *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \
+ *(*toP)++ = ((lo & 0x3f) | 0x80); \
+ break; \
+ default: \
+ if (toLim - *toP < 3) { \
+ *fromP = from; \
+ return; \
+ } \
+ /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \
+ *(*toP)++ = ((hi >> 4) | UTF8_cval3); \
+ *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \
+ *(*toP)++ = ((lo & 0x3f) | 0x80); \
+ break; \
+ case 0xD8: case 0xD9: case 0xDA: case 0xDB: \
+ if (toLim - *toP < 4) { \
+ *fromP = from; \
+ return; \
+ } \
+ plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \
+ *(*toP)++ = ((plane >> 2) | UTF8_cval4); \
+ *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \
+ from += 2; \
+ lo2 = GET_LO(from); \
+ *(*toP)++ = (((lo & 0x3) << 4) \
+ | ((GET_HI(from) & 0x3) << 2) \
+ | (lo2 >> 6) \
+ | 0x80); \
+ *(*toP)++ = ((lo2 & 0x3f) | 0x80); \
+ break; \
+ } \
+ } \
+ *fromP = from; \
+}
+
+#define DEFINE_UTF16_TO_UTF16(E) \
+static void PTRCALL \
+E ## toUtf16(const ENCODING *enc, \
+ const char **fromP, const char *fromLim, \
+ unsigned short **toP, const unsigned short *toLim) \
+{ \
+ /* Avoid copying first half only of surrogate */ \
+ if (fromLim - *fromP > ((toLim - *toP) << 1) \
+ && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \
+ fromLim -= 2; \
+ for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \
+ *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \
+}
+
+#define SET2(ptr, ch) \
+ (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8)))
+#define GET_LO(ptr) ((unsigned char)(ptr)[0])
+#define GET_HI(ptr) ((unsigned char)(ptr)[1])
+
+DEFINE_UTF16_TO_UTF8(little2_)
+DEFINE_UTF16_TO_UTF16(little2_)
+
+#undef SET2
+#undef GET_LO
+#undef GET_HI
+
+#define SET2(ptr, ch) \
+ (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF)))
+#define GET_LO(ptr) ((unsigned char)(ptr)[1])
+#define GET_HI(ptr) ((unsigned char)(ptr)[0])
+
+DEFINE_UTF16_TO_UTF8(big2_)
+DEFINE_UTF16_TO_UTF16(big2_)
+
+#undef SET2
+#undef GET_LO
+#undef GET_HI
+
+#define LITTLE2_BYTE_TYPE(enc, p) \
+ ((p)[1] == 0 \
+ ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \
+ : unicode_byte_type((p)[1], (p)[0]))
+#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1)
+#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c)
+#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0])
+#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0])
+
+#ifdef XML_MIN_SIZE
+
+static int PTRFASTCALL
+little2_byteType(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_BYTE_TYPE(enc, p);
+}
+
+static int PTRFASTCALL
+little2_byteToAscii(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_BYTE_TO_ASCII(enc, p);
+}
+
+static int PTRCALL
+little2_charMatches(const ENCODING *enc, const char *p, int c)
+{
+ return LITTLE2_CHAR_MATCHES(enc, p, c);
+}
+
+static int PTRFASTCALL
+little2_isNameMin(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p);
+}
+
+static int PTRFASTCALL
+little2_isNmstrtMin(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p);
+}
+
+#undef VTABLE
+#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16
+
+#else /* not XML_MIN_SIZE */
+
+#undef PREFIX
+#define PREFIX(ident) little2_ ## ident
+#define MINBPC(enc) 2
+/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
+#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p)
+#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p)
+#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c)
+#define IS_NAME_CHAR(enc, p, n) 0
+#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p)
+#define IS_NMSTRT_CHAR(enc, p, n) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p)
+
+#include "xmltok_impl.c"
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+#endif /* not XML_MIN_SIZE */
+
+#ifdef XML_NS
+
+static const struct normal_encoding little2_encoding_ns = {
+ { VTABLE, 2, 0,
+#if BYTEORDER == 1234
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#include "asciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_)
+};
+
+#endif
+
+static const struct normal_encoding little2_encoding = {
+ { VTABLE, 2, 0,
+#if BYTEORDER == 1234
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_)
+};
+
+#if BYTEORDER != 4321
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_little2_encoding_ns = {
+ { VTABLE, 2, 0, 1 },
+ {
+#include "iasciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_)
+};
+
+#endif
+
+static const struct normal_encoding internal_little2_encoding = {
+ { VTABLE, 2, 0, 1 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_)
+};
+
+#endif
+
+
+#define BIG2_BYTE_TYPE(enc, p) \
+ ((p)[0] == 0 \
+ ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \
+ : unicode_byte_type((p)[0], (p)[1]))
+#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1)
+#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c)
+#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1])
+#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1])
+
+#ifdef XML_MIN_SIZE
+
+static int PTRFASTCALL
+big2_byteType(const ENCODING *enc, const char *p)
+{
+ return BIG2_BYTE_TYPE(enc, p);
+}
+
+static int PTRFASTCALL
+big2_byteToAscii(const ENCODING *enc, const char *p)
+{
+ return BIG2_BYTE_TO_ASCII(enc, p);
+}
+
+static int PTRCALL
+big2_charMatches(const ENCODING *enc, const char *p, int c)
+{
+ return BIG2_CHAR_MATCHES(enc, p, c);
+}
+
+static int PTRFASTCALL
+big2_isNameMin(const ENCODING *enc, const char *p)
+{
+ return BIG2_IS_NAME_CHAR_MINBPC(enc, p);
+}
+
+static int PTRFASTCALL
+big2_isNmstrtMin(const ENCODING *enc, const char *p)
+{
+ return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p);
+}
+
+#undef VTABLE
+#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16
+
+#else /* not XML_MIN_SIZE */
+
+#undef PREFIX
+#define PREFIX(ident) big2_ ## ident
+#define MINBPC(enc) 2
+/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
+#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p)
+#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p)
+#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c)
+#define IS_NAME_CHAR(enc, p, n) 0
+#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p)
+#define IS_NMSTRT_CHAR(enc, p, n) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p)
+
+#include "xmltok_impl.c"
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+#endif /* not XML_MIN_SIZE */
+
+#ifdef XML_NS
+
+static const struct normal_encoding big2_encoding_ns = {
+ { VTABLE, 2, 0,
+#if BYTEORDER == 4321
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#include "asciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_)
+};
+
+#endif
+
+static const struct normal_encoding big2_encoding = {
+ { VTABLE, 2, 0,
+#if BYTEORDER == 4321
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_)
+};
+
+#if BYTEORDER != 1234
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_big2_encoding_ns = {
+ { VTABLE, 2, 0, 1 },
+ {
+#include "iasciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_)
+};
+
+#endif
+
+static const struct normal_encoding internal_big2_encoding = {
+ { VTABLE, 2, 0, 1 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_)
+};
+
+#endif
+
+#undef PREFIX
+
+static int FASTCALL
+streqci(const char *s1, const char *s2)
+{
+ for (;;) {
+ char c1 = *s1++;
+ char c2 = *s2++;
+ if (ASCII_a <= c1 && c1 <= ASCII_z)
+ c1 += ASCII_A - ASCII_a;
+ if (ASCII_a <= c2 && c2 <= ASCII_z)
+ c2 += ASCII_A - ASCII_a;
+ if (c1 != c2)
+ return 0;
+ if (!c1)
+ break;
+ }
+ return 1;
+}
+
+static void PTRCALL
+initUpdatePosition(const ENCODING *enc, const char *ptr,
+ const char *end, POSITION *pos)
+{
+ normal_updatePosition(&utf8_encoding.enc, ptr, end, pos);
+}
+
+static int
+toAscii(const ENCODING *enc, const char *ptr, const char *end)
+{
+ char buf[1];
+ char *p = buf;
+ XmlUtf8Convert(enc, &ptr, end, &p, p + 1);
+ if (p == buf)
+ return -1;
+ else
+ return buf[0];
+}
+
+static int FASTCALL
+isSpace(int c)
+{
+ switch (c) {
+ case 0x20:
+ case 0xD:
+ case 0xA:
+ case 0x9:
+ return 1;
+ }
+ return 0;
+}
+
+/* Return 1 if there's just optional white space or there's an S
+ followed by name=val.
+*/
+static int
+parsePseudoAttribute(const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **namePtr,
+ const char **nameEndPtr,
+ const char **valPtr,
+ const char **nextTokPtr)
+{
+ int c;
+ char open;
+ if (ptr == end) {
+ *namePtr = NULL;
+ return 1;
+ }
+ if (!isSpace(toAscii(enc, ptr, end))) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ do {
+ ptr += enc->minBytesPerChar;
+ } while (isSpace(toAscii(enc, ptr, end)));
+ if (ptr == end) {
+ *namePtr = NULL;
+ return 1;
+ }
+ *namePtr = ptr;
+ for (;;) {
+ c = toAscii(enc, ptr, end);
+ if (c == -1) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ if (c == ASCII_EQUALS) {
+ *nameEndPtr = ptr;
+ break;
+ }
+ if (isSpace(c)) {
+ *nameEndPtr = ptr;
+ do {
+ ptr += enc->minBytesPerChar;
+ } while (isSpace(c = toAscii(enc, ptr, end)));
+ if (c != ASCII_EQUALS) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ break;
+ }
+ ptr += enc->minBytesPerChar;
+ }
+ if (ptr == *namePtr) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ ptr += enc->minBytesPerChar;
+ c = toAscii(enc, ptr, end);
+ while (isSpace(c)) {
+ ptr += enc->minBytesPerChar;
+ c = toAscii(enc, ptr, end);
+ }
+ if (c != ASCII_QUOT && c != ASCII_APOS) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ open = (char)c;
+ ptr += enc->minBytesPerChar;
+ *valPtr = ptr;
+ for (;; ptr += enc->minBytesPerChar) {
+ c = toAscii(enc, ptr, end);
+ if (c == open)
+ break;
+ if (!(ASCII_a <= c && c <= ASCII_z)
+ && !(ASCII_A <= c && c <= ASCII_Z)
+ && !(ASCII_0 <= c && c <= ASCII_9)
+ && c != ASCII_PERIOD
+ && c != ASCII_MINUS
+ && c != ASCII_UNDERSCORE) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ }
+ *nextTokPtr = ptr + enc->minBytesPerChar;
+ return 1;
+}
+
+static const char KW_version[] = {
+ ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0'
+};
+
+static const char KW_encoding[] = {
+ ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0'
+};
+
+static const char KW_standalone[] = {
+ ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o,
+ ASCII_n, ASCII_e, '\0'
+};
+
+static const char KW_yes[] = {
+ ASCII_y, ASCII_e, ASCII_s, '\0'
+};
+
+static const char KW_no[] = {
+ ASCII_n, ASCII_o, '\0'
+};
+
+static int
+doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *,
+ const char *,
+ const char *),
+ int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **versionEndPtr,
+ const char **encodingName,
+ const ENCODING **encoding,
+ int *standalone)
+{
+ const char *val = NULL;
+ const char *name = NULL;
+ const char *nameEnd = NULL;
+ ptr += 5 * enc->minBytesPerChar;
+ end -= 2 * enc->minBytesPerChar;
+ if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)
+ || !name) {
+ *badPtr = ptr;
+ return 0;
+ }
+ if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) {
+ if (!isGeneralTextEntity) {
+ *badPtr = name;
+ return 0;
+ }
+ }
+ else {
+ if (versionPtr)
+ *versionPtr = val;
+ if (versionEndPtr)
+ *versionEndPtr = ptr;
+ if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
+ *badPtr = ptr;
+ return 0;
+ }
+ if (!name) {
+ if (isGeneralTextEntity) {
+ /* a TextDecl must have an EncodingDecl */
+ *badPtr = ptr;
+ return 0;
+ }
+ return 1;
+ }
+ }
+ if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) {
+ int c = toAscii(enc, val, end);
+ if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) {
+ *badPtr = val;
+ return 0;
+ }
+ if (encodingName)
+ *encodingName = val;
+ if (encoding)
+ *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar);
+ if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
+ *badPtr = ptr;
+ return 0;
+ }
+ if (!name)
+ return 1;
+ }
+ if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone)
+ || isGeneralTextEntity) {
+ *badPtr = name;
+ return 0;
+ }
+ if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) {
+ if (standalone)
+ *standalone = 1;
+ }
+ else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) {
+ if (standalone)
+ *standalone = 0;
+ }
+ else {
+ *badPtr = val;
+ return 0;
+ }
+ while (isSpace(toAscii(enc, ptr, end)))
+ ptr += enc->minBytesPerChar;
+ if (ptr != end) {
+ *badPtr = ptr;
+ return 0;
+ }
+ return 1;
+}
+
+static int FASTCALL
+checkCharRefNumber(int result)
+{
+ switch (result >> 8) {
+ case 0xD8: case 0xD9: case 0xDA: case 0xDB:
+ case 0xDC: case 0xDD: case 0xDE: case 0xDF:
+ return -1;
+ case 0:
+ if (latin1_encoding.type[result] == BT_NONXML)
+ return -1;
+ break;
+ case 0xFF:
+ if (result == 0xFFFE || result == 0xFFFF)
+ return -1;
+ break;
+ }
+ return result;
+}
+
+int FASTCALL
+XmlUtf8Encode(int c, char *buf)
+{
+ enum {
+ /* minN is minimum legal resulting value for N byte sequence */
+ min2 = 0x80,
+ min3 = 0x800,
+ min4 = 0x10000
+ };
+
+ if (c < 0)
+ return 0;
+ if (c < min2) {
+ buf[0] = (char)(c | UTF8_cval1);
+ return 1;
+ }
+ if (c < min3) {
+ buf[0] = (char)((c >> 6) | UTF8_cval2);
+ buf[1] = (char)((c & 0x3f) | 0x80);
+ return 2;
+ }
+ if (c < min4) {
+ buf[0] = (char)((c >> 12) | UTF8_cval3);
+ buf[1] = (char)(((c >> 6) & 0x3f) | 0x80);
+ buf[2] = (char)((c & 0x3f) | 0x80);
+ return 3;
+ }
+ if (c < 0x110000) {
+ buf[0] = (char)((c >> 18) | UTF8_cval4);
+ buf[1] = (char)(((c >> 12) & 0x3f) | 0x80);
+ buf[2] = (char)(((c >> 6) & 0x3f) | 0x80);
+ buf[3] = (char)((c & 0x3f) | 0x80);
+ return 4;
+ }
+ return 0;
+}
+
+int FASTCALL
+XmlUtf16Encode(int charNum, unsigned short *buf)
+{
+ if (charNum < 0)
+ return 0;
+ if (charNum < 0x10000) {
+ buf[0] = (unsigned short)charNum;
+ return 1;
+ }
+ if (charNum < 0x110000) {
+ charNum -= 0x10000;
+ buf[0] = (unsigned short)((charNum >> 10) + 0xD800);
+ buf[1] = (unsigned short)((charNum & 0x3FF) + 0xDC00);
+ return 2;
+ }
+ return 0;
+}
+
+struct unknown_encoding {
+ struct normal_encoding normal;
+ CONVERTER convert;
+ void *userData;
+ unsigned short utf16[256];
+ char utf8[256][4];
+};
+
+#define AS_UNKNOWN_ENCODING(enc) ((const struct unknown_encoding *) (enc))
+
+int
+XmlSizeOfUnknownEncoding(void)
+{
+ return sizeof(struct unknown_encoding);
+}
+
+static int PTRFASTCALL
+unknown_isName(const ENCODING *enc, const char *p)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ int c = uenc->convert(uenc->userData, p);
+ if (c & ~0xFFFF)
+ return 0;
+ return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF);
+}
+
+static int PTRFASTCALL
+unknown_isNmstrt(const ENCODING *enc, const char *p)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ int c = uenc->convert(uenc->userData, p);
+ if (c & ~0xFFFF)
+ return 0;
+ return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF);
+}
+
+static int PTRFASTCALL
+unknown_isInvalid(const ENCODING *enc, const char *p)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ int c = uenc->convert(uenc->userData, p);
+ return (c & ~0xFFFF) || checkCharRefNumber(c) < 0;
+}
+
+static void PTRCALL
+unknown_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ char buf[XML_UTF8_ENCODE_MAX];
+ for (;;) {
+ const char *utf8;
+ int n;
+ if (*fromP == fromLim)
+ break;
+ utf8 = uenc->utf8[(unsigned char)**fromP];
+ n = *utf8++;
+ if (n == 0) {
+ int c = uenc->convert(uenc->userData, *fromP);
+ n = XmlUtf8Encode(c, buf);
+ if (n > toLim - *toP)
+ break;
+ utf8 = buf;
+ *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
+ - (BT_LEAD2 - 2));
+ }
+ else {
+ if (n > toLim - *toP)
+ break;
+ (*fromP)++;
+ }
+ do {
+ *(*toP)++ = *utf8++;
+ } while (--n != 0);
+ }
+}
+
+static void PTRCALL
+unknown_toUtf16(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ while (*fromP != fromLim && *toP != toLim) {
+ unsigned short c = uenc->utf16[(unsigned char)**fromP];
+ if (c == 0) {
+ c = (unsigned short)
+ uenc->convert(uenc->userData, *fromP);
+ *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
+ - (BT_LEAD2 - 2));
+ }
+ else
+ (*fromP)++;
+ *(*toP)++ = c;
+ }
+}
+
+ENCODING *
+XmlInitUnknownEncoding(void *mem,
+ int *table,
+ CONVERTER convert,
+ void *userData)
+{
+ int i;
+ struct unknown_encoding *e = (struct unknown_encoding *)mem;
+ for (i = 0; i < (int)sizeof(struct normal_encoding); i++)
+ ((char *)mem)[i] = ((char *)&latin1_encoding)[i];
+ for (i = 0; i < 128; i++)
+ if (latin1_encoding.type[i] != BT_OTHER
+ && latin1_encoding.type[i] != BT_NONXML
+ && table[i] != i)
+ return 0;
+ for (i = 0; i < 256; i++) {
+ int c = table[i];
+ if (c == -1) {
+ e->normal.type[i] = BT_MALFORM;
+ /* This shouldn't really get used. */
+ e->utf16[i] = 0xFFFF;
+ e->utf8[i][0] = 1;
+ e->utf8[i][1] = 0;
+ }
+ else if (c < 0) {
+ if (c < -4)
+ return 0;
+ e->normal.type[i] = (unsigned char)(BT_LEAD2 - (c + 2));
+ e->utf8[i][0] = 0;
+ e->utf16[i] = 0;
+ }
+ else if (c < 0x80) {
+ if (latin1_encoding.type[c] != BT_OTHER
+ && latin1_encoding.type[c] != BT_NONXML
+ && c != i)
+ return 0;
+ e->normal.type[i] = latin1_encoding.type[c];
+ e->utf8[i][0] = 1;
+ e->utf8[i][1] = (char)c;
+ e->utf16[i] = (unsigned short)(c == 0 ? 0xFFFF : c);
+ }
+ else if (checkCharRefNumber(c) < 0) {
+ e->normal.type[i] = BT_NONXML;
+ /* This shouldn't really get used. */
+ e->utf16[i] = 0xFFFF;
+ e->utf8[i][0] = 1;
+ e->utf8[i][1] = 0;
+ }
+ else {
+ if (c > 0xFFFF)
+ return 0;
+ if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff))
+ e->normal.type[i] = BT_NMSTRT;
+ else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff))
+ e->normal.type[i] = BT_NAME;
+ else
+ e->normal.type[i] = BT_OTHER;
+ e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1);
+ e->utf16[i] = (unsigned short)c;
+ }
+ }
+ e->userData = userData;
+ e->convert = convert;
+ if (convert) {
+ e->normal.isName2 = unknown_isName;
+ e->normal.isName3 = unknown_isName;
+ e->normal.isName4 = unknown_isName;
+ e->normal.isNmstrt2 = unknown_isNmstrt;
+ e->normal.isNmstrt3 = unknown_isNmstrt;
+ e->normal.isNmstrt4 = unknown_isNmstrt;
+ e->normal.isInvalid2 = unknown_isInvalid;
+ e->normal.isInvalid3 = unknown_isInvalid;
+ e->normal.isInvalid4 = unknown_isInvalid;
+ }
+ e->normal.enc.utf8Convert = unknown_toUtf8;
+ e->normal.enc.utf16Convert = unknown_toUtf16;
+ return &(e->normal.enc);
+}
+
+/* If this enumeration is changed, getEncodingIndex and encodings
+must also be changed. */
+enum {
+ UNKNOWN_ENC = -1,
+ ISO_8859_1_ENC = 0,
+ US_ASCII_ENC,
+ UTF_8_ENC,
+ UTF_16_ENC,
+ UTF_16BE_ENC,
+ UTF_16LE_ENC,
+ /* must match encodingNames up to here */
+ NO_ENC
+};
+
+static const char KW_ISO_8859_1[] = {
+ ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9,
+ ASCII_MINUS, ASCII_1, '\0'
+};
+static const char KW_US_ASCII[] = {
+ ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I,
+ '\0'
+};
+static const char KW_UTF_8[] = {
+ ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0'
+};
+static const char KW_UTF_16[] = {
+ ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0'
+};
+static const char KW_UTF_16BE[] = {
+ ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E,
+ '\0'
+};
+static const char KW_UTF_16LE[] = {
+ ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E,
+ '\0'
+};
+
+static int FASTCALL
+getEncodingIndex(const char *name)
+{
+ static const char * const encodingNames[] = {
+ KW_ISO_8859_1,
+ KW_US_ASCII,
+ KW_UTF_8,
+ KW_UTF_16,
+ KW_UTF_16BE,
+ KW_UTF_16LE,
+ };
+ int i;
+ if (name == NULL)
+ return NO_ENC;
+ for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++)
+ if (streqci(name, encodingNames[i]))
+ return i;
+ return UNKNOWN_ENC;
+}
+
+/* For binary compatibility, we store the index of the encoding
+ specified at initialization in the isUtf16 member.
+*/
+
+#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16)
+#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i)
+
+/* This is what detects the encoding. encodingTable maps from
+ encoding indices to encodings; INIT_ENC_INDEX(enc) is the index of
+ the external (protocol) specified encoding; state is
+ XML_CONTENT_STATE if we're parsing an external text entity, and
+ XML_PROLOG_STATE otherwise.
+*/
+
+
+static int
+initScan(const ENCODING * const *encodingTable,
+ const INIT_ENCODING *enc,
+ int state,
+ const char *ptr,
+ const char *end,
+ const char **nextTokPtr)
+{
+ const ENCODING **encPtr;
+
+ if (ptr == end)
+ return XML_TOK_NONE;
+ encPtr = enc->encPtr;
+ if (ptr + 1 == end) {
+ /* only a single byte available for auto-detection */
+#ifndef XML_DTD /* FIXME */
+ /* a well-formed document entity must have more than one byte */
+ if (state != XML_CONTENT_STATE)
+ return XML_TOK_PARTIAL;
+#endif
+ /* so we're parsing an external text entity... */
+ /* if UTF-16 was externally specified, then we need at least 2 bytes */
+ switch (INIT_ENC_INDEX(enc)) {
+ case UTF_16_ENC:
+ case UTF_16LE_ENC:
+ case UTF_16BE_ENC:
+ return XML_TOK_PARTIAL;
+ }
+ switch ((unsigned char)*ptr) {
+ case 0xFE:
+ case 0xFF:
+ case 0xEF: /* possibly first byte of UTF-8 BOM */
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+ && state == XML_CONTENT_STATE)
+ break;
+ /* fall through */
+ case 0x00:
+ case 0x3C:
+ return XML_TOK_PARTIAL;
+ }
+ }
+ else {
+ switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) {
+ case 0xFEFF:
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+ && state == XML_CONTENT_STATE)
+ break;
+ *nextTokPtr = ptr + 2;
+ *encPtr = encodingTable[UTF_16BE_ENC];
+ return XML_TOK_BOM;
+ /* 00 3C is handled in the default case */
+ case 0x3C00:
+ if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC
+ || INIT_ENC_INDEX(enc) == UTF_16_ENC)
+ && state == XML_CONTENT_STATE)
+ break;
+ *encPtr = encodingTable[UTF_16LE_ENC];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+ case 0xFFFE:
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+ && state == XML_CONTENT_STATE)
+ break;
+ *nextTokPtr = ptr + 2;
+ *encPtr = encodingTable[UTF_16LE_ENC];
+ return XML_TOK_BOM;
+ case 0xEFBB:
+ /* Maybe a UTF-8 BOM (EF BB BF) */
+ /* If there's an explicitly specified (external) encoding
+ of ISO-8859-1 or some flavour of UTF-16
+ and this is an external text entity,
+ don't look for the BOM,
+ because it might be a legal data.
+ */
+ if (state == XML_CONTENT_STATE) {
+ int e = INIT_ENC_INDEX(enc);
+ if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC
+ || e == UTF_16LE_ENC || e == UTF_16_ENC)
+ break;
+ }
+ if (ptr + 2 == end)
+ return XML_TOK_PARTIAL;
+ if ((unsigned char)ptr[2] == 0xBF) {
+ *nextTokPtr = ptr + 3;
+ *encPtr = encodingTable[UTF_8_ENC];
+ return XML_TOK_BOM;
+ }
+ break;
+ default:
+ if (ptr[0] == '\0') {
+ /* 0 isn't a legal data character. Furthermore a document
+ entity can only start with ASCII characters. So the only
+ way this can fail to be big-endian UTF-16 if it it's an
+ external parsed general entity that's labelled as
+ UTF-16LE.
+ */
+ if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC)
+ break;
+ *encPtr = encodingTable[UTF_16BE_ENC];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+ }
+ else if (ptr[1] == '\0') {
+ /* We could recover here in the case:
+ - parsing an external entity
+ - second byte is 0
+ - no externally specified encoding
+ - no encoding declaration
+ by assuming UTF-16LE. But we don't, because this would mean when
+ presented just with a single byte, we couldn't reliably determine
+ whether we needed further bytes.
+ */
+ if (state == XML_CONTENT_STATE)
+ break;
+ *encPtr = encodingTable[UTF_16LE_ENC];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+ }
+ break;
+ }
+ }
+ *encPtr = encodingTable[INIT_ENC_INDEX(enc)];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+}
+
+
+#define NS(x) x
+#define ns(x) x
+#include "xmltok_ns.c"
+#undef NS
+#undef ns
+
+#ifdef XML_NS
+
+#define NS(x) x ## NS
+#define ns(x) x ## _ns
+
+#include "xmltok_ns.c"
+
+#undef NS
+#undef ns
+
+ENCODING *
+XmlInitUnknownEncodingNS(void *mem,
+ int *table,
+ CONVERTER convert,
+ void *userData)
+{
+ ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData);
+ if (enc)
+ ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON;
+ return enc;
+}
+
+#endif /* XML_NS */
diff --git a/src/lib/expat/xmltok.h b/src/lib/expat/xmltok.h
new file mode 100644
index 00000000000..ca867aa6b42
--- /dev/null
+++ b/src/lib/expat/xmltok.h
@@ -0,0 +1,316 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef XmlTok_INCLUDED
+#define XmlTok_INCLUDED 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The following token may be returned by XmlContentTok */
+#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be
+ start of illegal ]]> sequence */
+/* The following tokens may be returned by both XmlPrologTok and
+ XmlContentTok.
+*/
+#define XML_TOK_NONE -4 /* The string to be scanned is empty */
+#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan;
+ might be part of CRLF sequence */
+#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */
+#define XML_TOK_PARTIAL -1 /* only part of a token */
+#define XML_TOK_INVALID 0
+
+/* The following tokens are returned by XmlContentTok; some are also
+ returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok.
+*/
+#define XML_TOK_START_TAG_WITH_ATTS 1
+#define XML_TOK_START_TAG_NO_ATTS 2
+#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */
+#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4
+#define XML_TOK_END_TAG 5
+#define XML_TOK_DATA_CHARS 6
+#define XML_TOK_DATA_NEWLINE 7
+#define XML_TOK_CDATA_SECT_OPEN 8
+#define XML_TOK_ENTITY_REF 9
+#define XML_TOK_CHAR_REF 10 /* numeric character reference */
+
+/* The following tokens may be returned by both XmlPrologTok and
+ XmlContentTok.
+*/
+#define XML_TOK_PI 11 /* processing instruction */
+#define XML_TOK_XML_DECL 12 /* XML decl or text decl */
+#define XML_TOK_COMMENT 13
+#define XML_TOK_BOM 14 /* Byte order mark */
+
+/* The following tokens are returned only by XmlPrologTok */
+#define XML_TOK_PROLOG_S 15
+#define XML_TOK_DECL_OPEN 16 /* <!foo */
+#define XML_TOK_DECL_CLOSE 17 /* > */
+#define XML_TOK_NAME 18
+#define XML_TOK_NMTOKEN 19
+#define XML_TOK_POUND_NAME 20 /* #name */
+#define XML_TOK_OR 21 /* | */
+#define XML_TOK_PERCENT 22
+#define XML_TOK_OPEN_PAREN 23
+#define XML_TOK_CLOSE_PAREN 24
+#define XML_TOK_OPEN_BRACKET 25
+#define XML_TOK_CLOSE_BRACKET 26
+#define XML_TOK_LITERAL 27
+#define XML_TOK_PARAM_ENTITY_REF 28
+#define XML_TOK_INSTANCE_START 29
+
+/* The following occur only in element type declarations */
+#define XML_TOK_NAME_QUESTION 30 /* name? */
+#define XML_TOK_NAME_ASTERISK 31 /* name* */
+#define XML_TOK_NAME_PLUS 32 /* name+ */
+#define XML_TOK_COND_SECT_OPEN 33 /* <![ */
+#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */
+#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */
+#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */
+#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */
+#define XML_TOK_COMMA 38
+
+/* The following token is returned only by XmlAttributeValueTok */
+#define XML_TOK_ATTRIBUTE_VALUE_S 39
+
+/* The following token is returned only by XmlCdataSectionTok */
+#define XML_TOK_CDATA_SECT_CLOSE 40
+
+/* With namespace processing this is returned by XmlPrologTok for a
+ name with a colon.
+*/
+#define XML_TOK_PREFIXED_NAME 41
+
+#ifdef XML_DTD
+#define XML_TOK_IGNORE_SECT 42
+#endif /* XML_DTD */
+
+#ifdef XML_DTD
+#define XML_N_STATES 4
+#else /* not XML_DTD */
+#define XML_N_STATES 3
+#endif /* not XML_DTD */
+
+#define XML_PROLOG_STATE 0
+#define XML_CONTENT_STATE 1
+#define XML_CDATA_SECTION_STATE 2
+#ifdef XML_DTD
+#define XML_IGNORE_SECTION_STATE 3
+#endif /* XML_DTD */
+
+#define XML_N_LITERAL_TYPES 2
+#define XML_ATTRIBUTE_VALUE_LITERAL 0
+#define XML_ENTITY_VALUE_LITERAL 1
+
+/* The size of the buffer passed to XmlUtf8Encode must be at least this. */
+#define XML_UTF8_ENCODE_MAX 4
+/* The size of the buffer passed to XmlUtf16Encode must be at least this. */
+#define XML_UTF16_ENCODE_MAX 2
+
+typedef struct position {
+ /* first line and first column are 0 not 1 */
+ XML_Size lineNumber;
+ XML_Size columnNumber;
+} POSITION;
+
+typedef struct {
+ const char *name;
+ const char *valuePtr;
+ const char *valueEnd;
+ char normalized;
+} ATTRIBUTE;
+
+struct encoding;
+typedef struct encoding ENCODING;
+
+typedef int (PTRCALL *SCANNER)(const ENCODING *,
+ const char *,
+ const char *,
+ const char **);
+
+struct encoding {
+ SCANNER scanners[XML_N_STATES];
+ SCANNER literalScanners[XML_N_LITERAL_TYPES];
+ int (PTRCALL *sameName)(const ENCODING *,
+ const char *,
+ const char *);
+ int (PTRCALL *nameMatchesAscii)(const ENCODING *,
+ const char *,
+ const char *,
+ const char *);
+ int (PTRFASTCALL *nameLength)(const ENCODING *, const char *);
+ const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *);
+ int (PTRCALL *getAtts)(const ENCODING *enc,
+ const char *ptr,
+ int attsMax,
+ ATTRIBUTE *atts);
+ int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr);
+ int (PTRCALL *predefinedEntityName)(const ENCODING *,
+ const char *,
+ const char *);
+ void (PTRCALL *updatePosition)(const ENCODING *,
+ const char *ptr,
+ const char *end,
+ POSITION *);
+ int (PTRCALL *isPublicId)(const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr);
+ void (PTRCALL *utf8Convert)(const ENCODING *enc,
+ const char **fromP,
+ const char *fromLim,
+ char **toP,
+ const char *toLim);
+ void (PTRCALL *utf16Convert)(const ENCODING *enc,
+ const char **fromP,
+ const char *fromLim,
+ unsigned short **toP,
+ const unsigned short *toLim);
+ int minBytesPerChar;
+ char isUtf8;
+ char isUtf16;
+};
+
+/* Scan the string starting at ptr until the end of the next complete
+ token, but do not scan past eptr. Return an integer giving the
+ type of token.
+
+ Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set.
+
+ Return XML_TOK_PARTIAL when the string does not contain a complete
+ token; nextTokPtr will not be set.
+
+ Return XML_TOK_INVALID when the string does not start a valid
+ token; nextTokPtr will be set to point to the character which made
+ the token invalid.
+
+ Otherwise the string starts with a valid token; nextTokPtr will be
+ set to point to the character following the end of that token.
+
+ Each data character counts as a single token, but adjacent data
+ characters may be returned together. Similarly for characters in
+ the prolog outside literals, comments and processing instructions.
+*/
+
+
+#define XmlTok(enc, state, ptr, end, nextTokPtr) \
+ (((enc)->scanners[state])(enc, ptr, end, nextTokPtr))
+
+#define XmlPrologTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr)
+
+#define XmlContentTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr)
+
+#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr)
+
+#ifdef XML_DTD
+
+#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr)
+
+#endif /* XML_DTD */
+
+/* This is used for performing a 2nd-level tokenization on the content
+ of a literal that has already been returned by XmlTok.
+*/
+#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \
+ (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr))
+
+#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \
+ XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr)
+
+#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
+ XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
+
+#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
+
+#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
+ (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2))
+
+#define XmlNameLength(enc, ptr) \
+ (((enc)->nameLength)(enc, ptr))
+
+#define XmlSkipS(enc, ptr) \
+ (((enc)->skipS)(enc, ptr))
+
+#define XmlGetAttributes(enc, ptr, attsMax, atts) \
+ (((enc)->getAtts)(enc, ptr, attsMax, atts))
+
+#define XmlCharRefNumber(enc, ptr) \
+ (((enc)->charRefNumber)(enc, ptr))
+
+#define XmlPredefinedEntityName(enc, ptr, end) \
+ (((enc)->predefinedEntityName)(enc, ptr, end))
+
+#define XmlUpdatePosition(enc, ptr, end, pos) \
+ (((enc)->updatePosition)(enc, ptr, end, pos))
+
+#define XmlIsPublicId(enc, ptr, end, badPtr) \
+ (((enc)->isPublicId)(enc, ptr, end, badPtr))
+
+#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \
+ (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim))
+
+#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \
+ (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim))
+
+typedef struct {
+ ENCODING initEnc;
+ const ENCODING **encPtr;
+} INIT_ENCODING;
+
+int XmlParseXmlDecl(int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **versionEndPtr,
+ const char **encodingNamePtr,
+ const ENCODING **namedEncodingPtr,
+ int *standalonePtr);
+
+int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name);
+const ENCODING *XmlGetUtf8InternalEncoding(void);
+const ENCODING *XmlGetUtf16InternalEncoding(void);
+int FASTCALL XmlUtf8Encode(int charNumber, char *buf);
+int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf);
+int XmlSizeOfUnknownEncoding(void);
+
+
+typedef int (XMLCALL *CONVERTER) (void *userData, const char *p);
+
+ENCODING *
+XmlInitUnknownEncoding(void *mem,
+ int *table,
+ CONVERTER convert,
+ void *userData);
+
+int XmlParseXmlDeclNS(int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **versionEndPtr,
+ const char **encodingNamePtr,
+ const ENCODING **namedEncodingPtr,
+ int *standalonePtr);
+
+int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name);
+const ENCODING *XmlGetUtf8InternalEncodingNS(void);
+const ENCODING *XmlGetUtf16InternalEncodingNS(void);
+ENCODING *
+XmlInitUnknownEncodingNS(void *mem,
+ int *table,
+ CONVERTER convert,
+ void *userData);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not XmlTok_INCLUDED */
diff --git a/src/lib/expat/xmltok_impl.c b/src/lib/expat/xmltok_impl.c
new file mode 100644
index 00000000000..0ee57abb1f4
--- /dev/null
+++ b/src/lib/expat/xmltok_impl.c
@@ -0,0 +1,1779 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef IS_INVALID_CHAR
+#define IS_INVALID_CHAR(enc, ptr, n) (0)
+#endif
+
+#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (IS_INVALID_CHAR(enc, ptr, n)) { \
+ *(nextTokPtr) = (ptr); \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+#define INVALID_CASES(ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(2, ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(3, ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(4, ptr, nextTokPtr) \
+ case BT_NONXML: \
+ case BT_MALFORM: \
+ case BT_TRAIL: \
+ *(nextTokPtr) = (ptr); \
+ return XML_TOK_INVALID;
+
+#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (!IS_NAME_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \
+ case BT_NONASCII: \
+ if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ case BT_NMSTRT: \
+ case BT_HEX: \
+ case BT_DIGIT: \
+ case BT_NAME: \
+ case BT_MINUS: \
+ ptr += MINBPC(enc); \
+ break; \
+ CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \
+ CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \
+ CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr)
+
+#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \
+ case BT_NONASCII: \
+ if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ case BT_NMSTRT: \
+ case BT_HEX: \
+ ptr += MINBPC(enc); \
+ break; \
+ CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \
+ CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \
+ CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr)
+
+#ifndef PREFIX
+#define PREFIX(ident) ident
+#endif
+
+/* ptr points to character following "<!-" */
+
+static int PTRCALL
+PREFIX(scanComment)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr != end) {
+ if (!CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ ptr += MINBPC(enc);
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_MINUS:
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_COMMENT;
+ }
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "<!" */
+
+static int PTRCALL
+PREFIX(scanDecl)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_MINUS:
+ return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_LSQB:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_COND_SECT_OPEN;
+ case BT_NMSTRT:
+ case BT_HEX:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_PERCNT:
+ if (ptr + MINBPC(enc) == end)
+ return XML_TOK_PARTIAL;
+ /* don't allow <!ENTITY% foo "whatever"> */
+ switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) {
+ case BT_S: case BT_CR: case BT_LF: case BT_PERCNT:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ /* fall through */
+ case BT_S: case BT_CR: case BT_LF:
+ *nextTokPtr = ptr;
+ return XML_TOK_DECL_OPEN;
+ case BT_NMSTRT:
+ case BT_HEX:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr,
+ const char *end, int *tokPtr)
+{
+ int upper = 0;
+ *tokPtr = XML_TOK_PI;
+ if (end - ptr != MINBPC(enc)*3)
+ return 1;
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_x:
+ break;
+ case ASCII_X:
+ upper = 1;
+ break;
+ default:
+ return 1;
+ }
+ ptr += MINBPC(enc);
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_m:
+ break;
+ case ASCII_M:
+ upper = 1;
+ break;
+ default:
+ return 1;
+ }
+ ptr += MINBPC(enc);
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_l:
+ break;
+ case ASCII_L:
+ upper = 1;
+ break;
+ default:
+ return 1;
+ }
+ if (upper)
+ return 0;
+ *tokPtr = XML_TOK_XML_DECL;
+ return 1;
+}
+
+/* ptr points to character following "<?" */
+
+static int PTRCALL
+PREFIX(scanPi)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ int tok;
+ const char *target = ptr;
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_CR: case BT_LF:
+ if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ ptr += MINBPC(enc);
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_QUEST:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return tok;
+ }
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ return XML_TOK_PARTIAL;
+ case BT_QUEST:
+ if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return tok;
+ }
+ /* fall through */
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ static const char CDATA_LSQB[] = { ASCII_C, ASCII_D, ASCII_A,
+ ASCII_T, ASCII_A, ASCII_LSQB };
+ int i;
+ /* CDATA[ */
+ if (end - ptr < 6 * MINBPC(enc))
+ return XML_TOK_PARTIAL;
+ for (i = 0; i < 6; i++, ptr += MINBPC(enc)) {
+ if (!CHAR_MATCHES(enc, ptr, CDATA_LSQB[i])) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_CDATA_SECT_OPEN;
+}
+
+static int PTRCALL
+PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_NONE;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ if (n == 0)
+ return XML_TOK_PARTIAL;
+ end = ptr + n;
+ }
+ }
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
+ break;
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ ptr -= MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CDATA_SECT_CLOSE;
+ case BT_CR:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ case BT_LF:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ INVALID_CASES(ptr, nextTokPtr)
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_DATA_CHARS; \
+ } \
+ ptr += n; \
+ break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NONXML:
+ case BT_MALFORM:
+ case BT_TRAIL:
+ case BT_CR:
+ case BT_LF:
+ case BT_RSQB:
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+/* ptr points to character following "</" */
+
+static int PTRCALL
+PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_CR: case BT_LF:
+ for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S: case BT_CR: case BT_LF:
+ break;
+ case BT_GT:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_END_TAG;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+#ifdef XML_NS
+ case BT_COLON:
+ /* no need to check qname syntax here,
+ since end-tag must match exactly */
+ ptr += MINBPC(enc);
+ break;
+#endif
+ case BT_GT:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_END_TAG;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&#X" */
+
+static int PTRCALL
+PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ case BT_HEX:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ case BT_HEX:
+ break;
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CHAR_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&#" */
+
+static int PTRCALL
+PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr != end) {
+ if (CHAR_MATCHES(enc, ptr, ASCII_x))
+ return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ break;
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CHAR_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&" */
+
+static int PTRCALL
+PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_NUM:
+ return PREFIX(scanCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_ENTITY_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following first character of attribute name */
+
+static int PTRCALL
+PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+#ifdef XML_NS
+ int hadColon = 0;
+#endif
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+#ifdef XML_NS
+ case BT_COLON:
+ if (hadColon) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ hadColon = 1;
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ break;
+#endif
+ case BT_S: case BT_CR: case BT_LF:
+ for (;;) {
+ int t;
+
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ t = BYTE_TYPE(enc, ptr);
+ if (t == BT_EQUALS)
+ break;
+ switch (t) {
+ case BT_S:
+ case BT_LF:
+ case BT_CR:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ /* fall through */
+ case BT_EQUALS:
+ {
+ int open;
+#ifdef XML_NS
+ hadColon = 0;
+#endif
+ for (;;) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ open = BYTE_TYPE(enc, ptr);
+ if (open == BT_QUOT || open == BT_APOS)
+ break;
+ switch (open) {
+ case BT_S:
+ case BT_LF:
+ case BT_CR:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ ptr += MINBPC(enc);
+ /* in attribute value */
+ for (;;) {
+ int t;
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ t = BYTE_TYPE(enc, ptr);
+ if (t == open)
+ break;
+ switch (t) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_AMP:
+ {
+ int tok = PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, &ptr);
+ if (tok <= 0) {
+ if (tok == XML_TOK_INVALID)
+ *nextTokPtr = ptr;
+ return tok;
+ }
+ break;
+ }
+ case BT_LT:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
+ break;
+ case BT_SOL:
+ goto sol;
+ case BT_GT:
+ goto gt;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ /* ptr points to closing quote */
+ for (;;) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_CR: case BT_LF:
+ continue;
+ case BT_GT:
+ gt:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_START_TAG_WITH_ATTS;
+ case BT_SOL:
+ sol:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_EMPTY_ELEMENT_WITH_ATTS;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ break;
+ }
+ break;
+ }
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "<" */
+
+static int PTRCALL
+PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+#ifdef XML_NS
+ int hadColon;
+#endif
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_EXCL:
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_MINUS:
+ return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_LSQB:
+ return PREFIX(scanCdataSection)(enc, ptr + MINBPC(enc),
+ end, nextTokPtr);
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ case BT_QUEST:
+ return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_SOL:
+ return PREFIX(scanEndTag)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+#ifdef XML_NS
+ hadColon = 0;
+#endif
+ /* we have a start-tag */
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+#ifdef XML_NS
+ case BT_COLON:
+ if (hadColon) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ hadColon = 1;
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ break;
+#endif
+ case BT_S: case BT_CR: case BT_LF:
+ {
+ ptr += MINBPC(enc);
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_GT:
+ goto gt;
+ case BT_SOL:
+ goto sol;
+ case BT_S: case BT_CR: case BT_LF:
+ ptr += MINBPC(enc);
+ continue;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr);
+ }
+ return XML_TOK_PARTIAL;
+ }
+ case BT_GT:
+ gt:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_START_TAG_NO_ATTS;
+ case BT_SOL:
+ sol:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_EMPTY_ELEMENT_NO_ATTS;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_NONE;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ if (n == 0)
+ return XML_TOK_PARTIAL;
+ end = ptr + n;
+ }
+ }
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_LT:
+ return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_AMP:
+ return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_CR:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_CR;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ case BT_LF:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_RSQB;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
+ break;
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_RSQB;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ ptr -= MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ INVALID_CASES(ptr, nextTokPtr)
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_DATA_CHARS; \
+ } \
+ ptr += n; \
+ break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_RSQB:
+ if (ptr + MINBPC(enc) != end) {
+ if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) {
+ ptr += MINBPC(enc);
+ break;
+ }
+ if (ptr + 2*MINBPC(enc) != end) {
+ if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) {
+ ptr += MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr + 2*MINBPC(enc);
+ return XML_TOK_INVALID;
+ }
+ }
+ /* fall through */
+ case BT_AMP:
+ case BT_LT:
+ case BT_NONXML:
+ case BT_MALFORM:
+ case BT_TRAIL:
+ case BT_CR:
+ case BT_LF:
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+/* ptr points to character following "%" */
+
+static int PTRCALL
+PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return -XML_TOK_PERCENT;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_LF: case BT_CR: case BT_PERCNT:
+ *nextTokPtr = ptr;
+ return XML_TOK_PERCENT;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_PARAM_ENTITY_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_CR: case BT_LF: case BT_S:
+ case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR:
+ *nextTokPtr = ptr;
+ return XML_TOK_POUND_NAME;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return -XML_TOK_POUND_NAME;
+}
+
+static int PTRCALL
+PREFIX(scanLit)(int open, const ENCODING *enc,
+ const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ while (ptr != end) {
+ int t = BYTE_TYPE(enc, ptr);
+ switch (t) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_QUOT:
+ case BT_APOS:
+ ptr += MINBPC(enc);
+ if (t != open)
+ break;
+ if (ptr == end)
+ return -XML_TOK_LITERAL;
+ *nextTokPtr = ptr;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S: case BT_CR: case BT_LF:
+ case BT_GT: case BT_PERCNT: case BT_LSQB:
+ return XML_TOK_LITERAL;
+ default:
+ return XML_TOK_INVALID;
+ }
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ int tok;
+ if (ptr == end)
+ return XML_TOK_NONE;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ if (n == 0)
+ return XML_TOK_PARTIAL;
+ end = ptr + n;
+ }
+ }
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_QUOT:
+ return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_APOS:
+ return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_LT:
+ {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_EXCL:
+ return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_QUEST:
+ return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_NMSTRT:
+ case BT_HEX:
+ case BT_NONASCII:
+ case BT_LEAD2:
+ case BT_LEAD3:
+ case BT_LEAD4:
+ *nextTokPtr = ptr - MINBPC(enc);
+ return XML_TOK_INSTANCE_START;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ case BT_CR:
+ if (ptr + MINBPC(enc) == end) {
+ *nextTokPtr = end;
+ /* indicate that this might be part of a CR/LF pair */
+ return -XML_TOK_PROLOG_S;
+ }
+ /* fall through */
+ case BT_S: case BT_LF:
+ for (;;) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ break;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S: case BT_LF:
+ break;
+ case BT_CR:
+ /* don't split CR/LF pair */
+ if (ptr + MINBPC(enc) != end)
+ break;
+ /* fall through */
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_PROLOG_S;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_PROLOG_S;
+ case BT_PERCNT:
+ return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_COMMA:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_COMMA;
+ case BT_LSQB:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_OPEN_BRACKET;
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return -XML_TOK_CLOSE_BRACKET;
+ if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
+ if (ptr + MINBPC(enc) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) {
+ *nextTokPtr = ptr + 2*MINBPC(enc);
+ return XML_TOK_COND_SECT_CLOSE;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_CLOSE_BRACKET;
+ case BT_LPAR:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_OPEN_PAREN;
+ case BT_RPAR:
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return -XML_TOK_CLOSE_PAREN;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_AST:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CLOSE_PAREN_ASTERISK;
+ case BT_QUEST:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CLOSE_PAREN_QUESTION;
+ case BT_PLUS:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CLOSE_PAREN_PLUS;
+ case BT_CR: case BT_LF: case BT_S:
+ case BT_GT: case BT_COMMA: case BT_VERBAR:
+ case BT_RPAR:
+ *nextTokPtr = ptr;
+ return XML_TOK_CLOSE_PAREN;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ case BT_VERBAR:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_OR;
+ case BT_GT:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DECL_CLOSE;
+ case BT_NUM:
+ return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (IS_NMSTRT_CHAR(enc, ptr, n)) { \
+ ptr += n; \
+ tok = XML_TOK_NAME; \
+ break; \
+ } \
+ if (IS_NAME_CHAR(enc, ptr, n)) { \
+ ptr += n; \
+ tok = XML_TOK_NMTOKEN; \
+ break; \
+ } \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NMSTRT:
+ case BT_HEX:
+ tok = XML_TOK_NAME;
+ ptr += MINBPC(enc);
+ break;
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ tok = XML_TOK_NMTOKEN;
+ ptr += MINBPC(enc);
+ break;
+ case BT_NONASCII:
+ if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) {
+ ptr += MINBPC(enc);
+ tok = XML_TOK_NAME;
+ break;
+ }
+ if (IS_NAME_CHAR_MINBPC(enc, ptr)) {
+ ptr += MINBPC(enc);
+ tok = XML_TOK_NMTOKEN;
+ break;
+ }
+ /* fall through */
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_GT: case BT_RPAR: case BT_COMMA:
+ case BT_VERBAR: case BT_LSQB: case BT_PERCNT:
+ case BT_S: case BT_CR: case BT_LF:
+ *nextTokPtr = ptr;
+ return tok;
+#ifdef XML_NS
+ case BT_COLON:
+ ptr += MINBPC(enc);
+ switch (tok) {
+ case XML_TOK_NAME:
+ if (ptr == end)
+ return XML_TOK_PARTIAL;
+ tok = XML_TOK_PREFIXED_NAME;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ tok = XML_TOK_NMTOKEN;
+ break;
+ }
+ break;
+ case XML_TOK_PREFIXED_NAME:
+ tok = XML_TOK_NMTOKEN;
+ break;
+ }
+ break;
+#endif
+ case BT_PLUS:
+ if (tok == XML_TOK_NMTOKEN) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_NAME_PLUS;
+ case BT_AST:
+ if (tok == XML_TOK_NMTOKEN) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_NAME_ASTERISK;
+ case BT_QUEST:
+ if (tok == XML_TOK_NMTOKEN) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_NAME_QUESTION;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return -tok;
+}
+
+static int PTRCALL
+PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ const char *start;
+ if (ptr == end)
+ return XML_TOK_NONE;
+ start = ptr;
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: ptr += n; break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_AMP:
+ if (ptr == start)
+ return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_LT:
+ /* this is for inside entity references */
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ case BT_LF:
+ if (ptr == start) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_CR:
+ if (ptr == start) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_CR;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_S:
+ if (ptr == start) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_ATTRIBUTE_VALUE_S;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+static int PTRCALL
+PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ const char *start;
+ if (ptr == end)
+ return XML_TOK_NONE;
+ start = ptr;
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: ptr += n; break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_AMP:
+ if (ptr == start)
+ return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_PERCNT:
+ if (ptr == start) {
+ int tok = PREFIX(scanPercent)(enc, ptr + MINBPC(enc),
+ end, nextTokPtr);
+ return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_LF:
+ if (ptr == start) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_CR:
+ if (ptr == start) {
+ ptr += MINBPC(enc);
+ if (ptr == end)
+ return XML_TOK_TRAILING_CR;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+#ifdef XML_DTD
+
+static int PTRCALL
+PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ int level = 0;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ end = ptr + n;
+ }
+ }
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_LT:
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) {
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) {
+ ++level;
+ ptr += MINBPC(enc);
+ }
+ }
+ break;
+ case BT_RSQB:
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
+ if ((ptr += MINBPC(enc)) == end)
+ return XML_TOK_PARTIAL;
+ if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ ptr += MINBPC(enc);
+ if (level == 0) {
+ *nextTokPtr = ptr;
+ return XML_TOK_IGNORE_SECT;
+ }
+ --level;
+ }
+ }
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+#endif /* XML_DTD */
+
+static int PTRCALL
+PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **badPtr)
+{
+ ptr += MINBPC(enc);
+ end -= MINBPC(enc);
+ for (; ptr != end; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ case BT_HEX:
+ case BT_MINUS:
+ case BT_APOS:
+ case BT_LPAR:
+ case BT_RPAR:
+ case BT_PLUS:
+ case BT_COMMA:
+ case BT_SOL:
+ case BT_EQUALS:
+ case BT_QUEST:
+ case BT_CR:
+ case BT_LF:
+ case BT_SEMI:
+ case BT_EXCL:
+ case BT_AST:
+ case BT_PERCNT:
+ case BT_NUM:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ break;
+ case BT_S:
+ if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) {
+ *badPtr = ptr;
+ return 0;
+ }
+ break;
+ case BT_NAME:
+ case BT_NMSTRT:
+ if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f))
+ break;
+ default:
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case 0x24: /* $ */
+ case 0x40: /* @ */
+ break;
+ default:
+ *badPtr = ptr;
+ return 0;
+ }
+ break;
+ }
+ }
+ return 1;
+}
+
+/* This must only be called for a well-formed start-tag or empty
+ element tag. Returns the number of attributes. Pointers to the
+ first attsMax attributes are stored in atts.
+*/
+
+static int PTRCALL
+PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
+ int attsMax, ATTRIBUTE *atts)
+{
+ enum { other, inName, inValue } state = inName;
+ int nAtts = 0;
+ int open = 0; /* defined when state == inValue;
+ initialization just to shut up compilers */
+
+ for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define START_NAME \
+ if (state == other) { \
+ if (nAtts < attsMax) { \
+ atts[nAtts].name = ptr; \
+ atts[nAtts].normalized = 1; \
+ } \
+ state = inName; \
+ }
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NONASCII:
+ case BT_NMSTRT:
+ case BT_HEX:
+ START_NAME
+ break;
+#undef START_NAME
+ case BT_QUOT:
+ if (state != inValue) {
+ if (nAtts < attsMax)
+ atts[nAtts].valuePtr = ptr + MINBPC(enc);
+ state = inValue;
+ open = BT_QUOT;
+ }
+ else if (open == BT_QUOT) {
+ state = other;
+ if (nAtts < attsMax)
+ atts[nAtts].valueEnd = ptr;
+ nAtts++;
+ }
+ break;
+ case BT_APOS:
+ if (state != inValue) {
+ if (nAtts < attsMax)
+ atts[nAtts].valuePtr = ptr + MINBPC(enc);
+ state = inValue;
+ open = BT_APOS;
+ }
+ else if (open == BT_APOS) {
+ state = other;
+ if (nAtts < attsMax)
+ atts[nAtts].valueEnd = ptr;
+ nAtts++;
+ }
+ break;
+ case BT_AMP:
+ if (nAtts < attsMax)
+ atts[nAtts].normalized = 0;
+ break;
+ case BT_S:
+ if (state == inName)
+ state = other;
+ else if (state == inValue
+ && nAtts < attsMax
+ && atts[nAtts].normalized
+ && (ptr == atts[nAtts].valuePtr
+ || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE
+ || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE
+ || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open))
+ atts[nAtts].normalized = 0;
+ break;
+ case BT_CR: case BT_LF:
+ /* This case ensures that the first attribute name is counted
+ Apart from that we could just change state on the quote. */
+ if (state == inName)
+ state = other;
+ else if (state == inValue && nAtts < attsMax)
+ atts[nAtts].normalized = 0;
+ break;
+ case BT_GT:
+ case BT_SOL:
+ if (state != inValue)
+ return nAtts;
+ break;
+ default:
+ break;
+ }
+ }
+ /* not reached */
+}
+
+static int PTRFASTCALL
+PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr)
+{
+ int result = 0;
+ /* skip &# */
+ ptr += 2*MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_x)) {
+ for (ptr += MINBPC(enc);
+ !CHAR_MATCHES(enc, ptr, ASCII_SEMI);
+ ptr += MINBPC(enc)) {
+ int c = BYTE_TO_ASCII(enc, ptr);
+ switch (c) {
+ case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4:
+ case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9:
+ result <<= 4;
+ result |= (c - ASCII_0);
+ break;
+ case ASCII_A: case ASCII_B: case ASCII_C:
+ case ASCII_D: case ASCII_E: case ASCII_F:
+ result <<= 4;
+ result += 10 + (c - ASCII_A);
+ break;
+ case ASCII_a: case ASCII_b: case ASCII_c:
+ case ASCII_d: case ASCII_e: case ASCII_f:
+ result <<= 4;
+ result += 10 + (c - ASCII_a);
+ break;
+ }
+ if (result >= 0x110000)
+ return -1;
+ }
+ }
+ else {
+ for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) {
+ int c = BYTE_TO_ASCII(enc, ptr);
+ result *= 10;
+ result += (c - ASCII_0);
+ if (result >= 0x110000)
+ return -1;
+ }
+ }
+ return checkCharRefNumber(result);
+}
+
+static int PTRCALL
+PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr,
+ const char *end)
+{
+ switch ((end - ptr)/MINBPC(enc)) {
+ case 2:
+ if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) {
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_l:
+ return ASCII_LT;
+ case ASCII_g:
+ return ASCII_GT;
+ }
+ }
+ break;
+ case 3:
+ if (CHAR_MATCHES(enc, ptr, ASCII_a)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_m)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_p))
+ return ASCII_AMP;
+ }
+ }
+ break;
+ case 4:
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_q:
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_u)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_o)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_t))
+ return ASCII_QUOT;
+ }
+ }
+ break;
+ case ASCII_a:
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_p)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_o)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_s))
+ return ASCII_APOS;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static int PTRCALL
+PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2)
+{
+ for (;;) {
+ switch (BYTE_TYPE(enc, ptr1)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (*ptr1++ != *ptr2++) \
+ return 0;
+ LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2)
+#undef LEAD_CASE
+ /* fall through */
+ if (*ptr1++ != *ptr2++)
+ return 0;
+ break;
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ if (MINBPC(enc) > 1) {
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ if (MINBPC(enc) > 2) {
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ if (MINBPC(enc) > 3) {
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ }
+ }
+ }
+ break;
+ default:
+ if (MINBPC(enc) == 1 && *ptr1 == *ptr2)
+ return 1;
+ switch (BYTE_TYPE(enc, ptr2)) {
+ case BT_LEAD2:
+ case BT_LEAD3:
+ case BT_LEAD4:
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ return 0;
+ default:
+ return 1;
+ }
+ }
+ }
+ /* not reached */
+}
+
+static int PTRCALL
+PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1,
+ const char *end1, const char *ptr2)
+{
+ for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) {
+ if (ptr1 == end1)
+ return 0;
+ if (!CHAR_MATCHES(enc, ptr1, *ptr2))
+ return 0;
+ }
+ return ptr1 == end1;
+}
+
+static int PTRFASTCALL
+PREFIX(nameLength)(const ENCODING *enc, const char *ptr)
+{
+ const char *start = ptr;
+ for (;;) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: ptr += n; break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ return (int)(ptr - start);
+ }
+ }
+}
+
+static const char * PTRFASTCALL
+PREFIX(skipS)(const ENCODING *enc, const char *ptr)
+{
+ for (;;) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_LF:
+ case BT_CR:
+ case BT_S:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ return ptr;
+ }
+ }
+}
+
+static void PTRCALL
+PREFIX(updatePosition)(const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ POSITION *pos)
+{
+ while (ptr != end) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ ptr += n; \
+ break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_LF:
+ pos->columnNumber = (XML_Size)-1;
+ pos->lineNumber++;
+ ptr += MINBPC(enc);
+ break;
+ case BT_CR:
+ pos->lineNumber++;
+ ptr += MINBPC(enc);
+ if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ pos->columnNumber = (XML_Size)-1;
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ pos->columnNumber++;
+ }
+}
+
+#undef DO_LEAD_CASE
+#undef MULTIBYTE_CASES
+#undef INVALID_CASES
+#undef CHECK_NAME_CASE
+#undef CHECK_NAME_CASES
+#undef CHECK_NMSTRT_CASE
+#undef CHECK_NMSTRT_CASES
+
diff --git a/src/lib/expat/xmltok_impl.h b/src/lib/expat/xmltok_impl.h
new file mode 100644
index 00000000000..da0ea60a657
--- /dev/null
+++ b/src/lib/expat/xmltok_impl.h
@@ -0,0 +1,46 @@
+/*
+Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+See the file COPYING for copying permission.
+*/
+
+enum {
+ BT_NONXML,
+ BT_MALFORM,
+ BT_LT,
+ BT_AMP,
+ BT_RSQB,
+ BT_LEAD2,
+ BT_LEAD3,
+ BT_LEAD4,
+ BT_TRAIL,
+ BT_CR,
+ BT_LF,
+ BT_GT,
+ BT_QUOT,
+ BT_APOS,
+ BT_EQUALS,
+ BT_QUEST,
+ BT_EXCL,
+ BT_SOL,
+ BT_SEMI,
+ BT_NUM,
+ BT_LSQB,
+ BT_S,
+ BT_NMSTRT,
+ BT_COLON,
+ BT_HEX,
+ BT_DIGIT,
+ BT_NAME,
+ BT_MINUS,
+ BT_OTHER, /* known not to be a name or name start character */
+ BT_NONASCII, /* might be a name or name start character */
+ BT_PERCNT,
+ BT_LPAR,
+ BT_RPAR,
+ BT_AST,
+ BT_PLUS,
+ BT_COMMA,
+ BT_VERBAR
+};
+
+#include <stddef.h>
diff --git a/src/lib/expat/xmltok_ns.c b/src/lib/expat/xmltok_ns.c
new file mode 100644
index 00000000000..d2f893836fb
--- /dev/null
+++ b/src/lib/expat/xmltok_ns.c
@@ -0,0 +1,106 @@
+const ENCODING *
+NS(XmlGetUtf8InternalEncoding)(void)
+{
+ return &ns(internal_utf8_encoding).enc;
+}
+
+const ENCODING *
+NS(XmlGetUtf16InternalEncoding)(void)
+{
+#if BYTEORDER == 1234
+ return &ns(internal_little2_encoding).enc;
+#elif BYTEORDER == 4321
+ return &ns(internal_big2_encoding).enc;
+#else
+ const short n = 1;
+ return (*(const char *)&n
+ ? &ns(internal_little2_encoding).enc
+ : &ns(internal_big2_encoding).enc);
+#endif
+}
+
+static const ENCODING * const NS(encodings)[] = {
+ &ns(latin1_encoding).enc,
+ &ns(ascii_encoding).enc,
+ &ns(utf8_encoding).enc,
+ &ns(big2_encoding).enc,
+ &ns(big2_encoding).enc,
+ &ns(little2_encoding).enc,
+ &ns(utf8_encoding).enc /* NO_ENC */
+};
+
+static int PTRCALL
+NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ return initScan(NS(encodings), (const INIT_ENCODING *)enc,
+ XML_PROLOG_STATE, ptr, end, nextTokPtr);
+}
+
+static int PTRCALL
+NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ return initScan(NS(encodings), (const INIT_ENCODING *)enc,
+ XML_CONTENT_STATE, ptr, end, nextTokPtr);
+}
+
+int
+NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr,
+ const char *name)
+{
+ int i = getEncodingIndex(name);
+ if (i == UNKNOWN_ENC)
+ return 0;
+ SET_INIT_ENC_INDEX(p, i);
+ p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog);
+ p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent);
+ p->initEnc.updatePosition = initUpdatePosition;
+ p->encPtr = encPtr;
+ *encPtr = &(p->initEnc);
+ return 1;
+}
+
+static const ENCODING *
+NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end)
+{
+#define ENCODING_MAX 128
+ char buf[ENCODING_MAX];
+ char *p = buf;
+ int i;
+ XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
+ if (ptr != end)
+ return 0;
+ *p = 0;
+ if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2)
+ return enc;
+ i = getEncodingIndex(buf);
+ if (i == UNKNOWN_ENC)
+ return 0;
+ return NS(encodings)[i];
+}
+
+int
+NS(XmlParseXmlDecl)(int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **versionEndPtr,
+ const char **encodingName,
+ const ENCODING **encoding,
+ int *standalone)
+{
+ return doParseXmlDecl(NS(findEncoding),
+ isGeneralTextEntity,
+ enc,
+ ptr,
+ end,
+ badPtr,
+ versionPtr,
+ versionEndPtr,
+ encodingName,
+ encoding,
+ standalone);
+}
diff --git a/src/lib/lib.mak b/src/lib/lib.mak
new file mode 100644
index 00000000000..224caa63cf3
--- /dev/null
+++ b/src/lib/lib.mak
@@ -0,0 +1,84 @@
+###########################################################################
+#
+# lib.mak
+#
+# MAME dependent library makefile
+#
+# Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+# Visit http://mamedev.org for licensing and usage restrictions.
+#
+###########################################################################
+
+
+LIBOBJ = $(OBJ)/lib
+
+OBJDIRS += \
+ $(LIBOBJ)/util \
+ $(LIBOBJ)/expat \
+ $(LIBOBJ)/zlib \
+
+
+
+#-------------------------------------------------
+# utility library objects
+#-------------------------------------------------
+
+UTILOBJS = \
+ $(LIBOBJ)/util/astring.o \
+ $(LIBOBJ)/util/avcomp.o \
+ $(LIBOBJ)/util/aviio.o \
+ $(LIBOBJ)/util/bitmap.o \
+ $(LIBOBJ)/util/cdrom.o \
+ $(LIBOBJ)/util/chd.o \
+ $(LIBOBJ)/util/corefile.o \
+ $(LIBOBJ)/util/corestr.o \
+ $(LIBOBJ)/util/coreutil.o \
+ $(LIBOBJ)/util/harddisk.o \
+ $(LIBOBJ)/util/huffman.o \
+ $(LIBOBJ)/util/jedparse.o \
+ $(LIBOBJ)/util/md5.o \
+ $(LIBOBJ)/util/options.o \
+ $(LIBOBJ)/util/palette.o \
+ $(LIBOBJ)/util/png.o \
+ $(LIBOBJ)/util/pool.o \
+ $(LIBOBJ)/util/sha1.o \
+ $(LIBOBJ)/util/unicode.o \
+ $(LIBOBJ)/util/unzip.o \
+ $(LIBOBJ)/util/xmlfile.o \
+
+$(OBJ)/libutil.a: $(UTILOBJS)
+
+
+
+#-------------------------------------------------
+# expat library objects
+#-------------------------------------------------
+
+EXPATOBJS = \
+ $(LIBOBJ)/expat/xmlparse.o \
+ $(LIBOBJ)/expat/xmlrole.o \
+ $(LIBOBJ)/expat/xmltok.o
+
+$(OBJ)/libexpat.a: $(EXPATOBJS)
+
+
+
+#-------------------------------------------------
+# zlib library objects
+#-------------------------------------------------
+
+ZLIBOBJS = \
+ $(LIBOBJ)/zlib/adler32.o \
+ $(LIBOBJ)/zlib/compress.o \
+ $(LIBOBJ)/zlib/crc32.o \
+ $(LIBOBJ)/zlib/deflate.o \
+ $(LIBOBJ)/zlib/gzio.o \
+ $(LIBOBJ)/zlib/inffast.o \
+ $(LIBOBJ)/zlib/inflate.o \
+ $(LIBOBJ)/zlib/infback.o \
+ $(LIBOBJ)/zlib/inftrees.o \
+ $(LIBOBJ)/zlib/trees.o \
+ $(LIBOBJ)/zlib/uncompr.o \
+ $(LIBOBJ)/zlib/zutil.o
+
+$(OBJ)/libz.a: $(ZLIBOBJS)
diff --git a/src/lib/util/astring.c b/src/lib/util/astring.c
new file mode 100644
index 00000000000..b2ae0c6c61d
--- /dev/null
+++ b/src/lib/util/astring.c
@@ -0,0 +1,596 @@
+/***************************************************************************
+
+ astring.c
+
+ Allocated string manipulation functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************/
+
+#include "astring.h"
+#include "osdcore.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct _astring
+{
+ char * text;
+ int alloclen;
+ char smallbuf[256 - sizeof(int) - sizeof(char *)];
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static char dummy_text[2] = { 0 };
+static astring dummy_astring = { dummy_text, 1, { 0 } };
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ ensure_room - ensure we have room for a
+ given string, or else reallocate our buffer
+-------------------------------------------------*/
+
+INLINE int ensure_room(astring *str, int length)
+{
+ char *newbuf, *oldbuf;
+ int alloclen;
+
+ /* always fail to expand the dummy */
+ if (str == &dummy_astring)
+ return FALSE;
+
+ /* if we have the room, do nothing */
+ if (str->alloclen >= length + 1)
+ return TRUE;
+
+ /* allocate a new buffer with some slop */
+ alloclen = length + 256;
+ newbuf = malloc(alloclen);
+ if (newbuf == NULL)
+ return FALSE;
+
+ /* swap in the new buffer and free the old one */
+ oldbuf = (str->text == str->smallbuf) ? NULL : str->text;
+ str->text = strcpy(newbuf, str->text);
+ str->alloclen = alloclen;
+ if (oldbuf != NULL)
+ free(oldbuf);
+
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ safe_string_base - return a "safe" string
+ base for a given start index
+-------------------------------------------------*/
+
+INLINE char *safe_string_base(char *base, int start)
+{
+ int max = strlen(base);
+ return (start >= 0 && start < max) ? base + start : base + max;
+}
+
+
+/*-------------------------------------------------
+ normalize_substr - normalize substr parameters
+-------------------------------------------------*/
+
+INLINE void normalize_substr(int *start, int *count, int length)
+{
+ /* limit start */
+ if (*start < 0)
+ *start = 0;
+ else if (*start > length)
+ *start = length;
+
+ /* update count */
+ if (*count == -1 || *start + *count > length)
+ *count = length - *start;
+}
+
+
+
+/***************************************************************************
+ ASTRING ALLOCATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ astring_alloc - allocate a new astring
+-------------------------------------------------*/
+
+astring *astring_alloc(void)
+{
+ astring *str;
+
+ /* allocate memory; if we fail, return the dummy */
+ str = malloc(sizeof(*str));
+ if (str == NULL)
+ return &dummy_astring;
+ memset(str, 0, sizeof(*str));
+
+ /* initialize the small buffer */
+ str->text = str->smallbuf;
+ str->alloclen = ARRAY_LENGTH(str->smallbuf);
+ return str;
+}
+
+
+/*-------------------------------------------------
+ astring_free - free an astring
+-------------------------------------------------*/
+
+void astring_free(astring *str)
+{
+ /* ignore attempts to free the dummy */
+ if (str == &dummy_astring)
+ return;
+
+ /* if we allocated additional memory, free that */
+ if (str->text != str->smallbuf)
+ free(str->text);
+ free(str);
+}
+
+
+
+/***************************************************************************
+ INLINE ASTRING CHANGES
+***************************************************************************/
+
+/*-------------------------------------------------
+ astring_cpy - copy one astring into another
+-------------------------------------------------*/
+
+astring *astring_cpy(astring *dst, const astring *src)
+{
+ return astring_cpyc(dst, src->text);
+}
+
+
+/*-------------------------------------------------
+ astring_cpyc - copy a C string into an astring
+-------------------------------------------------*/
+
+astring *astring_cpyc(astring *dst, const char *src)
+{
+ return astring_cpych(dst, src, strlen(src));
+}
+
+
+/*-------------------------------------------------
+ astring_cpych - copy a character array into
+ an astring
+-------------------------------------------------*/
+
+astring *astring_cpych(astring *dst, const char *src, int count)
+{
+ /* make room; if we fail or if dst is the dummy, do nothing */
+ if (!ensure_room(dst, count))
+ return dst;
+
+ /* copy the raw data and NULL-terminate */
+ if (count > 0)
+ memcpy(dst->text, src, count);
+ dst->text[count] = 0;
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ astring_cpysubstr - copy a substring of one
+ string to another
+-------------------------------------------------*/
+
+astring *astring_cpysubstr(astring *dst, const astring *src, int start, int count)
+{
+ normalize_substr(&start, &count, strlen(src->text));
+ return astring_cpych(dst, src->text + start, count);
+}
+
+
+/*-------------------------------------------------
+ astring_ins - insert one astring into another
+-------------------------------------------------*/
+
+astring *astring_ins(astring *dst, int insbefore, const astring *src)
+{
+ return astring_insc(dst, insbefore, src->text);
+}
+
+
+/*-------------------------------------------------
+ astring_insc - insert a C string into an
+ astring
+-------------------------------------------------*/
+
+astring *astring_insc(astring *dst, int insbefore, const char *src)
+{
+ return astring_insch(dst, insbefore, src, strlen(src));
+}
+
+
+/*-------------------------------------------------
+ astring_insch - insert a character array
+ into an astring
+-------------------------------------------------*/
+
+astring *astring_insch(astring *dst, int insbefore, const char *src, int count)
+{
+ int dstlength = strlen(dst->text);
+
+ /* make room; if we fail or if dst is the dummy, do nothing */
+ if (!ensure_room(dst, dstlength + count))
+ return dst;
+
+ /* adjust insbefore to be logical */
+ if (insbefore < 0 || insbefore > dstlength)
+ insbefore = dstlength;
+
+ /* copy the data an NULL-terminate */
+ if (insbefore < dstlength)
+ memmove(dst->text + insbefore + count, dst->text + insbefore, dstlength - insbefore);
+ memcpy(dst->text + insbefore, src, count);
+ dst->text[dstlength + count] = 0;
+ return dst;
+}
+
+
+/*-------------------------------------------------
+ astring_inssubstr - insert a substring of
+ one string to another
+-------------------------------------------------*/
+
+astring *astring_inssubstr(astring *dst, int insbefore, const astring *src, int start, int count)
+{
+ normalize_substr(&start, &count, strlen(src->text));
+ return astring_insch(dst, insbefore, src->text + start, count);
+}
+
+
+/*-------------------------------------------------
+ astring_substr - extract a substring of
+ ourself, removing everything else
+-------------------------------------------------*/
+
+astring *astring_substr(astring *str, int start, int count)
+{
+ /* ignore attempts to do this on the dummy */
+ if (str == &dummy_astring)
+ return str;
+
+ /* normalize parameters */
+ normalize_substr(&start, &count, strlen(str->text));
+
+ /* move the data and NULL-terminate */
+ if (count > 0 && start > 0)
+ memmove(str->text, str->text + start, count);
+ str->text[count] = 0;
+ return str;
+}
+
+
+/*-------------------------------------------------
+ astring_printf - printf text into an astring
+-------------------------------------------------*/
+
+int astring_printf(astring *dst, const char *format, ...)
+{
+ char tempbuf[4096];
+ va_list args;
+ int result;
+
+ /* sprintf into the temporary buffer */
+ va_start(args, format);
+ result = vsprintf(tempbuf, format, args);
+ va_end(args);
+
+ /* set the result */
+ astring_cpyc(dst, tempbuf);
+ return result;
+}
+
+
+
+/***************************************************************************
+ ASTRING QUERIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ astring_c - return a pointer to a C string
+ from an astring
+-------------------------------------------------*/
+
+const char *astring_c(const astring *str)
+{
+ return str->text;
+}
+
+
+/*-------------------------------------------------
+ astring_len - return the length of an astring
+-------------------------------------------------*/
+
+int astring_len(const astring *str)
+{
+ return strlen(str->text);
+}
+
+
+/*-------------------------------------------------
+ astring_cmp - compare one astring to another
+-------------------------------------------------*/
+
+int astring_cmp(const astring *str1, const astring *str2)
+{
+ return astring_cmpc(str1, str2->text);
+}
+
+
+/*-------------------------------------------------
+ astring_cmpc - compare a C string to an astring
+-------------------------------------------------*/
+
+int astring_cmpc(const astring *str1, const char *str2)
+{
+ const char *s1 = str1->text;
+
+ /* loop while equal until we hit the end of strings */
+ while (*s1 != 0 && *str2 != 0 && *s1 == *str2)
+ s1++, str2++;
+ return *s1 - *str2;
+}
+
+
+/*-------------------------------------------------
+ astring_cmpch - compare a character array to
+ an astring
+-------------------------------------------------*/
+
+int astring_cmpch(const astring *str1, const char *str2, int count)
+{
+ const char *s1 = str1->text;
+ int result;
+
+ /* loop while equal until we hit the end of strings */
+ while (count-- > 0 && *s1 != 0 && *str2 != 0 && *s1 == *str2)
+ s1++, str2++;
+ result = (count == -1) ? 0 : *s1 - *str2;
+ if (result == 0 && *s1 != 0)
+ result = 1;
+ return result;
+}
+
+
+/*-------------------------------------------------
+ astring_cmpsubstr - compare a substring to
+ an astring
+-------------------------------------------------*/
+
+int astring_cmpsubstr(const astring *str1, const astring *str2, int start, int count)
+{
+ normalize_substr(&start, &count, strlen(str2->text));
+ return astring_cmpch(str1, str2->text + start, count);
+}
+
+
+/*-------------------------------------------------
+ astring_icmp - case-insenstive compare one
+ astring to another
+-------------------------------------------------*/
+
+int astring_icmp(const astring *str1, const astring *str2)
+{
+ return astring_icmpc(str1, str2->text);
+}
+
+
+/*-------------------------------------------------
+ astring_icmpc - case-insenstive compare a C
+ string to an astring
+-------------------------------------------------*/
+
+int astring_icmpc(const astring *str1, const char *str2)
+{
+ const char *s1 = str1->text;
+
+ /* loop while equal until we hit the end of strings */
+ while (*s1 != 0 && *str2 != 0 && tolower(*s1) == tolower(*str2))
+ s1++, str2++;
+ return tolower(*s1) - tolower(*str2);
+}
+
+
+/*-------------------------------------------------
+ astring_icmpch - case-insenstive compare a
+ character array to an astring
+-------------------------------------------------*/
+
+int astring_icmpch(const astring *str1, const char *str2, int count)
+{
+ const char *s1 = str1->text;
+ int result;
+
+ /* loop while equal until we hit the end of strings */
+ while (count-- > 0 && *s1 != 0 && *str2 != 0 && tolower(*s1) == tolower(*str2))
+ s1++, str2++;
+ result = (count == -1) ? 0 : tolower(*s1) - tolower(*str2);
+ if (result == 0 && *s1 != 0)
+ result = 1;
+ return result;
+}
+
+
+/*-------------------------------------------------
+ astring_icmpsubstr - case-insenstive compare a
+ substring to an astring
+-------------------------------------------------*/
+
+int astring_icmpsubstr(const astring *str1, const astring *str2, int start, int count)
+{
+ normalize_substr(&start, &count, strlen(str2->text));
+ return astring_icmpch(str1, str2->text + start, count);
+}
+
+
+/*-------------------------------------------------
+ astring_chr - return the index of a character
+ in an astring
+-------------------------------------------------*/
+
+int astring_chr(const astring *str, int start, int ch)
+{
+ char *result = strchr(safe_string_base(str->text, start), ch);
+ return (result != NULL) ? (result - str->text) : -1;
+}
+
+
+/*-------------------------------------------------
+ astring_rchr - return the index of a character
+ in an astring, searching from the end
+-------------------------------------------------*/
+
+int astring_rchr(const astring *str, int start, int ch)
+{
+ char *result = strrchr(safe_string_base(str->text, start), ch);
+ return (result != NULL) ? (result - str->text) : -1;
+}
+
+
+/*-------------------------------------------------
+ astring_find - find one astring in another
+-------------------------------------------------*/
+
+int astring_find(const astring *str, int start, const astring *search)
+{
+ return astring_findc(str, start, search->text);
+}
+
+
+/*-------------------------------------------------
+ astring_findc - find a C string in an astring
+-------------------------------------------------*/
+
+int astring_findc(const astring *str, int start, const char *search)
+{
+ char *result = strstr(safe_string_base(str->text, start), search);
+ return (result != NULL) ? (result - str->text) : -1;
+}
+
+
+
+/***************************************************************************
+ ASTRING UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ astring_delchr - delete all instances of
+ 'ch'
+-------------------------------------------------*/
+
+astring *astring_delchr(astring *str, int ch)
+{
+ char *src, *dst;
+
+ /* simple deletion */
+ for (src = dst = str->text; *src != 0; src++)
+ if (*src != ch)
+ *dst++ = *src;
+ *dst = 0;
+
+ return str;
+}
+
+
+/*-------------------------------------------------
+ astring_replacechr - replace all instances of
+ 'ch' with 'newch'
+-------------------------------------------------*/
+
+astring *astring_replacechr(astring *str, int ch, int newch)
+{
+ char *text;
+
+ /* simple replacement */
+ for (text = str->text; *text != 0; text++)
+ if (*text == ch)
+ *text = newch;
+
+ return str;
+}
+
+
+/*-------------------------------------------------
+ astring_toupper - convert string to all
+ upper-case
+-------------------------------------------------*/
+
+astring *astring_toupper(astring *str)
+{
+ char *text;
+
+ /* just toupper() on all characters */
+ for (text = str->text; *text != 0; text++)
+ *text = toupper(*text);
+
+ return str;
+}
+
+
+/*-------------------------------------------------
+ astring_tolower - convert string to all
+ lower-case
+-------------------------------------------------*/
+
+astring *astring_tolower(astring *str)
+{
+ char *text;
+
+ /* just toupper() on all characters */
+ for (text = str->text; *text != 0; text++)
+ *text = tolower(*text);
+
+ return str;
+}
+
+
+/*-------------------------------------------------
+ astring_trimspace - remove all space
+ characters from beginning/end
+-------------------------------------------------*/
+
+astring *astring_trimspace(astring *str)
+{
+ char *ptr;
+
+ /* first remove stuff from the end */
+ for (ptr = str->text + strlen(str->text) - 1; ptr >= str->text && isspace(*ptr); ptr--)
+ *ptr = 0;
+
+ /* then count how much to remove from the beginning */
+ for (ptr = str->text; *ptr != 0 && isspace(*ptr); ptr++) ;
+ if (ptr > str->text)
+ astring_substr(str, ptr - str->text, -1);
+
+ return str;
+}
diff --git a/src/lib/util/astring.h b/src/lib/util/astring.h
new file mode 100644
index 00000000000..3d80216383c
--- /dev/null
+++ b/src/lib/util/astring.h
@@ -0,0 +1,228 @@
+/***************************************************************************
+
+ astring.h
+
+ Allocated string manipulation functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __ASTRING_H__
+#define __ASTRING_H__
+
+#include "pool.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _astring astring;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- astring allocation ----- */
+
+/* allocate a new astring */
+astring *astring_alloc(void);
+
+/* free an astring */
+void astring_free(astring *str);
+
+
+
+/* ----- inline astring changes ----- */
+
+/* copy one astring into another */
+astring *astring_cpy(astring *dst, const astring *src);
+
+/* copy a C string into an astring */
+astring *astring_cpyc(astring *dst, const char *src);
+
+/* copy a character array into an astring */
+astring *astring_cpych(astring *dst, const char *src, int count);
+
+/* copy a substring of one string into another */
+astring *astring_cpysubstr(astring *dst, const astring *src, int start, int count);
+
+/* insert one astring into another */
+astring *astring_ins(astring *dst, int insbefore, const astring *src);
+
+/* insert a C string into an astring */
+astring *astring_insc(astring *dst, int insbefore, const char *src);
+
+/* insert a character array into an astring */
+astring *astring_insch(astring *dst, int insbefore, const char *src, int count);
+
+/* insert a substring of one string into another */
+astring *astring_inssubstr(astring *dst, int insbefore, const astring *src, int start, int count);
+
+/* extract a substring of ourself, removing everything else */
+astring *astring_substr(astring *str, int start, int count);
+
+/* formatted printf to an astring */
+int astring_printf(astring *dst, const char *format, ...);
+
+
+
+/* ----- astring queries ----- */
+
+/* return a pointer to a C string from an astring */
+const char *astring_c(const astring *str);
+
+/* return the length of an astring */
+int astring_len(const astring *str);
+
+/* compare two astrings */
+int astring_cmp(const astring *str1, const astring *str2);
+
+/* compare an astring to a C string */
+int astring_cmpc(const astring *str1, const char *str2);
+
+/* compare an astring to a character buffer */
+int astring_cmpch(const astring *str1, const char *str2, int count);
+
+/* compare an astring to a character buffer */
+int astring_cmpsubstr(const astring *str1, const astring *str2, int start, int count);
+
+/* case-insenstive compare two astrings */
+int astring_icmp(const astring *str1, const astring *str2);
+
+/* case-insenstive compare an astring to a C string */
+int astring_icmpc(const astring *str1, const char *str2);
+
+/* case-insenstive compare an astring to a character buffer */
+int astring_icmpch(const astring *str1, const char *str2, int count);
+
+/* case-insenstive compare an astring to a character buffer */
+int astring_icmpsubstr(const astring *str1, const astring *str2, int start, int count);
+
+/* search an astring for a character, returning offset or -1 if not found */
+int astring_chr(const astring *str, int start, int ch);
+
+/* reverse search an astring for a character, returning offset or -1 if not found */
+int astring_rchr(const astring *str, int start, int ch);
+
+/* search in an astring for another astring, returning offset or -1 if not found */
+int astring_find(const astring *str, int start, const astring *search);
+
+/* search in an astring for a C string, returning offset or -1 if not found */
+int astring_findc(const astring *str, int start, const char *search);
+
+
+
+/* ----- astring utilties ----- */
+
+/* delete all instances of 'ch' */
+astring *astring_delchr(astring *str, int ch);
+
+/* replace all instances of 'ch' with 'newch' */
+astring *astring_replacechr(astring *str, int ch, int newch);
+
+/* convert string to all upper-case */
+astring *astring_toupper(astring *str);
+
+/* convert string to all lower-case */
+astring *astring_tolower(astring *str);
+
+/* remove all space characters from beginning/end */
+astring *astring_trimspace(astring *str);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/* allocate a new duplicate of an astring */
+INLINE astring *astring_dup(const astring *str)
+{
+ return astring_cpy(astring_alloc(), str);
+}
+
+/* allocate a new duplicate of an astring */
+INLINE astring *astring_dupc(const char *str)
+{
+ return astring_cpyc(astring_alloc(), str);
+}
+
+/* allocate a new duplicate of an astring */
+INLINE astring *astring_dupch(const char *str, int count)
+{
+ return astring_cpych(astring_alloc(), str, count);
+}
+
+/* allocate a duplicate of a substring */
+INLINE astring *astring_dupsubstr(const astring *str, int start, int count)
+{
+ return astring_cpysubstr(astring_alloc(), str, start, count);
+}
+
+
+/* reset an astring to an empty string */
+INLINE astring *astring_reset(astring *dst)
+{
+ return astring_cpyc(dst, "");
+}
+
+
+/* concatenate one astring to the end of another */
+INLINE astring *astring_cat(astring *dst, const astring *src)
+{
+ return astring_ins(dst, -1, src);
+}
+
+/* concatenate a C string to the end of an astring */
+INLINE astring *astring_catc(astring *dst, const char *src)
+{
+ return astring_insc(dst, -1, src);
+}
+
+/* concatenate a character array to the end of an astring */
+INLINE astring *astring_catch(astring *dst, const char *src, int count)
+{
+ return astring_insch(dst, -1, src, count);
+}
+
+/* concatenate a substring of one string into another */
+INLINE astring *astring_catsubstr(astring *dst, const astring *src, int start, int count)
+{
+ return astring_inssubstr(dst, -1, src, start, count);
+}
+
+
+/* assemble an astring from 2 C strings */
+INLINE astring *astring_assemble_2(astring *dst, const char *src1, const char *src2)
+{
+ return astring_catc(astring_cpyc(dst, src1), src2);
+}
+
+/* assemble an astring from 3 C strings */
+INLINE astring *astring_assemble_3(astring *dst, const char *src1, const char *src2, const char *src3)
+{
+ return astring_catc(astring_assemble_2(dst, src1, src2), src3);
+}
+
+/* assemble an astring from 4 C strings */
+INLINE astring *astring_assemble_4(astring *dst, const char *src1, const char *src2, const char *src3, const char *src4)
+{
+ return astring_catc(astring_assemble_3(dst, src1, src2, src3), src4);
+}
+
+/* assemble an astring from 5 C strings */
+INLINE astring *astring_assemble_5(astring *dst, const char *src1, const char *src2, const char *src3, const char *src4, const char *src5)
+{
+ return astring_catc(astring_assemble_4(dst, src1, src2, src3, src4), src5);
+}
+
+
+#endif /* __ASTRING_H__ */
diff --git a/src/lib/util/avcomp.c b/src/lib/util/avcomp.c
new file mode 100644
index 00000000000..d3144e01175
--- /dev/null
+++ b/src/lib/util/avcomp.c
@@ -0,0 +1,840 @@
+/*
+To do:
+* verify Cb,Y,Cr,Y ordering
+* swap the ordering(?)
+* add backchannel support for samples as well?
+*/
+/***************************************************************************
+
+ avcomp.c
+
+ Audio/video compression and decompression helpers.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Each frame is compressed as a unit. The raw data is of the form:
+ (all multibyte values are stored in big-endian format)
+
+ 'chav' (4 bytes) - fixed header data to identify the format
+ metasize (1 byte) - size of metadata in bytes (max=255 bytes)
+ channels (1 byte) - number of audio channels
+ samples (2 bytes) - number of samples per audio stream
+ width (2 bytes) - width of video data
+ height (2 bytes) - height of video data (high bit set means interlaced)
+ <metadata> - as raw bytes
+ <audio stream 0> - as signed 16-bit samples
+ <audio stream 1> - as signed 16-bit samples
+ ...
+ <video data> - as a raw array of 8-bit YUY data in (Cb,Y,Cr,Y) order
+
+ When compressed, the data is stored as follows:
+ (all multibyte values are stored in big-endian format)
+
+ metasize (1 byte) - size of metadata in bytes
+ channels (1 byte) - number of audio channels
+ samples (2 bytes) - number of samples per audio stream
+ width (2 bytes) - width of video data
+ height (2 bytes) - height of video data (high bit set means interlaced)
+ audhuffsize (1 byte) - size of the audio Huffman table
+ str0size (2 bytes) - compressed size of stream 0
+ str1size (2 bytes) - compressed size of stream 1
+ ...
+ <metadata> - as raw data
+ <audio huffman table> - Huffman table for audio decoding
+ <audio stream 0 data> - Huffman-compressed deltas
+ <audio stream 1 data> - Huffman-compressed deltas
+ <...>
+ <video huffman table> - Huffman table for video decoding
+ <video data> - compressed data
+
+****************************************************************************
+
+ Attempted techniques that have not been worthwhile:
+
+ * Attempted to use integer DCTs from the IJG code; even the "slow"
+ variants produce a lot of error and thus kill our compression ratio,
+ since our compression is based on error not bitrate.
+
+ * Tried various other predictors for the lossless video encoding, but
+ none tended to give any significant gain over predicting the
+ previous pixel.
+
+***************************************************************************/
+
+#include "avcomp.h"
+#include "huffman.h"
+#include "chd.h"
+
+#include <math.h>
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct _avcomp_state
+{
+ /* decompression parameters */
+ UINT32 decodemask;
+ UINT8 * videobuffer;
+ UINT32 videostride;
+ UINT32 videoxor;
+ UINT32 audioxor;
+
+ /* video parameters */
+ UINT32 maxwidth, maxheight;
+
+ /* audio parameters */
+ UINT32 maxchannels;
+
+ /* intermediate data */
+ UINT8 * deltadata;
+ UINT8 * audiodata;
+
+ /* huffman contexts */
+ huffman_context * ycontext;
+ huffman_context * ccontext;
+ huffman_context * audiocontext;
+};
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+/* encoding helpers */
+static avcomp_error encode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 *dest, UINT8 *sizes);
+static avcomp_error encode_video(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT8 *dest, UINT32 *complength);
+static avcomp_error encode_video_lossless(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT8 *dest, UINT32 *complength);
+
+/* decoding helpers */
+static avcomp_error decode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 *dest, const UINT8 *sizes, UINT32 destxor);
+static avcomp_error decode_video(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT32 complength, UINT8 *dest);
+static avcomp_error decode_video_lossless(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 deststride, UINT32 destxor);
+
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ avcomp_init - allocate and initialize a
+ new state block for compression or
+ decompression
+-------------------------------------------------*/
+
+avcomp_state *avcomp_init(UINT32 maxwidth, UINT32 maxheight, UINT32 maxchannels)
+{
+ huffman_error hufferr;
+ avcomp_state *state;
+
+ /* allocate memory for state block */
+ state = malloc(sizeof(*state));
+ if (state == NULL)
+ return NULL;
+
+ /* clear the buffers */
+ memset(state, 0, sizeof(*state));
+
+ /* fill in sensible decompression defaults */
+ state->decodemask = AVCOMP_DECODE_DEFAULT;
+
+ /* compute the core info */
+ state->maxwidth = maxwidth;
+ state->maxheight = maxheight;
+ state->maxchannels = maxchannels;
+
+ /* now allocate data buffers */
+ state->deltadata = malloc(state->maxwidth * state->maxheight * 2);
+ state->audiodata = malloc(65536 * state->maxchannels * 2);
+ if (state->deltadata == NULL || state->audiodata == NULL)
+ goto cleanup;
+
+ /* create huffman contexts */
+ hufferr = huffman_create_context(&state->ycontext, 12);
+ if (hufferr != HUFFERR_NONE)
+ goto cleanup;
+ hufferr = huffman_create_context(&state->ccontext, 12);
+ if (hufferr != HUFFERR_NONE)
+ goto cleanup;
+ hufferr = huffman_create_context(&state->audiocontext, 12);
+ if (hufferr != HUFFERR_NONE)
+ goto cleanup;
+
+ return state;
+
+cleanup:
+ avcomp_free(state);
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ avcomp_free - free a state block
+-------------------------------------------------*/
+
+void avcomp_free(avcomp_state *state)
+{
+ /* free the data buffers */
+ if (state->deltadata != NULL)
+ free(state->deltadata);
+ if (state->audiodata != NULL)
+ free(state->audiodata);
+
+ /* free the contexts */
+ if (state->ycontext != NULL)
+ huffman_free_context(state->ycontext);
+ if (state->ccontext != NULL)
+ huffman_free_context(state->ccontext);
+ if (state->audiocontext != NULL)
+ huffman_free_context(state->audiocontext);
+
+ free(state);
+}
+
+
+/*-------------------------------------------------
+ avcomp_decompress_config - configure compression
+ parameters
+-------------------------------------------------*/
+
+void avcomp_decompress_config(avcomp_state *state, UINT32 decodemask, UINT8 *videobuffer, UINT32 videostride, UINT32 videoxor, UINT32 audioxor)
+{
+ state->decodemask = decodemask;
+ state->videobuffer = videobuffer;
+ state->videostride = videostride;
+ state->videoxor = videoxor;
+ state->audioxor = audioxor;
+}
+
+
+
+/***************************************************************************
+ ENCODING/DECODING FRONTENDS
+***************************************************************************/
+
+/*-------------------------------------------------
+ avcomp_encode_data - encode a block of data
+ into a compressed data stream
+-------------------------------------------------*/
+
+avcomp_error avcomp_encode_data(avcomp_state *state, const UINT8 *source, UINT8 *dest, UINT32 *complength)
+{
+ UINT32 metasize, channels, samples, width, height;
+ UINT32 srcoffs, dstoffs;
+ avcomp_error err;
+ int interlaced;
+
+ /* validate the header */
+ if (source[0] != 'c' || source[1] != 'h' || source[2] != 'a' || source[3] != 'v')
+ return AVCERR_INVALID_DATA;
+
+ /* extract info from the header */
+ metasize = source[4];
+ channels = source[5];
+ samples = (source[6] << 8) + source[7];
+ width = (source[8] << 8) + source[9];
+ height = (source[10] << 8) + source[11];
+ interlaced = (height >> 15) & 1;
+ height &= 0x7fff;
+
+ /* validate the info from the header */
+ if (width > state->maxwidth || height > state->maxheight)
+ return AVCERR_VIDEO_TOO_LARGE;
+ if (channels > state->maxchannels)
+ return AVCERR_AUDIO_TOO_LARGE;
+
+ /* write the basics to the new header */
+ dest[0] = metasize;
+ dest[1] = channels;
+ dest[2] = samples >> 8;
+ dest[3] = samples;
+ dest[4] = width >> 8;
+ dest[5] = width;
+ dest[6] = (interlaced << 7) | (height >> 8);
+ dest[7] = height;
+
+ /* starting offsets */
+ srcoffs = 12;
+ dstoffs = 9 + 2 * channels;
+
+ /* copy the metadata first */
+ if (metasize > 0)
+ {
+ memcpy(dest + dstoffs, source + srcoffs, metasize);
+ srcoffs += metasize;
+ dstoffs += metasize;
+ }
+
+ /* encode the audio channels */
+ if (channels > 0)
+ {
+ int chnum;
+
+ /* encode the audio */
+ err = encode_audio(state, channels, samples, source + srcoffs, dest + dstoffs, &dest[8]);
+ if (err != AVCERR_NONE)
+ return err;
+
+ /* advance the pointers past the data */
+ srcoffs += channels * samples * 2;
+ dstoffs += dest[8];
+ for (chnum = 0; chnum < channels; chnum++)
+ dstoffs += (dest[9 + 2 * chnum] << 8) + dest[10 + 2 * chnum];
+ }
+
+ /* encode the video data */
+ if (width > 0 && height > 0)
+ {
+ UINT32 vidlength;
+
+ /* encode the video */
+ err = encode_video(state, width, height, interlaced, source + srcoffs, dest + dstoffs, &vidlength);
+ if (err != AVCERR_NONE)
+ return err;
+
+ /* advance the pointers past the data */
+ srcoffs += width * height * 2;
+ dstoffs += vidlength;
+ }
+
+ /* set the total compression */
+ *complength = dstoffs;
+ return AVCERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ avcomp_decode_data - decode both
+ audio and video from a raw data stream
+-------------------------------------------------*/
+
+avcomp_error avcomp_decode_data(avcomp_state *state, const UINT8 *source, UINT32 complength, UINT8 *dest)
+{
+ UINT32 metasize, channels, samples, width, height;
+ UINT32 srcoffs, dstoffs, totalsize;
+ avcomp_error err;
+ int interlaced;
+ int chnum;
+
+ /* extract info from the header */
+ if (complength < 8)
+ return AVCERR_INVALID_DATA;
+ metasize = source[0];
+ channels = source[1];
+ samples = (source[2] << 8) + source[3];
+ width = (source[4] << 8) + source[5];
+ height = (source[6] << 8) + source[7];
+ interlaced = height >> 15;
+ height &= 0x7fff;
+
+ /* validate the info from the header */
+ if (width > state->maxwidth || height > state->maxheight)
+ return AVCERR_VIDEO_TOO_LARGE;
+ if (channels > state->maxchannels)
+ return AVCERR_AUDIO_TOO_LARGE;
+
+ /* validate that the sizes make sense */
+ if (complength < 9 + 2 * channels)
+ return AVCERR_INVALID_DATA;
+ totalsize = 9 + 2 * channels + source[8];
+ for (chnum = 0; chnum < channels; chnum++)
+ totalsize += (source[9 + 2 * chnum] << 8) | source[10 + 2 * chnum];
+ if (totalsize >= complength)
+ return AVCERR_INVALID_DATA;
+
+ /* starting offsets */
+ srcoffs = 9 + 2 * channels;
+ dstoffs = 12;
+
+ /* write the basics to the new header */
+ dest[0] = 'c';
+ dest[1] = 'h';
+ dest[2] = 'a';
+ dest[3] = 'v';
+ dest[4] = metasize;
+ dest[5] = channels;
+ dest[6] = samples >> 8;
+ dest[7] = samples;
+ dest[8] = width >> 8;
+ dest[9] = width;
+ dest[10] = (interlaced << 7) | (height >> 8);
+ dest[11] = height;
+
+ /* copy the metadata first */
+ if (metasize > 0)
+ {
+ if ((state->decodemask & AVCOMP_DECODE_META) != 0)
+ memcpy(dest + dstoffs, source + srcoffs, metasize);
+ srcoffs += metasize;
+ dstoffs += metasize;
+ }
+
+ /* decode the audio channels */
+ if (channels > 0)
+ {
+ /* decode the audio */
+ err = decode_audio(state, channels, samples, source + srcoffs, dest + dstoffs, &source[8], state->audioxor);
+ if (err != AVCERR_NONE)
+ return err;
+
+ /* advance the pointers past the data */
+ srcoffs += source[8];
+ for (chnum = 0; chnum < channels; chnum++)
+ srcoffs += (source[9 + 2 * chnum] << 8) + source[10 + 2 * chnum];
+ dstoffs += channels * samples * 2;
+ }
+
+ /* decode the video data */
+ if (width > 0 && height > 0 && (state->decodemask & AVCOMP_DECODE_VIDEO) != 0)
+ {
+ /* decode the video */
+ err = decode_video(state, width, height, interlaced, source + srcoffs, complength - srcoffs, dest + dstoffs);
+ if (err != AVCERR_NONE)
+ return err;
+ }
+ return AVCERR_NONE;
+}
+
+
+
+/***************************************************************************
+ ENCODING HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ encode_audio - encode raw audio data
+ to the destination
+-------------------------------------------------*/
+
+static avcomp_error encode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 *dest, UINT8 *sizes)
+{
+ UINT32 size, bytesleft;
+ huffman_error hufferr;
+ int chnum, sampnum;
+ const UINT8 *input;
+ UINT8 *output;
+
+ /* get input/output pointers */
+ input = source;
+ output = state->audiodata;
+
+ /* extract audio deltas */
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ INT16 prev = 0;
+
+ for (sampnum = 0; sampnum < samples; sampnum++)
+ {
+ INT16 cursample, delta;
+
+ /* read current sample (big endian) */
+ cursample = *input++ << 8;
+ cursample |= *input++;
+
+ /* compute delta against previous sample in this channel */
+ delta = cursample - prev;
+ prev = cursample;
+
+ /* store the delta (big endian) */
+ *output++ = delta >> 8;
+ *output++ = delta & 0xff;
+ }
+ }
+
+ /* reset our output pointer and huffman encode */
+ input = state->audiodata;
+ output = dest;
+ bytesleft = channels * samples * 2;
+
+ /* compute a single huffman tree for all the audio data */
+ hufferr = huffman_compute_tree(state->audiocontext, input, bytesleft, 1);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ hufferr = huffman_export_tree(state->audiocontext, output, bytesleft, &size);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ output += size;
+ *sizes++ = size;
+ bytesleft -= size;
+
+ /* encode each stream separately */
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ /* encode the data */
+ hufferr = huffman_encode_data(state->audiocontext, input, samples * 2, output, bytesleft, &size);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ input += samples * 2;
+ output += size;
+ bytesleft = (bytesleft > size) ? (bytesleft - size) : 0;
+
+ /* store the size of this stream */
+ *sizes++ = size >> 8;
+ *sizes++ = size;
+ }
+
+ /* if we didn't compress enough, set the huffman table size to 0 and memcpy the data */
+ if (bytesleft == 0)
+ {
+ /* back up to the beginning */
+ input = source;
+ output = dest;
+ sizes -= 1 + 2 * channels;
+
+ /* huffman table size of 0 */
+ *sizes++ = 0;
+
+ /* write the full size of each stream and then copy it */
+ size = samples * 2;
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ /* copy the data */
+ memcpy(output, input, size);
+ input += size;
+ output += size;
+
+ /* store the size of this stream */
+ *sizes++ = size >> 8;
+ *sizes++ = size;
+ }
+ }
+
+ return AVCERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ encode_video - encode raw video data
+ to the destination
+-------------------------------------------------*/
+
+static avcomp_error encode_video(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT8 *dest, UINT32 *complength)
+{
+ /* only lossless supported at this time */
+ return encode_video_lossless(state, width, height, interlaced, source, dest, complength);
+}
+
+
+/*-------------------------------------------------
+ encode_video_lossless - do a lossless video
+ encoding using deltas and huffman encoding
+-------------------------------------------------*/
+
+static avcomp_error encode_video_lossless(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT8 *dest, UINT32 *complength)
+{
+ UINT32 srcbytes = width * height * 2;
+ int rowbytes = width * 2;
+ huffman_error hufferr;
+ UINT32 outbytes;
+ UINT8 *output;
+ int x, y;
+
+ /* loop over rows */
+ output = state->deltadata;
+ for (y = 0; y < height; y++)
+ {
+ const UINT8 *src = &source[rowbytes * y];
+ UINT8 lasty = (y == 0) ? 0x80 : src[-rowbytes + 1];
+ UINT8 lastcb = (y == 0) ? 0x80 : src[-rowbytes + 0];
+ UINT8 lastcr = (y == 0) ? 0x80 : src[-rowbytes + 2];
+
+ /* loop over columns */
+ for (x = 0; x < rowbytes; x += 4)
+ {
+ *output++ = *src - lastcb;
+ lastcb = *src++;
+ *output++ = *src - lasty;
+ lasty = *src++;
+ *output++ = *src - lastcr;
+ lastcr = *src++;
+ *output++ = *src - lasty;
+ lasty = *src++;
+ }
+ }
+
+ /* set up the output; first byte is 0x80 to indicate lossless encoding */
+ output = dest;
+ *output++ = 0x80;
+
+ /* now encode to the destination using two trees, one for the Y and one for the Cr/Cb */
+
+ /* compute the histograms for the data */
+ hufferr = huffman_compute_tree(state->ycontext, state->deltadata + 0, srcbytes, 2);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ hufferr = huffman_compute_tree(state->ccontext, state->deltadata + 1, srcbytes, 2);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+
+ /* export the two trees to the data stream */
+ hufferr = huffman_export_tree(state->ycontext, output, 256, &outbytes);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ output += outbytes;
+ hufferr = huffman_export_tree(state->ccontext, output, 256, &outbytes);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ output += outbytes;
+
+ /* encode the data using the two trees */
+ hufferr = huffman_encode_data_interleaved_2(state->ycontext, state->ccontext, state->deltadata, srcbytes, output, srcbytes, &outbytes);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_COMPRESSION_ERROR;
+ output += outbytes;
+
+ /* set the final length */
+ *complength = output - dest;
+ return AVCERR_NONE;
+}
+
+
+
+/***************************************************************************
+ DECODING HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ decode_audio - decode audio from a
+ compressed data stream
+-------------------------------------------------*/
+
+static avcomp_error decode_audio(avcomp_state *state, int channels, int samples, const UINT8 *source, UINT8 *dest, const UINT8 *sizes, UINT32 destxor)
+{
+ huffman_error hufferr;
+ int chnum, sampnum;
+ const UINT8 *input;
+ UINT32 actsize;
+ UINT8 *output;
+ UINT16 size;
+
+ /* set up input/output pointers */
+ input = source;
+ output = dest;
+
+ /* if no huffman length, just copy the data */
+ size = *sizes++;
+ if (size == 0)
+ {
+ /* loop over channels */
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ /* extract the size of this channel */
+ size = *sizes++ << 8;
+ size |= *sizes++;
+
+ /* copy the data */
+ if ((state->decodemask & AVCOMP_DECODE_AUDIO(chnum)) != 0)
+ {
+ for (sampnum = 0; sampnum < samples; sampnum++)
+ {
+ output[0 ^ destxor] = input[0];
+ output[1 ^ destxor] = input[1];
+ output += 2;
+ input += 2;
+ }
+ }
+ else
+ {
+ input += size;
+ output += size;
+ }
+ }
+ return AVCERR_NONE;
+ }
+
+ /* extract the huffman tree */
+ input = source;
+ hufferr = huffman_import_tree(state->audiocontext, input, size, &actsize);
+ if (hufferr != HUFFERR_NONE || actsize != size)
+ return AVCERR_INVALID_DATA;
+ input += actsize;
+
+ /* now loop over channels and decode their data */
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ /* extract the size of this channel */
+ size = *sizes++ << 8;
+ size |= *sizes++;
+
+ /* decode the data */
+ if ((state->decodemask & AVCOMP_DECODE_AUDIO(chnum)) != 0)
+ {
+ hufferr = huffman_decode_data(state->audiocontext, input, size, output, samples * 2, &actsize);
+ if (hufferr != HUFFERR_NONE || actsize != size)
+ return AVCERR_INVALID_DATA;
+ }
+
+ /* advance */
+ input += size;
+ output += samples * 2;
+ }
+
+ /* reset input/output pointers */
+ output = dest;
+
+ /* reassemble audio from the deltas */
+ for (chnum = 0; chnum < channels; chnum++)
+ {
+ INT16 prev = 0;
+
+ if ((state->decodemask & AVCOMP_DECODE_AUDIO(chnum)) != 0)
+ {
+ for (sampnum = 0; sampnum < samples; sampnum++)
+ {
+ INT16 cursample;
+
+ /* read current sample (big endian) */
+ cursample = output[0] << 8;
+ cursample |= output[1];
+
+ /* compute delta against previous sample in this channel */
+ cursample += prev;
+ prev = cursample;
+
+ /* store the delta (big endian) */
+ output[0 ^ destxor] = cursample >> 8;
+ output[1 ^ destxor] = cursample;
+ output += 2;
+ }
+ }
+ else
+ output += samples * 2;
+ }
+ return AVCERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ decode_video - decode video from a
+ compressed data stream
+-------------------------------------------------*/
+
+static avcomp_error decode_video(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT32 complength, UINT8 *dest)
+{
+ UINT32 targetstride, targetxor;
+ UINT8 *target;
+
+ /* if we have a target buffer, use that instead */
+ if (state->videobuffer != NULL)
+ {
+ target = state->videobuffer;
+ targetstride = state->videostride;
+ targetxor = state->videoxor;
+ }
+ else
+ {
+ target = dest;
+ targetstride = width * 2;
+ targetxor = 0;
+ }
+
+ /* if the high bit of the first byte is set, we decode losslessly */
+ if (source[0] & 0x80)
+ return decode_video_lossless(state, width, height, interlaced, source, complength, target, targetstride, targetxor);
+ else
+ return AVCERR_INVALID_DATA;
+}
+
+
+/*-------------------------------------------------
+ decode_video_lossless - do a lossless video
+ decoding using deltas and huffman encoding
+-------------------------------------------------*/
+
+static avcomp_error decode_video_lossless(avcomp_state *state, int width, int height, int interlaced, const UINT8 *source, UINT32 complength, UINT8 *dest, UINT32 deststride, UINT32 destxor)
+{
+ const UINT8 *sourceend = source + complength;
+ const huffman_lookup_value *table1, *table2;
+ huffman_error hufferr;
+ UINT32 bitbuf = 0;
+ UINT32 actsize;
+ int sbits = 0;
+ int x, y;
+
+ /* skip the first byte */
+ source++;
+
+ /* decode the table and data */
+ hufferr = huffman_import_tree(state->ycontext, source, sourceend - source, &actsize);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_INVALID_DATA;
+ source += actsize;
+ hufferr = huffman_import_tree(state->ccontext, source, sourceend - source, &actsize);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_INVALID_DATA;
+ source += actsize;
+
+ /* get the lookup tables */
+ hufferr = huffman_get_lookup_table(state->ycontext, &table1);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_OUT_OF_MEMORY;
+ hufferr = huffman_get_lookup_table(state->ccontext, &table2);
+ if (hufferr != HUFFERR_NONE)
+ return AVCERR_OUT_OF_MEMORY;
+
+ /* loop over rows */
+ for (y = 0; y < height; y++)
+ {
+ UINT8 *dst = &dest[y * deststride];
+ UINT8 lasty = (y == 0) ? 0x80 : (dst - deststride)[1 ^ destxor];
+ UINT8 lastcb = (y == 0) ? 0x80 : (dst - deststride)[0 ^ destxor];
+ UINT8 lastcr = (y == 0) ? 0x80 : (dst - deststride)[2 ^ destxor];
+
+ /* loop over columns */
+ for (x = 0; x < width * 2; x += 4)
+ {
+ huffman_lookup_value lookup;
+
+ /* keep the buffer full */
+ while (sbits <= 24)
+ {
+ bitbuf |= *source++ << (24 - sbits);
+ sbits += 8;
+ }
+
+ /* do the Cb component */
+ lookup = table1[bitbuf >> 20];
+ dst[(x + 0) ^ destxor] = lastcb += lookup >> 8;
+ lookup &= 0x1f;
+ bitbuf <<= lookup;
+ sbits -= lookup;
+
+ /* do the Y component */
+ lookup = table2[bitbuf >> 20];
+ dst[(x + 1) ^ destxor] = lasty += lookup >> 8;
+ lookup &= 0x1f;
+ bitbuf <<= lookup;
+ sbits -= lookup;
+
+ /* keep the buffer full */
+ while (sbits <= 24)
+ {
+ bitbuf |= *source++ << (24 - sbits);
+ sbits += 8;
+ }
+
+ /* do the Cr component */
+ lookup = table1[bitbuf >> 20];
+ dst[(x + 2) ^ destxor] = lastcr += lookup >> 8;
+ lookup &= 0x1f;
+ bitbuf <<= lookup;
+ sbits -= lookup;
+
+ /* do the Y component */
+ lookup = table2[bitbuf >> 20];
+ dst[(x + 3) ^ destxor] = lasty += lookup >> 8;
+ lookup &= 0x1f;
+ bitbuf <<= lookup;
+ sbits -= lookup;
+ }
+ }
+
+ return AVCERR_NONE;
+}
diff --git a/src/lib/util/avcomp.h b/src/lib/util/avcomp.h
new file mode 100644
index 00000000000..9a729e3c1c1
--- /dev/null
+++ b/src/lib/util/avcomp.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+
+ avcomp.h
+
+ Audio/video compression and decompression helpers.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __AVCOMP_H__
+
+#include "osdcore.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* errors */
+enum _avcomp_error
+{
+ AVCERR_NONE = 0,
+ AVCERR_INVALID_DATA,
+ AVCERR_VIDEO_TOO_LARGE,
+ AVCERR_AUDIO_TOO_LARGE,
+ AVCERR_OUT_OF_MEMORY,
+ AVCERR_COMPRESSION_ERROR
+};
+typedef enum _avcomp_error avcomp_error;
+
+/* default decompression parameters */
+#define AVCOMP_DECODE_META (1 << 0)
+#define AVCOMP_DECODE_VIDEO (1 << 1)
+#define AVCOMP_DECODE_AUDIO(x) (1 << (2 + (x)))
+#define AVCOMP_DECODE_DEFAULT (~0)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _avcomp_state avcomp_state;
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+avcomp_state *avcomp_init(UINT32 maxwidth, UINT32 maxheight, UINT32 maxchannels);
+void avcomp_free(avcomp_state *state);
+void avcomp_decompress_config(avcomp_state *state, UINT32 decodemask, UINT8 *videobuffer, UINT32 videostride, UINT32 videoxor, UINT32 audioxor);
+
+avcomp_error avcomp_encode_data(avcomp_state *state, const UINT8 *source, UINT8 *dest, UINT32 *complength);
+avcomp_error avcomp_decode_data(avcomp_state *state, const UINT8 *source, UINT32 complength, UINT8 *dest);
+
+#endif
diff --git a/src/lib/util/aviio.c b/src/lib/util/aviio.c
new file mode 100644
index 00000000000..5fa464dcdb4
--- /dev/null
+++ b/src/lib/util/aviio.c
@@ -0,0 +1,2744 @@
+/***************************************************************************
+
+ aviio.c
+
+ AVI movie format parsing helpers.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "aviio.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define FILETYPE_READ 1
+#define FILETYPE_CREATE 2
+
+#define MAX_RIFF_SIZE (2UL * 1024 * 1024 * 1024 - 1024) /* just under 2GB */
+#define MAX_AVI_SIZE_IN_GB (256)
+#define FOUR_GB ((UINT64)1 << 32)
+
+#define MAX_SOUND_CHANNELS 2
+#define SOUND_BUFFER_MSEC 2000 /* microseconds of sond buffering */
+
+#define CHUNKTYPE_RIFF AVI_FOURCC('R','I','F','F')
+#define CHUNKTYPE_LIST AVI_FOURCC('L','I','S','T')
+#define CHUNKTYPE_JUNK AVI_FOURCC('J','U','N','K')
+#define CHUNKTYPE_AVIH AVI_FOURCC('a','v','i','h')
+#define CHUNKTYPE_STRH AVI_FOURCC('s','t','r','h')
+#define CHUNKTYPE_STRF AVI_FOURCC('s','t','r','f')
+#define CHUNKTYPE_IDX1 AVI_FOURCC('i','d','x','1')
+#define CHUNKTYPE_INDX AVI_FOURCC('i','n','d','x')
+#define CHUNKTYPE_XXDB AVI_FOURCC(0x00,0x00,'d','b')
+#define CHUNKTYPE_XXDC AVI_FOURCC(0x00,0x00,'d','c')
+#define CHUNKTYPE_XXWB AVI_FOURCC(0x00,0x00,'w','b')
+#define CHUNKTYPE_IXXX AVI_FOURCC('i','x',0x00,0x00)
+#define CHUNKTYPE_XX_MASK AVI_FOURCC(0x00,0x00,0xff,0xff)
+
+#define LISTTYPE_AVI AVI_FOURCC('A','V','I',' ')
+#define LISTTYPE_AVIX AVI_FOURCC('A','V','I','X')
+#define LISTTYPE_HDRL AVI_FOURCC('h','d','r','l')
+#define LISTTYPE_STRL AVI_FOURCC('s','t','r','l')
+#define LISTTYPE_MOVI AVI_FOURCC('m','o','v','i')
+
+#define STREAMTYPE_VIDS AVI_FOURCC('v','i','d','s')
+#define STREAMTYPE_AUDS AVI_FOURCC('a','u','d','s')
+
+#define HANDLER_DIB AVI_FOURCC('D','I','B',' ')
+#define HANDLER_HFYU AVI_FOURCC('h','f','y','u')
+
+#define FORMAT_UYVY AVI_FOURCC('U','Y','V','Y')
+#define FORMAT_VYUY AVI_FOURCC('V','Y','U','Y')
+#define FORMAT_YUY2 AVI_FOURCC('Y','U','Y','2')
+#define FORMAT_HFYU AVI_FOURCC('H','F','Y','U')
+
+/* main AVI header files */
+#define AVIF_HASINDEX 0x00000010
+#define AVIF_MUSTUSEINDEX 0x00000020
+#define AVIF_ISINTERLEAVED 0x00000100
+#define AVIF_COPYRIGHTED 0x00010000
+#define AVIF_WASCAPTUREFILE 0x00020000
+
+/* index definitions */
+#define AVI_INDEX_OF_INDEXES 0x00
+#define AVI_INDEX_OF_CHUNKS 0x01
+#define AVI_INDEX_IS_DATA 0x80
+#define AVI_INDEX_2FIELD 0x01
+
+/* HuffYUV definitions */
+#define HUFFYUV_PREDICT_LEFT 0
+#define HUFFYUV_PREDICT_GRADIENT 1
+#define HUFFYUV_PREDICT_MEDIAN 2
+#define HUFFYUV_PREDICT_DECORR 0x40
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _avi_chunk avi_chunk;
+struct _avi_chunk
+{
+ UINT64 offset; /* file offset of chunk header */
+ UINT64 size; /* size of this chunk */
+ UINT32 type; /* type of this chunk */
+ UINT32 listtype; /* type of this list (if we are a list) */
+};
+
+
+typedef struct _avi_chunk_list avi_chunk_list;
+struct _avi_chunk_list
+{
+ UINT64 offset; /* offset in the file of header */
+ UINT32 length; /* length of the chunk including header */
+};
+
+
+typedef struct _huffyuv_table huffyuv_table;
+struct _huffyuv_table
+{
+ UINT8 shift[256]; /* bit shift amounts */
+ UINT32 bits[256]; /* bit match values */
+ UINT32 mask[256]; /* bit mask values */
+ UINT16 baselookup[65536]; /* base lookup table */
+ UINT16 * extralookup; /* extra lookup tables */
+};
+
+
+typedef struct _huffyuv_data huffyuv_data;
+struct _huffyuv_data
+{
+ UINT8 predictor; /* predictor */
+ huffyuv_table table[3]; /* array of tables */
+};
+
+
+typedef struct _avi_stream avi_stream;
+struct _avi_stream
+{
+ UINT32 type; /* subtype of stream */
+ UINT32 format; /* format of stream data */
+
+ UINT32 rate; /* timescale for stream */
+ UINT32 scale; /* duration of one sample in the stream */
+ UINT32 samples; /* number of samples */
+
+ avi_chunk_list * chunk; /* list of chunks */
+ UINT32 chunks; /* chunks currently known */
+ UINT32 chunksalloc; /* number of chunks allocated */
+
+ UINT32 width; /* width of video */
+ UINT32 height; /* height of video */
+ UINT32 depth; /* depth of video */
+ UINT8 interlace; /* interlace parameters */
+ huffyuv_data * huffyuv; /* huffyuv decompression data */
+
+ UINT16 channels; /* audio channels */
+ UINT16 samplebits; /* audio bits per sample */
+ UINT32 samplerate; /* audio sample rate */
+
+ /* only used when creating */
+ UINT64 saved_strh_offset; /* writeoffset of strh chunk */
+ UINT64 saved_indx_offset; /* writeoffset of indx chunk */
+};
+
+
+struct _avi_file
+{
+ /* shared data */
+ osd_file * file; /* pointer to open file */
+ int type; /* type of access (read/create) */
+ avi_movie_info info; /* movie info structure */
+ UINT8 * tempbuffer; /* temporary buffer */
+ UINT32 tempbuffersize; /* size of the temporary buffer */
+
+ /* only used when reading */
+ int streams; /* number of streams */
+ avi_stream * stream; /* allocated array of stream information */
+ avi_chunk rootchunk; /* dummy root chunk that wraps the whole file */
+
+ /* only used when creating */
+ UINT64 writeoffs; /* current file write offset */
+ UINT64 riffbase; /* base of the current RIFF */
+
+ avi_chunk chunkstack[8]; /* stack of chunks we are writing */
+ int chunksp; /* stack pointer for the current chunk */
+
+ UINT64 saved_movi_offset; /* writeoffset of movi list */
+ UINT64 saved_avih_offset; /* writeoffset of avih chunk */
+
+ INT16 * soundbuf; /* buffer for sound data */
+ UINT32 soundbuf_samples; /* length of sound buffer in samples */
+ UINT32 soundbuf_chansamples[MAX_SOUND_CHANNELS]; /* samples in buffer for each channel */
+ UINT32 soundbuf_chunks; /* number of chunks completed so far */
+ UINT32 soundbuf_frames; /* number of frames ahead of the video */
+};
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+/* stream helpers */
+
+/* core chunk read routines */
+static avi_error get_first_chunk(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk);
+static avi_error get_next_chunk(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk);
+static avi_error find_first_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result);
+static avi_error find_next_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result);
+static avi_error get_next_chunk_internal(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk, UINT64 offset);
+static avi_error read_chunk_data(avi_file *file, const avi_chunk *chunk, UINT8 **buffer);
+
+/* chunk read helpers */
+static avi_error read_movie_data(avi_file *file);
+static avi_error extract_movie_info(avi_file *file);
+static avi_error parse_avih_chunk(avi_file *file, avi_chunk *avih);
+static avi_error parse_strh_chunk(avi_file *file, avi_stream *stream, avi_chunk *strh);
+static avi_error parse_strf_chunk(avi_file *file, avi_stream *stream, avi_chunk *strf);
+static avi_error parse_indx_chunk(avi_file *file, avi_stream *stream, avi_chunk *strf);
+static avi_error parse_idx1_chunk(avi_file *file, UINT64 baseoffset, avi_chunk *idx1);
+
+/* core chunk write routines */
+static avi_error chunk_open(avi_file *file, UINT32 type, UINT32 listtype, UINT32 estlength);
+static avi_error chunk_close(avi_file *file);
+static avi_error chunk_write(avi_file *file, UINT32 type, const void *data, UINT32 length);
+static avi_error chunk_overwrite(avi_file *file, UINT32 type, const void *data, UINT32 length, UINT64 *offset, int initial_write);
+
+/* chunk write helpers */
+static avi_error write_initial_headers(avi_file *file);
+static avi_error write_avih_chunk(avi_file *file, int initial_write);
+static avi_error write_strh_chunk(avi_file *file, avi_stream *stream, int initial_write);
+static avi_error write_strf_chunk(avi_file *file, avi_stream *stream);
+static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initial_write);
+static avi_error write_idx1_chunk(avi_file *file);
+
+/* sound buffering helpers */
+static avi_error soundbuf_initialize(avi_file *file);
+static avi_error soundbuf_write_chunk(avi_file *file, UINT32 framenum);
+static avi_error soundbuf_flush(avi_file *file, int only_flush_full);
+
+/* YUY helpers */
+static avi_error yuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_t *bitmap);
+static avi_error yuy16_compress_to_yuy(avi_stream *stream, const bitmap_t *bitmap, UINT8 *data, UINT32 numbytes);
+
+/* HuffYUV helpers */
+static avi_error huffyuv_extract_tables(avi_stream *stream, const UINT8 *chunkdata, UINT32 size);
+static avi_error huffyuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_t *bitmap);
+
+/* debugging */
+static void printf_chunk_recursive(avi_file *file, avi_chunk *chunk, int indent);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ fetch_16bits - read 16 bits in LSB order
+ from the given buffer
+-------------------------------------------------*/
+
+INLINE UINT16 fetch_16bits(const UINT8 *data)
+{
+ return data[0] | (data[1] << 8);
+}
+
+
+/*-------------------------------------------------
+ fetch_32bits - read 32 bits in LSB order
+ from the given buffer
+-------------------------------------------------*/
+
+INLINE UINT32 fetch_32bits(const UINT8 *data)
+{
+ return data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
+}
+
+
+/*-------------------------------------------------
+ fetch_64bits - read 64 bits in LSB order
+ from the given buffer
+-------------------------------------------------*/
+
+INLINE UINT64 fetch_64bits(const UINT8 *data)
+{
+ return (UINT64)data[0] | ((UINT64)data[1] << 8) |
+ ((UINT64)data[2] << 16) | ((UINT64)data[3] << 24) |
+ ((UINT64)data[4] << 32) | ((UINT64)data[5] << 40) |
+ ((UINT64)data[6] << 48) | ((UINT64)data[7] << 56);
+}
+
+
+/*-------------------------------------------------
+ put_16bits - write 16 bits in LSB order
+ to the given buffer
+-------------------------------------------------*/
+
+INLINE void put_16bits(UINT8 *data, UINT16 value)
+{
+ data[0] = value >> 0;
+ data[1] = value >> 8;
+}
+
+
+/*-------------------------------------------------
+ put_32bits - write 32 bits in LSB order
+ to the given buffer
+-------------------------------------------------*/
+
+INLINE void put_32bits(UINT8 *data, UINT32 value)
+{
+ data[0] = value >> 0;
+ data[1] = value >> 8;
+ data[2] = value >> 16;
+ data[3] = value >> 24;
+}
+
+
+/*-------------------------------------------------
+ put_64bits - write 64 bits in LSB order
+ to the given buffer
+-------------------------------------------------*/
+
+INLINE void put_64bits(UINT8 *data, UINT64 value)
+{
+ data[0] = value >> 0;
+ data[1] = value >> 8;
+ data[2] = value >> 16;
+ data[3] = value >> 24;
+ data[4] = value >> 32;
+ data[5] = value >> 40;
+ data[6] = value >> 48;
+ data[7] = value >> 56;
+}
+
+
+/*-------------------------------------------------
+ get_video_stream - return a pointer to the
+ video stream
+-------------------------------------------------*/
+
+INLINE avi_stream *get_video_stream(avi_file *file)
+{
+ int streamnum;
+
+ /* find the video stream */
+ for (streamnum = 0; streamnum < file->streams; streamnum++)
+ if (file->stream[streamnum].type == STREAMTYPE_VIDS)
+ return &file->stream[streamnum];
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ get_audio_stream - return a pointer to the
+ audio stream for the 'n'th channel
+-------------------------------------------------*/
+
+INLINE avi_stream *get_audio_stream(avi_file *file, int channel, int *offset)
+{
+ int streamnum;
+
+ /* find the audios stream */
+ for (streamnum = 0; streamnum < file->streams; streamnum++)
+ if (file->stream[streamnum].type == STREAMTYPE_AUDS)
+ {
+ if (channel < file->stream[streamnum].channels)
+ {
+ if (offset != NULL)
+ *offset = channel;
+ return &file->stream[streamnum];
+ }
+ channel -= file->stream[streamnum].channels;
+ }
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ set_stream_chunk_info - set the chunk info
+ for a given chunk within a stream
+-------------------------------------------------*/
+
+INLINE avi_error set_stream_chunk_info(avi_stream *stream, UINT32 index, UINT64 offset, UINT32 length)
+{
+ /* if we need to allocate more, allocate more */
+ if (index >= stream->chunksalloc)
+ {
+ UINT32 newcount = MAX(index, stream->chunksalloc + 1000);
+ stream->chunk = realloc(stream->chunk, newcount * sizeof(stream->chunk[0]));
+ if (stream->chunk == NULL)
+ return AVIERR_NO_MEMORY;
+ stream->chunksalloc = newcount;
+ }
+
+ /* set the data */
+ stream->chunk[index].offset = offset;
+ stream->chunk[index].length = length;
+
+ /* update the number of chunks */
+ stream->chunks = MAX(stream->chunks, index + 1);
+ return AVIERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ compute_idx1_size - compute the size of the
+ idx1 chunk
+-------------------------------------------------*/
+
+INLINE UINT32 compute_idx1_size(avi_file *file)
+{
+ int chunks = 0;
+ int strnum;
+
+ /* count chunks in streams */
+ for (strnum = 0; strnum < file->streams; strnum++)
+ chunks += file->stream[strnum].chunks;
+
+ return chunks * 16 + 8;
+}
+
+
+/*-------------------------------------------------
+ get_chunkid_for_stream - make a chunk id for
+ a given stream
+-------------------------------------------------*/
+
+INLINE UINT32 get_chunkid_for_stream(avi_file *file, avi_stream *stream)
+{
+ UINT32 chunkid;
+
+ chunkid = AVI_FOURCC('0' + (stream - file->stream) / 10, '0' + (stream - file->stream) % 10, 0, 0);
+ if (stream->type == STREAMTYPE_VIDS)
+ chunkid |= (stream->format == 0) ? CHUNKTYPE_XXDB : CHUNKTYPE_XXDC;
+ else if (stream->type == STREAMTYPE_AUDS)
+ chunkid |= CHUNKTYPE_XXWB;
+
+ return chunkid;
+}
+
+
+/*-------------------------------------------------
+ framenum_to_samplenum - given a video frame
+ number, get the first sample number
+-------------------------------------------------*/
+
+INLINE UINT32 framenum_to_samplenum(avi_file *file, UINT32 framenum)
+{
+ return ((UINT64)file->info.audio_samplerate * (UINT64)framenum * (UINT64)file->info.video_sampletime + file->info.video_timescale - 1) / (UINT64)file->info.video_timescale;
+}
+
+
+/*-------------------------------------------------
+ expand_tempbuffer - expand the file's
+ tempbuffer if necessary to contain the
+ requested amount of data
+-------------------------------------------------*/
+
+INLINE avi_error expand_tempbuffer(avi_file *file, UINT32 length)
+{
+ /* expand the tempbuffer to hold the data if necessary */
+ if (length > file->tempbuffersize)
+ {
+ file->tempbuffersize = 2 * length;
+ file->tempbuffer = realloc(file->tempbuffer, file->tempbuffersize);
+ if (file->tempbuffer == NULL)
+ return AVIERR_NO_MEMORY;
+ }
+ return AVIERR_NONE;
+}
+
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ avi_open - open an AVI movie file for read
+-------------------------------------------------*/
+
+avi_error avi_open(const char *filename, avi_file **file)
+{
+ avi_file *newfile = NULL;
+ file_error filerr;
+ avi_error avierr;
+ UINT64 length;
+
+ /* allocate the file */
+ newfile = malloc(sizeof(*newfile));
+ if (newfile == NULL)
+ return AVIERR_NO_MEMORY;
+ memset(newfile, 0, sizeof(*newfile));
+ newfile->type = FILETYPE_READ;
+
+ /* open the file */
+ filerr = osd_open(filename, OPEN_FLAG_READ, &newfile->file, &length);
+ if (filerr != FILERR_NONE)
+ {
+ avierr = AVIERR_CANT_OPEN_FILE;
+ goto error;
+ }
+
+ /* make a root atom */
+ newfile->rootchunk.offset = 0;
+ newfile->rootchunk.size = length;
+ newfile->rootchunk.type = 0;
+ newfile->rootchunk.listtype = 0;
+
+ /* parse the data */
+ avierr = read_movie_data(newfile);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ *file = newfile;
+ return AVIERR_NONE;
+
+error:
+ /* clean up after an error */
+ if (newfile != NULL)
+ {
+ if (newfile->file != NULL)
+ osd_close(newfile->file);
+ free(newfile);
+ }
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ avi_create - create a new QuickTime movie file
+-------------------------------------------------*/
+
+avi_error avi_create(const char *filename, const avi_movie_info *info, avi_file **file)
+{
+ avi_file *newfile = NULL;
+ file_error filerr;
+ avi_stream *stream;
+ avi_error avierr;
+ UINT64 length;
+
+ /* validate video info */
+ if ((info->video_format != 0 && info->video_format != FORMAT_UYVY && info->video_format != FORMAT_VYUY && info->video_format != FORMAT_YUY2) ||
+ info->video_width == 0 ||
+ info->video_height == 0 ||
+ info->video_depth == 0 || info->video_depth % 8 != 0)
+ return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+
+ /* validate audio info */
+ if (info->audio_format != 0 ||
+ info->audio_channels > MAX_SOUND_CHANNELS ||
+ info->audio_samplebits != 16)
+ return AVIERR_UNSUPPORTED_AUDIO_FORMAT;
+
+ /* allocate the file */
+ newfile = malloc(sizeof(*newfile));
+ if (newfile == NULL)
+ return AVIERR_NO_MEMORY;
+ memset(newfile, 0, sizeof(*newfile));
+ newfile->type = FILETYPE_CREATE;
+
+ /* open the file */
+ filerr = osd_open(filename, OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS, &newfile->file, &length);
+ if (filerr != FILERR_NONE)
+ {
+ avierr = AVIERR_CANT_OPEN_FILE;
+ goto error;
+ }
+
+ /* copy the movie info */
+ newfile->info = *info;
+ newfile->info.video_numsamples = 0;
+ newfile->info.audio_numsamples = 0;
+
+ /* allocate two streams */
+ newfile->stream = malloc(2 * sizeof(newfile->stream[0]));
+ if (newfile->stream == NULL)
+ {
+ avierr = AVIERR_NO_MEMORY;
+ goto error;
+ }
+ memset(newfile->stream, 0, 2 * sizeof(newfile->stream[0]));
+
+ /* initialize the video track */
+ stream = &newfile->stream[newfile->streams++];
+ stream->type = STREAMTYPE_VIDS;
+ stream->format = newfile->info.video_format;
+ stream->rate = newfile->info.video_timescale;
+ stream->scale = newfile->info.video_sampletime;
+ stream->width = newfile->info.video_width;
+ stream->height = newfile->info.video_height;
+ stream->depth = newfile->info.video_depth;
+
+ /* initialize the audio track */
+ if (newfile->info.audio_channels > 0)
+ {
+ stream = &newfile->stream[newfile->streams++];
+ stream->type = STREAMTYPE_AUDS;
+ stream->format = newfile->info.audio_format;
+ stream->rate = newfile->info.audio_timescale;
+ stream->scale = newfile->info.audio_sampletime;
+ stream->channels = newfile->info.audio_channels;
+ stream->samplebits = newfile->info.audio_samplebits;
+ stream->samplerate = newfile->info.audio_samplerate;
+
+ /* initialize the sound buffering */
+ avierr = soundbuf_initialize(newfile);
+ if (avierr != AVIERR_NONE)
+ goto error;
+ }
+
+ /* write the initial headers */
+ avierr = write_initial_headers(newfile);
+
+ *file = newfile;
+ return AVIERR_NONE;
+
+error:
+ /* clean up after an error */
+ if (newfile != NULL)
+ {
+ if (newfile->stream != NULL)
+ free(newfile->stream);
+ if (newfile->file != NULL)
+ {
+ osd_close(newfile->file);
+ osd_rmfile(filename);
+ }
+ free(newfile);
+ }
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ avi_close - close a QuickTime movie file
+-------------------------------------------------*/
+
+avi_error avi_close(avi_file *file)
+{
+ avi_error avierr = AVIERR_NONE;
+ int strnum;
+
+ /* if we're creating a new file, finalize it by writing out the non-media chunks */
+ if (file->type == FILETYPE_CREATE)
+ {
+ /* flush any pending sound data */
+ avierr = soundbuf_flush(file, FALSE);
+
+ /* close the movi chunk */
+ if (avierr == AVIERR_NONE)
+ avierr = chunk_close(file);
+
+ /* if this is the first RIFF chunk, write an idx1 */
+ if (avierr == AVIERR_NONE && file->riffbase == 0)
+ avierr = write_idx1_chunk(file);
+
+ /* close the RIFF chunk */
+ if (avierr == AVIERR_NONE)
+ avierr = chunk_close(file);
+
+ /* update the avih chunk */
+ if (avierr == AVIERR_NONE)
+ avierr = write_avih_chunk(file, FALSE);
+
+ /* update the strh and indx chunks for each stream */
+ for (strnum = 0; strnum < file->streams; strnum++)
+ {
+ if (avierr == AVIERR_NONE)
+ avierr = write_strh_chunk(file, &file->stream[strnum], FALSE);
+ if (avierr == AVIERR_NONE)
+ avierr = write_indx_chunk(file, &file->stream[strnum], FALSE);
+ }
+ }
+
+ /* close the file */
+ osd_close(file->file);
+
+ /* free the stream-specific data */
+ for (strnum = 0; strnum < file->streams; strnum++)
+ {
+ avi_stream *stream = &file->stream[strnum];
+ if (stream->huffyuv != NULL)
+ {
+ huffyuv_data *huffyuv = stream->huffyuv;
+ int table;
+
+ for (table = 0; table < ARRAY_LENGTH(huffyuv->table); table++)
+ if (huffyuv->table[table].extralookup != NULL)
+ free(huffyuv->table[table].extralookup);
+ free(huffyuv);
+ }
+ if (stream->chunk != NULL)
+ free(stream->chunk);
+ }
+
+ /* free the file itself */
+ if (file->soundbuf != NULL)
+ free(file->soundbuf);
+ if (file->stream != NULL)
+ free(file->stream);
+ if (file->tempbuffer != NULL)
+ free(file->tempbuffer);
+ free(file);
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ avi_printf_chunks - print the chunks in a file
+-------------------------------------------------*/
+
+void avi_printf_chunks(avi_file *file)
+{
+ printf_chunk_recursive(file, &file->rootchunk, 0);
+}
+
+
+/*-------------------------------------------------
+ avi_error_string - get the error string for
+ an avi_error
+-------------------------------------------------*/
+
+const char *avi_error_string(avi_error err)
+{
+ switch (err)
+ {
+ case AVIERR_NONE: return "success";
+ case AVIERR_END: return "hit end of file";
+ case AVIERR_INVALID_DATA: return "invalid data";
+ case AVIERR_NO_MEMORY: return "out of memory";
+ case AVIERR_READ_ERROR: return "read error";
+ case AVIERR_WRITE_ERROR: return "write error";
+ case AVIERR_STACK_TOO_DEEP: return "stack overflow";
+ case AVIERR_UNSUPPORTED_FEATURE: return "unsupported feature";
+ case AVIERR_CANT_OPEN_FILE: return "unable to open file";
+ case AVIERR_INCOMPATIBLE_AUDIO_STREAMS: return "found incompatible audio streams";
+ case AVIERR_INVALID_SAMPLERATE: return "found invalid sample rate";
+ case AVIERR_INVALID_STREAM: return "invalid stream";
+ case AVIERR_INVALID_FRAME: return "invalid frame index";
+ case AVIERR_INVALID_BITMAP: return "invalid bitmap";
+ case AVIERR_UNSUPPORTED_VIDEO_FORMAT: return "unsupported video format";
+ case AVIERR_UNSUPPORTED_AUDIO_FORMAT: return "unsupported audio format";
+ case AVIERR_EXCEEDED_SOUND_BUFFER: return "sound buffer overflow";
+ default: return "undocumented error";
+ }
+}
+
+
+/*-------------------------------------------------
+ avi_get_movie_info - return a pointer to the
+ movie info
+-------------------------------------------------*/
+
+const avi_movie_info *avi_get_movie_info(avi_file *file)
+{
+ return &file->info;
+}
+
+
+/*-------------------------------------------------
+ avi_frame_to_sample - convert a frame index
+ to a sample index
+-------------------------------------------------*/
+
+UINT32 avi_first_sample_in_frame(avi_file *file, UINT32 framenum)
+{
+ return framenum_to_samplenum(file, framenum);
+}
+
+
+/*-------------------------------------------------
+ avi_read_video_frame_yuy16 - read video data
+ for a particular frame from the AVI file,
+ converting to YUY16 format
+-------------------------------------------------*/
+
+avi_error avi_read_video_frame_yuy16(avi_file *file, UINT32 framenum, bitmap_t *bitmap)
+{
+ avi_error avierr = AVIERR_NONE;
+ UINT32 bytes_read, chunkid;
+ file_error filerr;
+ avi_stream *stream;
+
+ /* get the video stream */
+ stream = get_video_stream(file);
+ if (stream == NULL)
+ return AVIERR_INVALID_STREAM;
+
+ /* validate our ability to handle the data */
+ if (stream->format != FORMAT_UYVY && stream->format != FORMAT_VYUY && stream->format != FORMAT_YUY2 && stream->format != FORMAT_HFYU)
+ return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+
+ /* assume one chunk == one frame */
+ if (framenum >= stream->chunks)
+ return AVIERR_INVALID_FRAME;
+
+ /* we only support YUY-style bitmaps (16bpp) */
+ if (bitmap->format != BITMAP_FORMAT_YUY16 || bitmap->width < stream->width || bitmap->height < stream->height)
+ return AVIERR_INVALID_BITMAP;
+
+ /* expand the tempbuffer to hold the data if necessary */
+ avierr = expand_tempbuffer(file, stream->chunk[framenum].length);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* read in the data */
+ filerr = osd_read(file->file, file->tempbuffer, stream->chunk[framenum].offset, stream->chunk[framenum].length, &bytes_read);
+ if (filerr != FILERR_NONE || bytes_read != stream->chunk[framenum].length)
+ return AVIERR_READ_ERROR;
+
+ /* validate this is good data */
+ chunkid = fetch_32bits(&file->tempbuffer[0]);
+ if (chunkid == get_chunkid_for_stream(file, stream))
+ {
+ /* HuffYUV-compressed */
+ if (stream->format == FORMAT_HFYU)
+ avierr = huffyuv_decompress_to_yuy16(stream, file->tempbuffer + 8, stream->chunk[framenum].length - 8, bitmap);
+
+ /* other YUV-compressed */
+ else
+ avierr = yuv_decompress_to_yuy16(stream, file->tempbuffer + 8, stream->chunk[framenum].length - 8, bitmap);
+ }
+ else
+ avierr = AVIERR_INVALID_DATA;
+
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ avi_read_sound_samples - read sound sample
+ data from an AVI file
+-------------------------------------------------*/
+
+avi_error avi_read_sound_samples(avi_file *file, int channel, UINT32 firstsample, UINT32 numsamples, INT16 *output)
+{
+ avi_error avierr = AVIERR_NONE;
+ UINT32 bytes_per_sample;
+ file_error filerr;
+ avi_stream *stream;
+ int offset;
+
+ /* get the audio stream */
+ stream = get_audio_stream(file, channel, &offset);
+ if (stream == NULL)
+ return AVIERR_INVALID_STREAM;
+
+ /* validate our ability to handle the data */
+ if (stream->format != 0 || (stream->samplebits != 8 && stream->samplebits != 16))
+ return AVIERR_UNSUPPORTED_AUDIO_FORMAT;
+
+ /* verify we are in range */
+ if (firstsample >= stream->samples)
+ return AVIERR_INVALID_FRAME;
+ if (firstsample + numsamples > stream->samples)
+ numsamples = stream->samples - firstsample;
+
+ /* determine bytes per sample */
+ bytes_per_sample = (stream->samplebits / 8) * stream->channels;
+
+ /* loop until all samples have been extracted */
+ while (numsamples > 0)
+ {
+ UINT32 chunkbase = 0, chunkend = 0, chunkid;
+ UINT32 bytes_read, samples_this_chunk;
+ int chunknum, sampnum;
+
+ /* locate the chunk with the first sample */
+ for (chunknum = 0; chunknum < stream->chunks; chunknum++)
+ {
+ chunkend = chunkbase + (stream->chunk[chunknum].length - 8) / bytes_per_sample;
+ if (firstsample < chunkend)
+ break;
+ chunkbase = chunkend;
+ }
+
+ /* expand the tempbuffer to hold the data if necessary */
+ avierr = expand_tempbuffer(file, stream->chunk[chunknum].length);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* read in the data */
+ filerr = osd_read(file->file, file->tempbuffer, stream->chunk[chunknum].offset, stream->chunk[chunknum].length, &bytes_read);
+ if (filerr != FILERR_NONE || bytes_read != stream->chunk[chunknum].length)
+ return AVIERR_READ_ERROR;
+
+ /* validate this is good data */
+ chunkid = fetch_32bits(&file->tempbuffer[0]);
+ if (chunkid != get_chunkid_for_stream(file, stream))
+ return AVIERR_INVALID_DATA;
+
+ /* determine how many samples to copy */
+ samples_this_chunk = chunkend - firstsample;
+ samples_this_chunk = MIN(samples_this_chunk, numsamples);
+
+ /* extract 16-bit samples from the chunk */
+ if (stream->samplebits == 16)
+ {
+ const INT16 *base = (const INT16 *)(file->tempbuffer + 8);
+ base += stream->channels * (firstsample - chunkbase) + offset;
+ for (sampnum = 0; sampnum < samples_this_chunk; sampnum++)
+ {
+ *output++ = LITTLE_ENDIANIZE_INT16(*base);
+ base += stream->channels;
+ }
+ }
+
+ /* extract 8-bit samples from the chunk */
+ else if (stream->samplebits == 8)
+ {
+ const UINT8 *base = (const UINT8 *)(file->tempbuffer + 8);
+ base += stream->channels * (firstsample - chunkbase) + offset;
+ for (sampnum = 0; sampnum < samples_this_chunk; sampnum++)
+ {
+ *output++ = (*base << 8) - 0x8000;
+ base += stream->channels;
+ }
+ }
+
+ /* update our counters */
+ firstsample += samples_this_chunk;
+ numsamples -= samples_this_chunk;
+ }
+
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ avi_append_video_frame_yuy16 - append a frame
+ of video in YUY16 format
+-------------------------------------------------*/
+
+avi_error avi_append_video_frame_yuy16(avi_file *file, const bitmap_t *bitmap)
+{
+ avi_stream *stream = get_video_stream(file);
+ avi_error avierr;
+ UINT32 maxlength;
+
+ /* double check bitmap format */
+ if (bitmap->format != BITMAP_FORMAT_YUY16)
+ return AVIERR_INVALID_BITMAP;
+
+ /* write out any sound data first */
+ avierr = soundbuf_write_chunk(file, stream->chunks);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* make sure we have enough room */
+ maxlength = 2 * stream->width * stream->height;
+ avierr = expand_tempbuffer(file, maxlength);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* now compress the data */
+ avierr = yuy16_compress_to_yuy(stream, bitmap, file->tempbuffer, maxlength);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* set the info for this new chunk */
+ avierr = set_stream_chunk_info(stream, stream->chunks, file->writeoffs, maxlength + 8);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+ stream->samples = file->info.video_numsamples = stream->chunks;
+
+ /* write the data */
+ return chunk_write(file, get_chunkid_for_stream(file, stream), file->tempbuffer, maxlength);
+}
+
+
+/*-------------------------------------------------
+ avi_append_sound_samples - append sound
+ samples
+-------------------------------------------------*/
+
+avi_error avi_append_sound_samples(avi_file *file, int channel, const INT16 *samples, UINT32 numsamples)
+{
+ UINT32 sampoffset = file->soundbuf_chansamples[channel];
+ UINT32 sampnum;
+
+ /* see if we have enough room in the buffer */
+ if (sampoffset + numsamples > file->soundbuf_samples)
+ return AVIERR_EXCEEDED_SOUND_BUFFER;
+
+ /* append samples to the buffer in little-endian format */
+ for (sampnum = 0; sampnum < numsamples; sampnum++)
+ {
+ INT16 data = *samples++;
+ data = LITTLE_ENDIANIZE_INT16(data);
+ file->soundbuf[sampoffset++ * file->info.audio_channels + channel] = data;
+ }
+ file->soundbuf_chansamples[channel] = sampoffset;
+
+ /* flush any full sound chunks to disk */
+ return soundbuf_flush(file, TRUE);
+}
+
+
+/*-------------------------------------------------
+ read_chunk_data - read a chunk's data into
+ memory
+-------------------------------------------------*/
+
+static avi_error read_chunk_data(avi_file *file, const avi_chunk *chunk, UINT8 **buffer)
+{
+ file_error filerr;
+ UINT32 bytes_read;
+
+ /* allocate memory for the data */
+ *buffer = malloc(chunk->size);
+ if (*buffer == NULL)
+ return AVIERR_NO_MEMORY;
+
+ /* read from the file */
+ filerr = osd_read(file->file, *buffer, chunk->offset + 8, chunk->size, &bytes_read);
+ if (filerr != FILERR_NONE || bytes_read != chunk->size)
+ {
+ free(*buffer);
+ *buffer = NULL;
+ return AVIERR_READ_ERROR;
+ }
+
+ return AVIERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ get_first_chunk - get information about the
+ first chunk in a container
+-------------------------------------------------*/
+
+static avi_error get_first_chunk(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk)
+{
+ UINT64 startoffset = (parent != NULL && parent->type != 0) ? parent->offset + 12 : 0;
+ if (parent != NULL && parent->type != CHUNKTYPE_LIST && parent->type != CHUNKTYPE_RIFF && parent->type != 0)
+ return AVIERR_INVALID_DATA;
+ return get_next_chunk_internal(file, parent, newchunk, startoffset);
+}
+
+
+/*-------------------------------------------------
+ get_next_chunk - get information about the
+ next chunk in a container
+-------------------------------------------------*/
+
+static avi_error get_next_chunk(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk)
+{
+ UINT64 nextoffset = newchunk->offset + 8 + newchunk->size + (newchunk->size & 1);
+ return get_next_chunk_internal(file, parent, newchunk, nextoffset);
+}
+
+
+/*-------------------------------------------------
+ find_first_chunk - get information about the
+ first chunk of a particular type in a container
+-------------------------------------------------*/
+
+static avi_error find_first_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+{
+ avi_error avierr;
+
+ for (avierr = get_first_chunk(file, container, result); avierr == AVIERR_NONE; avierr = get_next_chunk(file, container, result))
+ if (result->type == findme)
+ return AVIERR_NONE;
+
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ find_next_chunk - get information about the
+ next chunk of a particular type in a container
+-------------------------------------------------*/
+
+static avi_error find_next_chunk(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+{
+ avi_error avierr;
+
+ for (avierr = get_next_chunk(file, container, result); avierr == AVIERR_NONE; avierr = get_next_chunk(file, container, result))
+ if (result->type == findme)
+ return AVIERR_NONE;
+
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ find_first_list - get information about the
+ first list of a particular type in a container
+-------------------------------------------------*/
+
+static avi_error find_first_list(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+{
+ avi_error avierr;
+
+ for (avierr = find_first_chunk(file, CHUNKTYPE_LIST, container, result); avierr == AVIERR_NONE; avierr = find_next_chunk(file, CHUNKTYPE_LIST, container, result))
+ if (result->listtype == findme)
+ return AVIERR_NONE;
+
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ find_next_list - get information about the
+ next list of a particular type in a container
+-------------------------------------------------*/
+
+static avi_error find_next_list(avi_file *file, UINT32 findme, const avi_chunk *container, avi_chunk *result)
+{
+ avi_error avierr;
+
+ for (avierr = find_next_chunk(file, CHUNKTYPE_LIST, container, result); avierr == AVIERR_NONE; avierr = find_next_chunk(file, CHUNKTYPE_LIST, container, result))
+ if (result->listtype == findme)
+ return AVIERR_NONE;
+
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ get_next_chunk_internal - fetch the next
+ chunk relative to the current one
+-------------------------------------------------*/
+
+static avi_error get_next_chunk_internal(avi_file *file, const avi_chunk *parent, avi_chunk *newchunk, UINT64 offset)
+{
+ file_error filerr;
+ UINT8 buffer[12];
+ UINT32 bytesread;
+
+ /* NULL parent implies the root */
+ if (parent == NULL)
+ parent = &file->rootchunk;
+
+ /* start at the current offset */
+ newchunk->offset = offset;
+
+ /* if we're past the bounds of the parent, bail */
+ if (newchunk->offset + 8 >= parent->offset + 8 + parent->size)
+ return AVIERR_END;
+
+ /* read the header */
+ filerr = osd_read(file->file, buffer, newchunk->offset, 8, &bytesread);
+ if (filerr != FILERR_NONE || bytesread != 8)
+ return AVIERR_INVALID_DATA;
+
+ /* fill in the new chunk */
+ newchunk->type = fetch_32bits(&buffer[0]);
+ newchunk->size = fetch_32bits(&buffer[4]);
+
+ /* if we are a list, fetch the list type */
+ if (newchunk->type == CHUNKTYPE_LIST || newchunk->type == CHUNKTYPE_RIFF)
+ {
+ filerr = osd_read(file->file, &buffer[8], newchunk->offset + 8, 4, &bytesread);
+ if (filerr != FILERR_NONE || bytesread != 4)
+ return AVIERR_INVALID_DATA;
+ newchunk->listtype = fetch_32bits(&buffer[8]);
+ }
+
+ return AVIERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ read_movie_data - get data about a movie
+-------------------------------------------------*/
+
+static avi_error read_movie_data(avi_file *file)
+{
+ avi_chunk riff, hdrl, avih, strl, strh, strf, indx, movi, idx1;
+ avi_error avierr;
+ int strindex;
+
+ /* find the RIFF chunk */
+ avierr = find_first_chunk(file, CHUNKTYPE_RIFF, NULL, &riff);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* verify that the RIFF type is AVI */
+ if (riff.listtype != LISTTYPE_AVI)
+ {
+ avierr = AVIERR_INVALID_DATA;
+ goto error;
+ }
+
+ /* find the hdrl LIST chunk within the RIFF */
+ avierr = find_first_list(file, LISTTYPE_HDRL, &riff, &hdrl);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* find the avih chunk */
+ avierr = find_first_chunk(file, CHUNKTYPE_AVIH, &hdrl, &avih);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* parse the avih chunk */
+ avierr = parse_avih_chunk(file, &avih);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* loop over strl LIST chunks */
+ strindex = 0;
+ for (avierr = find_first_list(file, LISTTYPE_STRL, &hdrl, &strl); avierr == AVIERR_NONE; avierr = find_next_list(file, LISTTYPE_STRL, &hdrl, &strl))
+ {
+ /* if we have too many, it's a bad file */
+ if (strindex >= file->streams)
+ goto error;
+
+ /* find the strh chunk */
+ avierr = find_first_chunk(file, CHUNKTYPE_STRH, &strl, &strh);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* parse the data */
+ avierr = parse_strh_chunk(file, &file->stream[strindex], &strh);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* find the strf chunk */
+ avierr = find_first_chunk(file, CHUNKTYPE_STRF, &strl, &strf);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* parse the data */
+ avierr = parse_strf_chunk(file, &file->stream[strindex], &strf);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* find the indx chunk, if present */
+ avierr = find_first_chunk(file, CHUNKTYPE_INDX, &strl, &indx);
+ if (avierr == AVIERR_NONE)
+ avierr = parse_indx_chunk(file, &file->stream[strindex], &indx);
+
+ /* next stream */
+ strindex++;
+ }
+
+ /* normalize the error after parsing the stream headers */
+ if (avierr == AVIERR_END)
+ avierr = AVIERR_NONE;
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* find the base of the movi data */
+ avierr = find_first_list(file, LISTTYPE_MOVI, &riff, &movi);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* find and parse the idx1 chunk within the RIFF (if present) */
+ avierr = find_first_chunk(file, CHUNKTYPE_IDX1, &riff, &idx1);
+ if (avierr == AVIERR_NONE)
+ avierr = parse_idx1_chunk(file, movi.offset + 8, &idx1);
+ avierr = AVIERR_NONE;
+
+ /* now extract the movie info */
+ avierr = extract_movie_info(file);
+
+error:
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ extract_movie_info - extract the movie info
+ from the streams we've read
+-------------------------------------------------*/
+
+static avi_error extract_movie_info(avi_file *file)
+{
+ avi_stream *audiostream;
+ avi_stream *stream;
+
+ /* get the video stream */
+ stream = get_video_stream(file);
+ if (stream != NULL)
+ {
+ /* fill in the info */
+ file->info.video_format = stream->format;
+ file->info.video_timescale = stream->rate;
+ file->info.video_sampletime = stream->scale;
+ file->info.video_numsamples = stream->samples;
+ file->info.video_width = stream->width;
+ file->info.video_height = stream->height;
+ }
+
+ /* get the first audio stream */
+ stream = get_audio_stream(file, 0, NULL);
+ if (stream != NULL)
+ {
+ /* fill in the info */
+ file->info.audio_format = stream->format;
+ file->info.audio_timescale = stream->rate;
+ file->info.audio_sampletime = stream->scale;
+ file->info.audio_numsamples = stream->samples;
+ file->info.audio_channels = 1;
+ file->info.audio_samplebits = stream->samplebits;
+ file->info.audio_samplerate = stream->samplerate;
+ }
+
+ /* now make sure all other audio streams are valid */
+ audiostream = stream;
+ while (1)
+ {
+ /* get the stream info */
+ stream = get_audio_stream(file, file->info.audio_channels, NULL);
+ if (stream == NULL)
+ break;
+ file->info.audio_channels++;
+
+ /* verify compatibility */
+ if (file->info.audio_format != stream->format ||
+ file->info.audio_timescale != stream->rate ||
+ file->info.audio_sampletime != stream->scale ||
+ file->info.audio_numsamples != stream->samples ||
+ file->info.audio_samplebits != stream->samplebits ||
+ file->info.audio_samplerate != stream->samplerate)
+ return AVIERR_INCOMPATIBLE_AUDIO_STREAMS;
+ }
+
+ return AVIERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ parse_avih_chunk - parse an avih header
+ chunk
+-------------------------------------------------*/
+
+static avi_error parse_avih_chunk(avi_file *file, avi_chunk *avih)
+{
+ UINT8 *chunkdata = NULL;
+ avi_error avierr;
+
+ /* read the data */
+ avierr = read_chunk_data(file, avih, &chunkdata);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* extract the data */
+ file->streams = fetch_32bits(&chunkdata[24]);
+
+ /* allocate memory for the streams */
+ file->stream = malloc(sizeof(*file->stream) * file->streams);
+ if (file->stream == NULL)
+ goto error;
+ memset(file->stream, 0, sizeof(*file->stream) * file->streams);
+
+error:
+ if (chunkdata != NULL)
+ free(chunkdata);
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ parse_strh_chunk - parse a strh header
+ chunk
+-------------------------------------------------*/
+
+static avi_error parse_strh_chunk(avi_file *file, avi_stream *stream, avi_chunk *strh)
+{
+ UINT8 *chunkdata = NULL;
+ avi_error avierr;
+
+ /* read the data */
+ avierr = read_chunk_data(file, strh, &chunkdata);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* extract the data */
+ stream->type = fetch_32bits(&chunkdata[0]);
+ stream->scale = fetch_32bits(&chunkdata[20]);
+ stream->rate = fetch_32bits(&chunkdata[24]);
+ stream->samples = fetch_32bits(&chunkdata[32]);
+
+error:
+ if (chunkdata != NULL)
+ free(chunkdata);
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ parse_strf_chunk - parse a strf header
+ chunk
+-------------------------------------------------*/
+
+static avi_error parse_strf_chunk(avi_file *file, avi_stream *stream, avi_chunk *strf)
+{
+ UINT8 *chunkdata = NULL;
+ avi_error avierr;
+
+ /* read the data */
+ avierr = read_chunk_data(file, strf, &chunkdata);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* audio and video streams have differing headers */
+ if (stream->type == STREAMTYPE_VIDS)
+ {
+ stream->width = fetch_32bits(&chunkdata[4]);
+ stream->height = fetch_32bits(&chunkdata[8]);
+ stream->depth = fetch_16bits(&chunkdata[14]);
+ stream->format = fetch_32bits(&chunkdata[16]);
+
+ /* extra extraction for HuffYUV data */
+ if (stream->format == FORMAT_HFYU && strf->size >= 56)
+ {
+ avierr = huffyuv_extract_tables(stream, chunkdata, strf->size);
+ if (avierr != AVIERR_NONE)
+ goto error;
+ }
+ }
+ else if (stream->type == STREAMTYPE_AUDS)
+ {
+ stream->channels = fetch_16bits(&chunkdata[2]);
+ stream->samplebits = fetch_16bits(&chunkdata[14]);
+ stream->samplerate = fetch_32bits(&chunkdata[4]);
+ }
+
+error:
+ if (chunkdata != NULL)
+ free(chunkdata);
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ parse_indx_chunk - parse an indx chunk
+-------------------------------------------------*/
+
+static avi_error parse_indx_chunk(avi_file *file, avi_stream *stream, avi_chunk *strf)
+{
+ UINT32 entries, entry, id;
+ UINT8 *chunkdata = NULL;
+ UINT16 longs_per_entry;
+ UINT8 subtype, type;
+ UINT64 baseoffset;
+ avi_error avierr;
+
+ /* read the data */
+ avierr = read_chunk_data(file, strf, &chunkdata);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* extract the data */
+ longs_per_entry = fetch_16bits(&chunkdata[0]);
+ subtype = chunkdata[2];
+ type = chunkdata[3];
+ entries = fetch_32bits(&chunkdata[4]);
+ id = fetch_32bits(&chunkdata[8]);
+ baseoffset = fetch_64bits(&chunkdata[12]);
+
+ /* if this is a superindex, loop over entries and call ourselves recursively */
+ if (type == AVI_INDEX_OF_INDEXES)
+ {
+ /* validate the size of each entry */
+ if (longs_per_entry != 4)
+ return AVIERR_INVALID_DATA;
+
+ /* loop over entries and create subchunks for each */
+ for (entry = 0; entry < entries; entry++)
+ {
+ const UINT8 *base = &chunkdata[24 + entry * 16];
+ file_error filerr;
+ avi_chunk subchunk;
+ UINT32 bytes_read;
+ UINT8 buffer[8];
+
+ /* go read the subchunk */
+ subchunk.offset = fetch_64bits(&base[0]);
+ filerr = osd_read(file->file, buffer, subchunk.offset, sizeof(buffer), &bytes_read);
+ if (filerr != FILERR_NONE || bytes_read != sizeof(buffer))
+ {
+ avierr = AVIERR_READ_ERROR;
+ break;
+ }
+
+ /* parse the data */
+ subchunk.type = fetch_32bits(&buffer[0]);
+ subchunk.size = fetch_32bits(&buffer[4]);
+
+ /* recursively parse each referenced chunk; stop if we hit an error */
+ avierr = parse_indx_chunk(file, stream, &subchunk);
+ if (avierr != AVIERR_NONE)
+ break;
+ }
+ }
+
+ /* otherwise, this is a standard index */
+ else if (type == AVI_INDEX_OF_CHUNKS)
+ {
+ /* validate the size of each entry */
+ if (longs_per_entry != 2 && longs_per_entry != 3)
+ return AVIERR_INVALID_DATA;
+
+ /* loop over entries and parse out the data */
+ for (entry = 0; entry < entries; entry++)
+ {
+ const UINT8 *base = &chunkdata[24 + entry * 4 * longs_per_entry];
+ UINT32 offset = fetch_32bits(&base[0]);
+ UINT32 size = fetch_32bits(&base[4]);
+
+ /* set the info for this chunk and advance */
+ avierr = set_stream_chunk_info(stream, stream->chunks++, baseoffset + offset - 8, size + 8);
+ if (avierr != AVIERR_NONE)
+ break;
+ }
+ }
+
+error:
+ if (chunkdata != NULL)
+ free(chunkdata);
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ parse_idx1_chunk - parse an idx1 chunk
+-------------------------------------------------*/
+
+static avi_error parse_idx1_chunk(avi_file *file, UINT64 baseoffset, avi_chunk *idx1)
+{
+ UINT8 *chunkdata = NULL;
+ avi_error avierr;
+ UINT32 entries;
+ UINT32 entry;
+
+ /* read the data */
+ avierr = read_chunk_data(file, idx1, &chunkdata);
+ if (avierr != AVIERR_NONE)
+ goto error;
+
+ /* loop over entries */
+ entries = idx1->size / 16;
+ for (entry = 0; entry < entries; entry++)
+ {
+ const UINT8 *base = &chunkdata[entry * 16];
+ UINT32 chunkid = fetch_32bits(&base[0]);
+ UINT32 offset = fetch_32bits(&base[8]);
+ UINT32 size = fetch_32bits(&base[12]);
+ avi_stream *stream;
+ int streamnum;
+
+ /* determine the stream index */
+ streamnum = ((chunkid >> 8) & 0xff) - '0';
+ streamnum += 10 * ((chunkid & 0xff) - '0');
+ if (streamnum >= file->streams)
+ {
+ avierr = AVIERR_INVALID_DATA;
+ goto error;
+ }
+ stream = &file->stream[streamnum];
+
+ /* set the appropriate entry */
+ avierr = set_stream_chunk_info(stream, stream->chunks++, baseoffset + offset, size + 8);
+ if (avierr != AVIERR_NONE)
+ goto error;
+ }
+
+error:
+ if (chunkdata != NULL)
+ free(chunkdata);
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ chunk_open - open a new chunk for writing
+-------------------------------------------------*/
+
+static avi_error chunk_open(avi_file *file, UINT32 type, UINT32 listtype, UINT32 estlength)
+{
+ file_error filerr;
+ avi_chunk *chunk;
+ UINT32 written;
+
+ /* if we're out of stack entries, bail */
+ if (file->chunksp >= ARRAY_LENGTH(file->chunkstack))
+ return AVIERR_STACK_TOO_DEEP;
+ chunk = &file->chunkstack[file->chunksp++];
+
+ /* set up the chunk information */
+ chunk->offset = file->writeoffs;
+ chunk->size = estlength;
+ chunk->type = type;
+ chunk->listtype = listtype;
+
+ /* non-list types */
+ if (type != CHUNKTYPE_RIFF && type != CHUNKTYPE_LIST)
+ {
+ UINT8 buffer[8];
+
+ /* populate the header */
+ put_32bits(&buffer[0], chunk->type);
+ put_32bits(&buffer[4], chunk->size);
+
+ /* write the header */
+ filerr = osd_write(file->file, buffer, file->writeoffs, sizeof(buffer), &written);
+ if (filerr != FILERR_NONE || written != sizeof(buffer))
+ return AVIERR_WRITE_ERROR;
+ file->writeoffs += written;
+ }
+
+ /* list types */
+ else
+ {
+ UINT8 buffer[12];
+
+ /* populate the header */
+ put_32bits(&buffer[0], chunk->type);
+ put_32bits(&buffer[4], chunk->size);
+ put_32bits(&buffer[8], chunk->listtype);
+
+ /* write the header */
+ filerr = osd_write(file->file, buffer, file->writeoffs, sizeof(buffer), &written);
+ if (filerr != FILERR_NONE || written != sizeof(buffer))
+ return AVIERR_WRITE_ERROR;
+ file->writeoffs += written;
+ }
+
+ return AVIERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ chunk_close - finish writing an chunk
+-------------------------------------------------*/
+
+static avi_error chunk_close(avi_file *file)
+{
+ avi_chunk *chunk = &file->chunkstack[--file->chunksp];
+ UINT64 chunksize = file->writeoffs - (chunk->offset + 8);
+ UINT32 written;
+
+ /* error if we don't fit into 32 bits */
+ if (chunksize != (UINT32)chunksize)
+ return AVIERR_INVALID_DATA;
+
+ /* write the final size if it is different from the guess */
+ if (chunk->size != chunksize)
+ {
+ file_error filerr;
+ UINT8 buffer[4];
+
+ put_32bits(&buffer[0], (UINT32)chunksize);
+ filerr = osd_write(file->file, buffer, chunk->offset + 4, sizeof(buffer), &written);
+ if (filerr != FILERR_NONE || written != sizeof(buffer))
+ return AVIERR_WRITE_ERROR;
+ }
+
+ /* round up to the next word */
+ file->writeoffs += chunksize & 1;
+
+ return AVIERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ chunk_write - write an chunk and its data
+-------------------------------------------------*/
+
+static avi_error chunk_write(avi_file *file, UINT32 type, const void *data, UINT32 length)
+{
+ file_error filerr;
+ avi_error avierr;
+ UINT32 written;
+
+ /* if we are getting too big, split the RIFF */
+ if ((file->riffbase == 0 && file->writeoffs + length + compute_idx1_size(file) >= MAX_RIFF_SIZE) ||
+ file->writeoffs + length - file->riffbase >= MAX_RIFF_SIZE)
+ {
+ /* close the movi list */
+ avierr = chunk_close(file);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* write the idx1 chunk if this is the first */
+ if (file->riffbase == 0)
+ {
+ avierr = write_idx1_chunk(file);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+ }
+
+ /* close the RIFF */
+ avierr = chunk_close(file);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* open a new RIFF */
+ file->riffbase = file->writeoffs;
+ avierr = chunk_open(file, CHUNKTYPE_RIFF, LISTTYPE_AVIX, 0);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* open a nested movi list */
+ file->saved_movi_offset = file->writeoffs;
+ avierr = chunk_open(file, CHUNKTYPE_LIST, LISTTYPE_MOVI, 0);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+ }
+
+ /* open the chunk */
+ avierr = chunk_open(file, type, 0, length);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* write the data */
+ filerr = osd_write(file->file, data, file->writeoffs, length, &written);
+ if (filerr != FILERR_NONE || written != length)
+ return AVIERR_WRITE_ERROR;
+ file->writeoffs += written;
+
+ /* close the chunk */
+ return chunk_close(file);
+}
+
+
+/*-------------------------------------------------
+ chunk_overwrite - write a chunk in two passes;
+ first pass writes to the end of file and
+ saves the offset; second pass overwrites the
+ original
+-------------------------------------------------*/
+
+static avi_error chunk_overwrite(avi_file *file, UINT32 type, const void *data, UINT32 length, UINT64 *offset, int initial_write)
+{
+ UINT64 savedoffset = 0;
+ avi_error avierr;
+
+ /* if this is our initial write, save the offset */
+ if (initial_write)
+ *offset = file->writeoffs;
+
+ /* otherwise, remember the current write offset and replace it with the original */
+ else
+ {
+ savedoffset = file->writeoffs;
+ file->writeoffs = *offset;
+ }
+
+ /* write the chunk */
+ avierr = chunk_write(file, type, data, length);
+
+ /* if this isn't the initial write, restore the previous offset */
+ if (!initial_write)
+ file->writeoffs = savedoffset;
+
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ write_initial_headers - write out the inital
+ set of AVI and stream headers
+-------------------------------------------------*/
+
+static avi_error write_initial_headers(avi_file *file)
+{
+ avi_error avierr;
+ int strnum;
+
+ /* reset the write pointer */
+ file->writeoffs = 0;
+
+ /* open a RIFF chunk */
+ avierr = chunk_open(file, CHUNKTYPE_RIFF, LISTTYPE_AVI, 0);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* open a hdlr LIST */
+ avierr = chunk_open(file, CHUNKTYPE_LIST, LISTTYPE_HDRL, 0);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* write an avih chunk */
+ avierr = write_avih_chunk(file, TRUE);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* for each stream, write a strl LIST */
+ for (strnum = 0; strnum < file->streams; strnum++)
+ {
+ /* open a strl LIST */
+ avierr = chunk_open(file, CHUNKTYPE_LIST, LISTTYPE_STRL, 0);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* write the strh chunk */
+ avierr = write_strh_chunk(file, &file->stream[strnum], TRUE);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* write the strf chunk */
+ avierr = write_strf_chunk(file, &file->stream[strnum]);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* write the indx chunk */
+ avierr = write_indx_chunk(file, &file->stream[strnum], TRUE);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* close the strl LIST */
+ avierr = chunk_close(file);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+ }
+
+ /* close the hdlr LIST */
+ avierr = chunk_close(file);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* open a movi LIST */
+ file->saved_movi_offset = file->writeoffs;
+ avierr = chunk_open(file, CHUNKTYPE_LIST, LISTTYPE_MOVI, 0);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ write_avih_chunk - write the avih header
+ chunk
+-------------------------------------------------*/
+
+static avi_error write_avih_chunk(avi_file *file, int initial_write)
+{
+ avi_stream *video = get_video_stream(file);
+ UINT8 buffer[56];
+
+ /* reset the buffer */
+ memset(buffer, 0, sizeof(buffer));
+
+ put_32bits(&buffer[0], 1000000 * (INT64)video->scale / video->rate); /* dwMicroSecPerFrame */
+ put_32bits(&buffer[12], AVIF_HASINDEX | AVIF_ISINTERLEAVED); /* dwFlags */
+ put_32bits(&buffer[16], video->samples); /* dwTotalFrames */
+ put_32bits(&buffer[24], file->streams); /* dwStreams */
+ put_32bits(&buffer[32], video->width); /* dwWidth */
+ put_32bits(&buffer[36], video->height); /* dwHeight */
+
+ /* (over)write the chunk */
+ return chunk_overwrite(file, CHUNKTYPE_AVIH, buffer, sizeof(buffer), &file->saved_avih_offset, initial_write);
+}
+
+
+/*-------------------------------------------------
+ write_strh_chunk - write the strh header
+ chunk
+-------------------------------------------------*/
+
+static avi_error write_strh_chunk(avi_file *file, avi_stream *stream, int initial_write)
+{
+ UINT8 buffer[56];
+
+ /* reset the buffer */
+ memset(buffer, 0, sizeof(buffer));
+
+ put_32bits(&buffer[0], stream->type); /* fccType */
+ put_32bits(&buffer[20], stream->scale); /* dwScale */
+ put_32bits(&buffer[24], stream->rate); /* dwRate */
+ put_32bits(&buffer[32], stream->samples); /* dwLength */
+ put_32bits(&buffer[40], 10000); /* dwQuality */
+
+ /* video-stream specific data */
+ if (stream->type == STREAMTYPE_VIDS)
+ {
+ put_32bits(&buffer[4], /* fccHandler */
+ (stream->format == FORMAT_HFYU) ? HANDLER_HFYU : HANDLER_DIB);
+ put_32bits(&buffer[36], /* dwSuggestedBufferSize */
+ stream->width * stream->height * 4);
+ put_16bits(&buffer[52], stream->width); /* rcFrame.right */
+ put_16bits(&buffer[54], stream->height); /* rcFrame.bottom */
+ }
+
+ /* audio-stream specific data */
+ if (stream->type == STREAMTYPE_AUDS)
+ {
+ put_32bits(&buffer[36], /* dwSuggestedBufferSize */
+ stream->samplerate * stream->channels * (stream->samplebits / 8));
+ put_32bits(&buffer[44], /* dwSampleSize */
+ stream->channels * (stream->samplebits / 8));
+ }
+
+ /* write the chunk */
+ return chunk_overwrite(file, CHUNKTYPE_STRH, buffer, sizeof(buffer), &stream->saved_strh_offset, initial_write);
+}
+
+
+/*-------------------------------------------------
+ write_strf_chunk - write the strf header
+ chunk
+-------------------------------------------------*/
+
+static avi_error write_strf_chunk(avi_file *file, avi_stream *stream)
+{
+ /* video stream */
+ if (stream->type == STREAMTYPE_VIDS)
+ {
+ UINT8 buffer[40];
+
+ /* reset the buffer */
+ memset(buffer, 0, sizeof(buffer));
+
+ put_32bits(&buffer[0], sizeof(buffer)); /* biSize */
+ put_32bits(&buffer[4], stream->width); /* biWidth */
+ put_32bits(&buffer[8], stream->height); /* biHeight */
+ put_16bits(&buffer[12], 1); /* biPlanes */
+ put_16bits(&buffer[14], stream->depth); /* biBitCount */
+ put_32bits(&buffer[16], stream->format); /* biCompression */
+ put_32bits(&buffer[20], /* biSizeImage */
+ stream->width * stream->height * (stream->depth + 7) / 8);
+
+ /* write the chunk */
+ return chunk_write(file, CHUNKTYPE_STRF, buffer, sizeof(buffer));
+ }
+
+ /* audio stream */
+ if (stream->type == STREAMTYPE_AUDS)
+ {
+ UINT8 buffer[16];
+
+ /* reset the buffer */
+ memset(buffer, 0, sizeof(buffer));
+
+ put_16bits(&buffer[0], 1); /* wFormatTag */
+ put_16bits(&buffer[2], stream->channels); /* nChannels */
+ put_32bits(&buffer[4], stream->samplerate); /* nSamplesPerSec */
+ put_32bits(&buffer[8], /* nAvgBytesPerSec */
+ stream->samplerate * stream->channels * (stream->samplebits / 8));
+ put_16bits(&buffer[12], /* nBlockAlign */
+ stream->channels * (stream->samplebits / 8));
+ put_16bits(&buffer[14], stream->samplebits); /* wBitsPerSample */
+
+ /* write the chunk */
+ return chunk_write(file, CHUNKTYPE_STRF, buffer, sizeof(buffer));
+ }
+
+ return AVIERR_INVALID_DATA;
+}
+
+
+/*-------------------------------------------------
+ write_indx_chunk - write the indx header
+ chunk
+-------------------------------------------------*/
+
+static avi_error write_indx_chunk(avi_file *file, avi_stream *stream, int initial_write)
+{
+ UINT8 buffer[24 + 16 * MAX_AVI_SIZE_IN_GB / 4];
+ UINT32 chunkid, indexchunkid;
+ UINT32 master_entries = 0;
+
+ /* reset the buffer */
+ memset(buffer, 0, sizeof(buffer));
+
+ /* construct the chunk ID and index chunk ID */
+ chunkid = get_chunkid_for_stream(file, stream);
+ indexchunkid = AVI_FOURCC('i', 'x', '0' + (stream - file->stream) / 10, '0' + (stream - file->stream) % 10);
+
+ /* loop over chunks of 4GB and write out indexes for them first */
+ if (!initial_write && file->riffbase != 0)
+ {
+ UINT64 currentbase;
+ for (currentbase = 0; currentbase < file->writeoffs; currentbase += FOUR_GB)
+ {
+ UINT64 currentend = currentbase + FOUR_GB;
+ UINT32 chunks_this_index = 0;
+ UINT32 bytes_this_index = 0;
+ avi_error avierr;
+ UINT32 chunknum;
+ UINT8 *tempbuf;
+
+ /* count chunks that are in this region */
+ for (chunknum = 0; chunknum < stream->chunks; chunknum++)
+ if (stream->chunk[chunknum].offset >= currentbase && stream->chunk[chunknum].offset < currentend)
+ chunks_this_index++;
+
+ /* if no chunks, skip */
+ if (chunks_this_index == 0)
+ continue;
+
+ /* allocate memory */
+ tempbuf = malloc(24 + 8 * chunks_this_index);
+ if (tempbuf == NULL)
+ return AVIERR_NO_MEMORY;
+ memset(tempbuf, 0, 24 + 8 * chunks_this_index);
+
+ /* make a regular index */
+ put_16bits(&tempbuf[0], 2); /* wLongsPerEntry */
+ tempbuf[2] = 0; /* bIndexSubType */
+ tempbuf[3] = AVI_INDEX_OF_CHUNKS; /* bIndexType */
+ put_32bits(&tempbuf[4], chunks_this_index); /* nEntriesInUse */
+ put_32bits(&tempbuf[8], chunkid); /* dwChunkId */
+ put_64bits(&tempbuf[12], currentbase); /* qwBaseOffset */
+
+ /* now fill in the indexes */
+ chunks_this_index = 0;
+ for (chunknum = 0; chunknum < stream->chunks; chunknum++)
+ if (stream->chunk[chunknum].offset >= currentbase && stream->chunk[chunknum].offset < currentend)
+ {
+ put_32bits(&tempbuf[24 + 8 * chunks_this_index + 0], stream->chunk[chunknum].offset + 8 - currentbase);
+ put_32bits(&tempbuf[24 + 8 * chunks_this_index + 4], stream->chunk[chunknum].length - 8);
+ bytes_this_index += stream->chunk[chunknum].length;
+ chunks_this_index++;
+ }
+
+ /* write the offset of this index to the master table */
+ put_64bits(&buffer[24 + 16 * master_entries + 0], file->writeoffs);
+ put_32bits(&buffer[24 + 16 * master_entries + 8], 24 + 8 * chunks_this_index + 8);
+ if (stream->type == STREAMTYPE_VIDS)
+ put_32bits(&buffer[24 + 16 * master_entries + 12], chunks_this_index);
+ else if (stream->type == STREAMTYPE_AUDS)
+ put_32bits(&buffer[24 + 16 * master_entries + 12], bytes_this_index / ((stream->samplebits / 8) * stream->channels));
+ master_entries++;
+
+ /* write the index */
+ avierr = chunk_write(file, indexchunkid, tempbuf, 24 + 8 * chunks_this_index);
+ free(tempbuf);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+ }
+ }
+
+ /* build up the master index */
+ if (master_entries != 0)
+ {
+ put_16bits(&buffer[0], 4); /* wLongsPerEntry */
+ buffer[2] = 0; /* bIndexSubType */
+ buffer[3] = AVI_INDEX_OF_INDEXES; /* bIndexType */
+ put_32bits(&buffer[4], master_entries); /* nEntriesInUse */
+ put_32bits(&buffer[8], chunkid); /* dwChunkId */
+ }
+
+ /* (over)write the chunk */
+ return chunk_overwrite(file, (master_entries == 0) ? CHUNKTYPE_JUNK : CHUNKTYPE_INDX, buffer, sizeof(buffer), &stream->saved_indx_offset, initial_write);
+}
+
+
+/*-------------------------------------------------
+ write_idx1_chunk - write the idx1 chunk
+-------------------------------------------------*/
+
+static avi_error write_idx1_chunk(avi_file *file)
+{
+ UINT32 tempbuflength = compute_idx1_size(file) - 8;
+ UINT32 curchunk[2] = { 0 };
+ UINT32 curoffset;
+ avi_error avierr;
+ UINT8 *tempbuf;
+
+ /* allocate a temporary buffer */
+ tempbuf = malloc(tempbuflength);
+ if (tempbuf == NULL)
+ return AVIERR_NO_MEMORY;
+
+ /* fill it in */
+ for (curoffset = 0; curoffset < tempbuflength; curoffset += 16)
+ {
+ UINT64 minoffset = ~(UINT64)0;
+ int strnum, minstr = 0;
+
+ /* determine which stream has the next chunk */
+ for (strnum = 0; strnum < file->streams; strnum++)
+ if (curchunk[strnum] < file->stream[strnum].chunks && file->stream[strnum].chunk[curchunk[strnum]].offset < minoffset)
+ {
+ minoffset = file->stream[strnum].chunk[curchunk[strnum]].offset;
+ minstr = strnum;
+ }
+
+ /* make an entry for this index */
+ put_32bits(&tempbuf[curoffset + 0], get_chunkid_for_stream(file, &file->stream[minstr]));
+ put_32bits(&tempbuf[curoffset + 4], 0x0010 /* AVIIF_KEYFRAME */);
+ put_32bits(&tempbuf[curoffset + 8], minoffset - (file->saved_movi_offset + 8));
+ put_32bits(&tempbuf[curoffset + 12], file->stream[minstr].chunk[curchunk[minstr]].length - 8);
+
+ /* advance the chunk counter for this stream */
+ curchunk[minstr]++;
+ }
+
+ /* write the chunk */
+ avierr = chunk_write(file, CHUNKTYPE_IDX1, tempbuf, tempbuflength);
+ free(tempbuf);
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ soundbuf_initialize - initialize the sound
+ buffering system
+-------------------------------------------------*/
+
+static avi_error soundbuf_initialize(avi_file *file)
+{
+ avi_stream *audio = get_audio_stream(file, 0, NULL);
+ avi_stream *video = get_video_stream(file);
+
+ /* we require a video stream */
+ if (video == NULL)
+ return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+
+ /* skip if no audio stream */
+ if (audio == NULL)
+ return AVIERR_NONE;
+
+ /* determine the number of samples we want in our buffer; 2 seconds should be enough */
+ file->soundbuf_samples = file->info.audio_samplerate * SOUND_BUFFER_MSEC / 1000;
+
+ /* allocate a buffer */
+ file->soundbuf = malloc(file->soundbuf_samples * file->info.audio_channels * sizeof(file->soundbuf[0]));
+ if (file->soundbuf == NULL)
+ return AVIERR_NO_MEMORY;
+ memset(file->soundbuf, 0, file->soundbuf_samples * file->info.audio_channels * sizeof(file->soundbuf[0]));
+
+ /* determine the number of frames to be ahead (0.75secs) */
+ file->soundbuf_frames = ((UINT64)video->rate * 75) / ((UINT64)video->scale * 100) + 1;
+ return AVIERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ soundbuf_write_chunk - write the initial
+ chunk data
+-------------------------------------------------*/
+
+static avi_error soundbuf_write_chunk(avi_file *file, UINT32 framenum)
+{
+ avi_stream *stream = get_audio_stream(file, 0, NULL);
+ avi_error avierr;
+ UINT32 chunknum;
+ UINT32 length;
+
+ /* skip if no audio stream */
+ if (stream == NULL)
+ return AVIERR_NONE;
+
+ /* determine the length of this chunk */
+ if (framenum == 0)
+ length = framenum_to_samplenum(file, file->soundbuf_frames);
+ else
+ length = framenum_to_samplenum(file, framenum + 1 + file->soundbuf_frames) - framenum_to_samplenum(file, framenum + file->soundbuf_frames);
+ length *= stream->channels * sizeof(INT16);
+
+ /* set the info for this new chunk */
+ chunknum = stream->chunks;
+ avierr = set_stream_chunk_info(stream, chunknum, file->writeoffs, length + 8);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* then do the initial write */
+ return chunk_overwrite(file, get_chunkid_for_stream(file, stream), file->soundbuf, length, &stream->chunk[chunknum].offset, TRUE);
+}
+
+
+/*-------------------------------------------------
+ soundbuf_flush - flush data from the sound
+ buffers
+-------------------------------------------------*/
+
+static avi_error soundbuf_flush(avi_file *file, int only_flush_full)
+{
+ avi_stream *stream = get_audio_stream(file, 0, NULL);
+ INT32 channelsamples = file->soundbuf_samples;
+ INT32 processedsamples = 0;
+ UINT32 bytes_per_sample;
+ UINT32 finalchunks;
+ avi_error avierr;
+ UINT32 chunknum;
+ UINT32 chunkid;
+ int channel;
+
+ /* skip if no stream */
+ if (stream == NULL)
+ return AVIERR_NONE;
+
+ /* get the chunk ID for this stream */
+ chunkid = get_chunkid_for_stream(file, stream);
+ bytes_per_sample = stream->channels * sizeof(INT16);
+ finalchunks = stream->chunks;
+
+ /* find out how many samples we've accumulated */
+ for (channel = 0; channel < stream->channels; channel++)
+ channelsamples = MIN(channelsamples, file->soundbuf_chansamples[channel]);
+
+ /* loop over pending sound chunks */
+ for (chunknum = file->soundbuf_chunks; chunknum < stream->chunks; chunknum++)
+ {
+ avi_chunk_list *chunk = &stream->chunk[chunknum];
+ UINT32 chunksamples = (chunk->length - 8) / bytes_per_sample;
+
+ /* stop if we don't have enough to satisfy this chunk */
+ if (only_flush_full && channelsamples < chunksamples)
+ break;
+
+ /* if we don't have all the samples we need, pad with 0's */
+ if (channelsamples > 0 && channelsamples < chunksamples)
+ {
+ if (processedsamples + chunksamples > file->soundbuf_samples)
+ return AVIERR_EXCEEDED_SOUND_BUFFER;
+ memset(&file->soundbuf[(processedsamples + channelsamples) * stream->channels], 0, (chunksamples - channelsamples) * bytes_per_sample);
+ }
+
+ /* if we're completely out of samples, clear the buffer entirely and use the end */
+ else if (channelsamples <= 0)
+ {
+ processedsamples = file->soundbuf_samples - chunksamples;
+ memset(&file->soundbuf[processedsamples * stream->channels], 0, chunksamples * bytes_per_sample);
+ chunkid = CHUNKTYPE_JUNK;
+ finalchunks--;
+ }
+
+ /* copy the sample data in */
+ avierr = chunk_overwrite(file, chunkid, &file->soundbuf[processedsamples * stream->channels], chunk->length - 8, &chunk->offset, FALSE);
+ if (avierr != AVIERR_NONE)
+ return avierr;
+
+ /* add up the samples */
+ if (channelsamples > 0)
+ file->info.audio_numsamples = stream->samples += channelsamples;
+
+ /* advance past those */
+ processedsamples += chunksamples;
+ channelsamples -= chunksamples;
+ channelsamples = MAX(0, channelsamples);
+ }
+
+ /* if we have a non-zero offset, shift everything down */
+ if (processedsamples > 0)
+ {
+ /* first account for the samples we processed */
+ memmove(&file->soundbuf[0], &file->soundbuf[processedsamples * stream->channels], (file->soundbuf_samples - processedsamples) * bytes_per_sample);
+ for (channel = 0; channel < stream->channels; channel++)
+ file->soundbuf_chansamples[channel] -= processedsamples;
+ }
+
+ /* update the final chunk count */
+ if (!only_flush_full)
+ stream->chunks = finalchunks;
+
+ /* account for flushed chunks */
+ file->soundbuf_chunks = chunknum;
+ return AVIERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ yuv_decompress_to_yuy16 - decompress a YUV
+ encoded frame to a YUY16 bitmap
+-------------------------------------------------*/
+
+static avi_error yuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_t *bitmap)
+{
+ const UINT16 *dataend = (const UINT16 *)(data + numbytes);
+ int x, y;
+
+ /* compressed video */
+ for (y = 0; y < stream->height; y++)
+ {
+ const UINT16 *source = (const UINT16 *)data + y * stream->width;
+ UINT16 *dest = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+
+ /* switch off the compression */
+ switch (stream->format)
+ {
+ case FORMAT_UYVY:
+ for (x = 0; x < stream->width && source < dataend; x++)
+ *dest++ = *source++;
+ break;
+
+ case FORMAT_VYUY:
+ case FORMAT_YUY2:
+ for (x = 0; x < stream->width && source < dataend; x++)
+ {
+ UINT16 pix = *source++;
+ *dest++ = (pix >> 8) | (pix << 8);
+ }
+ break;
+ }
+ }
+
+ return AVIERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ yuy16_compress_to_yuy - "compress" a YUY16
+ bitmap to a YUV encoded frame
+-------------------------------------------------*/
+
+static avi_error yuy16_compress_to_yuy(avi_stream *stream, const bitmap_t *bitmap, UINT8 *data, UINT32 numbytes)
+{
+ const UINT16 *dataend = (const UINT16 *)(data + numbytes);
+ int x, y;
+
+ /* compressed video */
+ for (y = 0; y < stream->height; y++)
+ {
+ const UINT16 *source = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+ UINT16 *dest = (UINT16 *)data + y * stream->width;
+
+ /* switch off the compression */
+ switch (stream->format)
+ {
+ case FORMAT_UYVY:
+ for (x = 0; x < stream->width && dest < dataend; x++)
+ *dest++ = *source++;
+ break;
+
+ case FORMAT_VYUY:
+ case FORMAT_YUY2:
+ for (x = 0; x < stream->width && source < dataend; x++)
+ {
+ UINT16 pix = *source++;
+ *dest++ = (pix >> 8) | (pix << 8);
+ }
+ break;
+ }
+ }
+
+ return AVIERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ huffyuv_extract_tables - extract HuffYUV
+ tables
+-------------------------------------------------*/
+
+static avi_error huffyuv_extract_tables(avi_stream *stream, const UINT8 *chunkdata, UINT32 size)
+{
+ const UINT8 *chunkend = chunkdata + size;
+ avi_error avierr = AVIERR_NONE;
+ int tabnum;
+
+ /* allocate memory for the data */
+ stream->huffyuv = malloc(sizeof(*stream->huffyuv));
+ if (stream->huffyuv == NULL)
+ {
+ avierr = AVIERR_NO_MEMORY;
+ goto error;
+ }
+
+ /* extract predictor information */
+ if (&chunkdata[40] >= chunkend)
+ return AVIERR_INVALID_DATA;
+ stream->huffyuv->predictor = chunkdata[40];
+
+ /* make sure it's the left predictor */
+ if ((stream->huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) != HUFFYUV_PREDICT_LEFT)
+ return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+
+ /* make sure it's 16bpp YUV data */
+ if (chunkdata[41] != 16)
+ return AVIERR_UNSUPPORTED_VIDEO_FORMAT;
+ chunkdata += 44;
+
+ /* loop over tables */
+ for (tabnum = 0; tabnum < 3; tabnum++)
+ {
+ huffyuv_table *table = &stream->huffyuv->table[tabnum];
+ UINT32 curbits, bitadd;
+ UINT16 bitsat16 = 0;
+ int offset = 0, bits;
+
+ /* loop until we populate the whole table */
+ while (offset < 256)
+ {
+ int data, shift, count, i;
+
+ /* extract the next run */
+ if (chunkdata >= chunkend)
+ {
+ avierr = AVIERR_INVALID_DATA;
+ goto error;
+ }
+ data = *chunkdata++;
+ shift = data & 0x1f;
+ count = data >> 5;
+
+ /* zero count means next whole byte is a count */
+ if (count == 0)
+ {
+ if (chunkdata >= chunkend)
+ {
+ avierr = AVIERR_INVALID_DATA;
+ goto error;
+ }
+ count = *chunkdata++;
+ }
+ for (i = 0; i < count; i++)
+ table->shift[offset++] = shift;
+ }
+
+ /* now determine bit patterns and masks */
+ curbits = 0;
+ for (bits = 31; bits >= 0; bits--)
+ {
+ bitadd = 1 << (32 - bits);
+
+ /* make sure we've cleared out all the bits below */
+ if ((curbits & (bitadd - 1)) != 0)
+ {
+ avierr = AVIERR_INVALID_DATA;
+ goto error;
+ }
+
+ /* find all entries with this shift count and assign them */
+ for (offset = 0; offset < 256; offset++)
+ if (table->shift[offset] == bits)
+ {
+ table->bits[offset] = curbits;
+ table->mask[offset] = ~(bitadd - 1);
+ curbits += bitadd;
+ }
+
+ /* remember the bit pattern when we complete all the 17-bit codes */
+ if (bits == 17)
+ bitsat16 = curbits >> 16;
+ }
+
+ /* allocate the number of extra lookup tables we need */
+ if (bitsat16 > 0)
+ {
+ table->extralookup = malloc(bitsat16 * 65536 * sizeof(table->extralookup[0]));
+ if (table->extralookup == NULL)
+ {
+ avierr = AVIERR_NO_MEMORY;
+ goto error;
+ }
+ for (offset = 0; offset < bitsat16; offset++)
+ table->baselookup[offset] = (offset << 8) | 0;
+ }
+
+ /* then create lookup tables */
+ for (offset = 0; offset < 256; offset++)
+ if (table->shift[offset] > 16)
+ {
+ UINT16 *tablebase = table->extralookup + (table->bits[offset] >> 16) * 65536;
+ UINT32 start = table->bits[offset] & 0xffff;
+ UINT32 end = start + ((1 << (32 - table->shift[offset])) - 1);
+ while (start <= end)
+ tablebase[start++] = (offset << 8) | (table->shift[offset] - 16);
+ }
+ else if (table->shift[offset] > 0)
+ {
+ UINT32 start = table->bits[offset] >> 16;
+ UINT32 end = start + ((1 << (16 - table->shift[offset])) - 1);
+ while (start <= end)
+ table->baselookup[start++] = (offset << 8) | table->shift[offset];
+ }
+ }
+
+error:
+ if (avierr != AVIERR_NONE && stream->huffyuv != NULL)
+ {
+ free(stream->huffyuv);
+ stream->huffyuv = NULL;
+ }
+ return avierr;
+}
+
+
+/*-------------------------------------------------
+ huffyuv_decompress_to_yuy16 - decompress a
+ HuffYUV-encoded frame to a YUY16 bitmap
+-------------------------------------------------*/
+
+static avi_error huffyuv_decompress_to_yuy16(avi_stream *stream, const UINT8 *data, UINT32 numbytes, bitmap_t *bitmap)
+{
+ huffyuv_data *huffyuv = stream->huffyuv;
+ int prevlines = (stream->height > 288) ? 2 : 1;
+ UINT8 lastprevy = 0, lastprevcb = 0, lastprevcr = 0;
+ UINT8 lasty = 0, lastcb = 0, lastcr = 0;
+ UINT8 bitsinbuffer = 0;
+ UINT32 bitbuffer = 0;
+ UINT32 dataoffs = 0;
+ int x, y;
+
+ /* compressed video */
+ for (y = 0; y < stream->height; y++)
+ {
+ UINT16 *dest = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+
+ /* handle the first four bytes independently */
+ x = 0;
+ if (y == 0)
+ {
+ /* first DWORD is stored as YUY2 */
+ lasty = data[dataoffs++];
+ lastcb = data[dataoffs++];
+ *dest++ = (lasty << 8) | lastcb;
+ lasty = data[dataoffs++];
+ lastcr = data[dataoffs++];
+ *dest++ = (lasty << 8) | lastcr;
+ x = 2;
+ }
+
+ /* loop over pixels */
+ for ( ; x < stream->width; x++)
+ {
+ huffyuv_table *ytable = &huffyuv->table[0];
+ huffyuv_table *ctable = &huffyuv->table[1 + (x & 1)];
+ UINT16 pixel, huffdata;
+ int shift;
+
+ /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
+ while (bitsinbuffer <= 24 && dataoffs < numbytes)
+ {
+ bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
+ bitsinbuffer += 8;
+ }
+
+ /* look up the Y component */
+ huffdata = ytable->baselookup[bitbuffer >> 16];
+ shift = huffdata & 0xff;
+ if (shift == 0)
+ {
+ bitsinbuffer -= 16;
+ bitbuffer <<= 16;
+
+ /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
+ while (bitsinbuffer <= 24 && dataoffs < numbytes)
+ {
+ bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
+ bitsinbuffer += 8;
+ }
+
+ huffdata = ytable->extralookup[(huffdata >> 8) * 65536 + (bitbuffer >> 16)];
+ shift = huffdata & 0xff;
+ }
+ bitsinbuffer -= shift;
+ bitbuffer <<= shift;
+ pixel = huffdata & 0xff00;
+
+ /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
+ while (bitsinbuffer <= 24 && dataoffs < numbytes)
+ {
+ bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
+ bitsinbuffer += 8;
+ }
+
+ /* look up the Cb/Cr component */
+ huffdata = ctable->baselookup[bitbuffer >> 16];
+ shift = huffdata & 0xff;
+ if (shift == 0)
+ {
+ bitsinbuffer -= 16;
+ bitbuffer <<= 16;
+
+ /* fill up the buffer; they store little-endian DWORDs, so we XOR with 3 */
+ while (bitsinbuffer <= 24 && dataoffs < numbytes)
+ {
+ bitbuffer |= data[dataoffs++ ^ 3] << (24 - bitsinbuffer);
+ bitsinbuffer += 8;
+ }
+
+ huffdata = ctable->extralookup[(huffdata >> 8) * 65536 + (bitbuffer >> 16)];
+ shift = huffdata & 0xff;
+ }
+ bitsinbuffer -= shift;
+ bitbuffer <<= shift;
+ *dest++ = pixel | (huffdata >> 8);
+ }
+ }
+
+ /* apply deltas */
+ lasty = lastcb = lastcr = 0;
+ lastprevy = lastprevcb = lastprevcr = 0;
+ for (y = 0; y < stream->height; y++)
+ {
+ UINT16 *dest = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+ UINT16 *prevrow = dest - prevlines * bitmap->rowpixels;
+
+ /* left predict or gradient predict */
+ if ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_LEFT ||
+ ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_GRADIENT))
+ {
+ /* first do left deltas */
+ for (x = 0; x < stream->width; x += 2)
+ {
+ UINT16 pixel0 = dest[x + 0];
+ UINT16 pixel1 = dest[x + 1];
+
+ lasty += pixel0 >> 8;
+ lastcb += pixel0;
+ dest[x + 0] = (lasty << 8) | lastcb;
+
+ lasty += pixel1 >> 8;
+ lastcr += pixel1;
+ dest[x + 1] = (lasty << 8) | lastcr;
+ }
+
+ /* for gradient, we then add in the previous row */
+ if ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_GRADIENT && y >= prevlines)
+ for (x = 0; x < stream->width; x++)
+ {
+ UINT16 curpix = dest[x];
+ UINT16 prevpix = prevrow[x];
+ UINT8 ysum = (curpix >> 8) + (prevpix >> 8);
+ UINT8 csum = curpix + prevpix;
+ dest[x] = (ysum << 8) | csum;
+ }
+ }
+
+ /* median predict on rows > 0 */
+ else if ((huffyuv->predictor & ~HUFFYUV_PREDICT_DECORR) == HUFFYUV_PREDICT_MEDIAN && y >= prevlines)
+ {
+ for (x = 0; x < stream->width; x += 2)
+ {
+ UINT16 prevpixel0 = prevrow[x + 0];
+ UINT16 prevpixel1 = prevrow[x + 1];
+ UINT16 pixel0 = dest[x + 0];
+ UINT16 pixel1 = dest[x + 1];
+ UINT8 a, b, c;
+
+ /* compute previous, above, and (prev + above - above-left) */
+ a = lasty;
+ b = prevpixel0 >> 8;
+ c = lastprevy;
+ lastprevy = b;
+ if (a > b) { UINT8 tmp = a; a = b; b = tmp; }
+ if (a > c) { UINT8 tmp = a; a = c; c = tmp; }
+ if (b > c) { UINT8 tmp = b; b = c; c = tmp; }
+ lasty = (pixel0 >> 8) + b;
+
+ /* compute previous, above, and (prev + above - above-left) */
+ a = lastcb;
+ b = prevpixel0 & 0xff;
+ c = lastprevcb;
+ lastprevcb = b;
+ if (a > b) { UINT8 tmp = a; a = b; b = tmp; }
+ if (a > c) { UINT8 tmp = a; a = c; c = tmp; }
+ if (b > c) { UINT8 tmp = b; b = c; c = tmp; }
+ lastcb = (pixel0 & 0xff) + b;
+ dest[x + 0] = (lasty << 8) | lastcb;
+
+ /* compute previous, above, and (prev + above - above-left) */
+ a = lasty;
+ b = prevpixel1 >> 8;
+ c = lastprevy;
+ lastprevy = b;
+ if (a > b) { UINT8 tmp = a; a = b; b = tmp; }
+ if (a > c) { UINT8 tmp = a; a = c; c = tmp; }
+ if (b > c) { UINT8 tmp = b; b = c; c = tmp; }
+ lasty = (pixel1 >> 8) + b;
+
+ /* compute previous, above, and (prev + above - above-left) */
+ a = lastcr;
+ b = prevpixel1 & 0xff;
+ c = lastprevcr;
+ lastprevcr = b;
+ if (a > b) { UINT8 tmp = a; a = b; b = tmp; }
+ if (a > c) { UINT8 tmp = a; a = c; c = tmp; }
+ if (b > c) { UINT8 tmp = b; b = c; c = tmp; }
+ lastcr = (pixel1 & 0xff) + b;
+ dest[x + 1] = (lasty << 8) | lastcr;
+ }
+ }
+ }
+
+ return AVIERR_NONE;
+}
+
+
+static void u64toa(UINT64 val, char *output)
+{
+ UINT32 lo = (UINT32)(val & 0xffffffff);
+ UINT32 hi = (UINT32)(val >> 32);
+ if (hi != 0)
+ sprintf(output, "%X%08X", hi, lo);
+ else
+ sprintf(output, "%X", lo);
+}
+
+
+/*-------------------------------------------------
+ printf_chunk_recursive - print information
+ about a chunk recursively
+-------------------------------------------------*/
+
+static void printf_chunk_recursive(avi_file *file, avi_chunk *container, int indent)
+{
+ char size[20], offset[20];
+ avi_chunk curchunk;
+ int avierr;
+
+ /* iterate over chunks in this container */
+ for (avierr = get_first_chunk(file, container, &curchunk); avierr == AVIERR_NONE; avierr = get_next_chunk(file, container, &curchunk))
+ {
+ UINT32 chunksize = curchunk.size;
+ int recurse = FALSE;
+
+ u64toa(curchunk.size, size);
+ u64toa(curchunk.offset, offset);
+ printf("%*schunk = %c%c%c%c, size=%s (%s)\n", indent, "",
+ (UINT8)(curchunk.type >> 0),
+ (UINT8)(curchunk.type >> 8),
+ (UINT8)(curchunk.type >> 16),
+ (UINT8)(curchunk.type >> 24),
+ size, offset);
+
+ /* certain chunks are just containers; recurse into them */
+ switch (curchunk.type)
+ {
+ /* basic containers */
+ case CHUNKTYPE_RIFF:
+ case CHUNKTYPE_LIST:
+ printf("%*stype = %c%c%c%c\n", indent, "",
+ (UINT8)(curchunk.listtype >> 0),
+ (UINT8)(curchunk.listtype >> 8),
+ (UINT8)(curchunk.listtype >> 16),
+ (UINT8)(curchunk.listtype >> 24));
+ recurse = TRUE;
+ chunksize = 0;
+ break;
+ }
+
+ /* print data within the chunk */
+ if (chunksize > 0 && curchunk.size < 1024 * 1024)
+ {
+ UINT8 *data = NULL;
+ int i;
+
+ /* read the data for a chunk */
+ avierr = read_chunk_data(file, &curchunk, &data);
+ if (avierr == AVIERR_NONE)
+ {
+ int bytes = MIN(512, chunksize);
+ for (i = 0; i < bytes; i++)
+ {
+ if (i % 16 == 0) printf("%*s ", indent, "");
+ printf("%02X ", data[i]);
+ if (i % 16 == 15) printf("\n");
+ }
+ if (chunksize % 16 != 0) printf("\n");
+ free(data);
+ }
+ }
+
+ /* if we're recursing, dive down */
+ if (recurse)
+ printf_chunk_recursive(file, &curchunk, indent + 4);
+ }
+
+ /* if we didn't get a legitimate error, indicate that */
+ if (avierr != AVIERR_END)
+ printf("[chunk error %d]\n", avierr);
+}
diff --git a/src/lib/util/aviio.h b/src/lib/util/aviio.h
new file mode 100644
index 00000000000..41f9eba826d
--- /dev/null
+++ b/src/lib/util/aviio.h
@@ -0,0 +1,123 @@
+/***************************************************************************
+
+ aviio.h
+
+ AVI movie format parsing helpers.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __AVIIO_H__
+
+#include "osdcore.h"
+#include "bitmap.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+enum _avi_error
+{
+ AVIERR_NONE = 0,
+ AVIERR_END,
+ AVIERR_INVALID_DATA,
+ AVIERR_NO_MEMORY,
+ AVIERR_READ_ERROR,
+ AVIERR_WRITE_ERROR,
+ AVIERR_STACK_TOO_DEEP,
+ AVIERR_UNSUPPORTED_FEATURE,
+ AVIERR_CANT_OPEN_FILE,
+ AVIERR_INCOMPATIBLE_AUDIO_STREAMS,
+ AVIERR_INVALID_SAMPLERATE,
+ AVIERR_INVALID_STREAM,
+ AVIERR_INVALID_FRAME,
+ AVIERR_INVALID_BITMAP,
+ AVIERR_UNSUPPORTED_VIDEO_FORMAT,
+ AVIERR_UNSUPPORTED_AUDIO_FORMAT,
+ AVIERR_EXCEEDED_SOUND_BUFFER
+};
+typedef enum _avi_error avi_error;
+
+
+enum _avi_datatype
+{
+ AVIDATA_VIDEO,
+ AVIDATA_AUDIO_CHAN0,
+ AVIDATA_AUDIO_CHAN1,
+ AVIDATA_AUDIO_CHAN2,
+ AVIDATA_AUDIO_CHAN3,
+ AVIDATA_AUDIO_CHAN4,
+ AVIDATA_AUDIO_CHAN5,
+ AVIDATA_AUDIO_CHAN6,
+ AVIDATA_AUDIO_CHAN7
+};
+typedef enum _avi_datatype avi_datatype;
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define AVI_FOURCC(a,b,c,d) ((a) | ((b) << 8) | ((c) << 16) | ((d) << 24))
+
+#define FORMAT_UYVY AVI_FOURCC('U','Y','V','Y')
+#define FORMAT_VYUY AVI_FOURCC('V','Y','U','Y')
+#define FORMAT_YUY2 AVI_FOURCC('Y','U','Y','2')
+#define FORMAT_HFYU AVI_FOURCC('H','F','Y','U')
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _avi_file avi_file;
+
+
+typedef struct _avi_movie_info avi_movie_info;
+struct _avi_movie_info
+{
+ UINT32 video_format; /* format of video data */
+ UINT32 video_timescale; /* timescale for video data */
+ UINT32 video_sampletime; /* duration of a single video sample (frame) */
+ UINT32 video_numsamples; /* total number of video samples */
+ UINT32 video_width; /* width of the video */
+ UINT32 video_height; /* height of the video */
+ UINT32 video_depth; /* depth of the video */
+
+ UINT32 audio_format; /* format of audio data */
+ UINT32 audio_timescale; /* timescale for audio data */
+ UINT32 audio_sampletime; /* duration of a single audio sample */
+ UINT32 audio_numsamples; /* total number of audio samples */
+ UINT32 audio_channels; /* number of audio channels */
+ UINT32 audio_samplebits; /* number of bits per channel */
+ UINT32 audio_samplerate; /* sample rate of audio */
+};
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+avi_error avi_open(const char *filename, avi_file **file);
+avi_error avi_create(const char *filename, const avi_movie_info *info, avi_file **file);
+avi_error avi_close(avi_file *file);
+
+void avi_printf_chunks(avi_file *file);
+const char *avi_error_string(avi_error err);
+
+const avi_movie_info *avi_get_movie_info(avi_file *file);
+UINT32 avi_first_sample_in_frame(avi_file *file, UINT32 framenum);
+
+avi_error avi_read_video_frame_yuy16(avi_file *file, UINT32 framenum, bitmap_t *bitmap);
+avi_error avi_read_sound_samples(avi_file *file, int channel, UINT32 firstsample, UINT32 numsamples, INT16 *output);
+
+avi_error avi_append_video_frame_yuy16(avi_file *file, const bitmap_t *bitmap);
+avi_error avi_append_sound_samples(avi_file *file, int channel, const INT16 *samples, UINT32 numsamples);
+
+#endif
diff --git a/src/lib/util/bitmap.c b/src/lib/util/bitmap.c
new file mode 100644
index 00000000000..a7e5d5e46f8
--- /dev/null
+++ b/src/lib/util/bitmap.c
@@ -0,0 +1,263 @@
+/***************************************************************************
+
+ bitmap.c
+
+ Core bitmap routines.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "bitmap.h"
+
+
+
+/***************************************************************************
+ BITMAP ALLOCATION/CONFIGURATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ bitmap_alloc -- allocate memory for a new
+ bitmap of the given format
+-------------------------------------------------*/
+
+bitmap_t *bitmap_alloc(int width, int height, bitmap_format format)
+{
+ return bitmap_alloc_slop(width, height, 0, 0, format);
+}
+
+
+/*-------------------------------------------------
+ bitmap_alloc_slop -- allocate a new bitmap with
+ additional slop on the borders
+-------------------------------------------------*/
+
+bitmap_t *bitmap_alloc_slop(int width, int height, int xslop, int yslop, bitmap_format format)
+{
+ int bpp = bitmap_format_to_bpp(format);
+ size_t allocbytes;
+ bitmap_t *bitmap;
+ int rowpixels;
+
+ /* fail if invalid format */
+ if (bpp == 0)
+ return NULL;
+
+ /* allocate the bitmap itself */
+ bitmap = malloc(sizeof(*bitmap));
+ if (bitmap == NULL)
+ return NULL;
+ memset(bitmap, 0, sizeof(*bitmap));
+
+ /* round the width to a multiple of 8 and add some padding */
+ rowpixels = (width + 2 * xslop + 7) & ~7;
+
+ /* allocate memory for the bitmap itself */
+ allocbytes = rowpixels * (height + 2 * yslop) * bpp / 8;
+ bitmap->alloc = malloc(allocbytes);
+ if (bitmap->alloc == NULL)
+ {
+ free(bitmap);
+ return NULL;
+ }
+
+ /* clear to 0 by default */
+ memset(bitmap->alloc, 0, allocbytes);
+
+ /* fill in the data */
+ bitmap->format = format;
+ bitmap->width = width;
+ bitmap->height = height;
+ bitmap->bpp = bpp;
+ bitmap->rowpixels = rowpixels;
+ bitmap->base = (UINT8 *)bitmap->alloc + (rowpixels * yslop + xslop) * (bpp / 8);
+
+ return bitmap;
+}
+
+
+/*-------------------------------------------------
+ bitmap_wrap -- wrap an existing memory buffer
+ as a bitmap
+-------------------------------------------------*/
+
+bitmap_t *bitmap_wrap(void *base, int width, int height, int rowpixels, bitmap_format format)
+{
+ int bpp = bitmap_format_to_bpp(format);
+ bitmap_t *bitmap;
+
+ /* fail if invalid format */
+ if (bpp == 0)
+ return NULL;
+
+ /* allocate memory */
+ bitmap = malloc(sizeof(*bitmap));
+ if (bitmap == NULL)
+ return NULL;
+ memset(bitmap, 0, sizeof(*bitmap));
+
+ /* fill in the data */
+ bitmap->format = format;
+ bitmap->width = width;
+ bitmap->height = height;
+ bitmap->bpp = bpp;
+ bitmap->rowpixels = rowpixels;
+ bitmap->base = base;
+
+ return bitmap;
+}
+
+
+/*-------------------------------------------------
+ bitmap_set_palette -- associate a palette with
+ a bitmap
+-------------------------------------------------*/
+
+void bitmap_set_palette(bitmap_t *bitmap, palette_t *palette)
+{
+ /* first dereference any existing palette */
+ if (bitmap->palette != NULL)
+ {
+ palette_deref(bitmap->palette);
+ bitmap->palette = NULL;
+ }
+
+ /* then reference any new palette */
+ if (palette != NULL)
+ {
+ palette_ref(palette);
+ bitmap->palette = palette;
+ }
+}
+
+
+/*-------------------------------------------------
+ bitmap_free -- release memory allocated for
+ a bitmap
+-------------------------------------------------*/
+
+void bitmap_free(bitmap_t *bitmap)
+{
+ /* dereference the palette */
+ if (bitmap->palette != NULL)
+ palette_deref(bitmap->palette);
+
+ /* free any allocated memory */
+ if (bitmap->alloc != NULL)
+ free(bitmap->alloc);
+
+ /* free the bitmap */
+ free(bitmap);
+}
+
+
+
+/***************************************************************************
+ BITMAP DRAWING
+***************************************************************************/
+
+/*-------------------------------------------------
+ bitmap_fill -- fill a bitmap with a solid
+ color
+-------------------------------------------------*/
+
+void bitmap_fill(bitmap_t *dest, const rectangle *cliprect, UINT32 color)
+{
+ rectangle fill;
+ int x, y;
+
+ /* default to the whole bitmap */
+ fill.min_x = fill.min_y = 0;
+ fill.max_x = dest->width - 1;
+ fill.max_y = dest->height - 1;
+
+ /* if we have a cliprect, intersect with that */
+ if (cliprect != NULL)
+ sect_rect(&fill, cliprect);
+
+ /* early out if nothing to do */
+ if (fill.min_x > fill.max_x || fill.min_y > fill.max_y)
+ return;
+
+ /* based on the bpp go from there */
+ switch (dest->bpp)
+ {
+ case 8:
+ /* 8bpp always uses memset */
+ for (y = fill.min_y; y <= fill.max_y; y++)
+ memset(BITMAP_ADDR8(dest, y, fill.min_x), (UINT8)color, fill.max_x + 1 - fill.min_x);
+ break;
+
+ case 16:
+ /* 16bpp can use memset if the bytes are equal */
+ if ((UINT8)(color >> 8) == (UINT8)color)
+ {
+ for (y = fill.min_y; y <= fill.max_y; y++)
+ memset(BITMAP_ADDR16(dest, y, fill.min_x), (UINT8)color, (fill.max_x + 1 - fill.min_x) * 2);
+ }
+ else
+ {
+ for (y = fill.min_y; y <= fill.max_y; y++)
+ {
+ UINT16 *destrow = BITMAP_ADDR16(dest, y, 0);
+ for (x = fill.min_x; x <= fill.max_x; x++)
+ destrow[x] = (UINT16)color;
+ }
+ }
+ break;
+
+ case 32:
+ /* 32bpp can use memset if the bytes are equal */
+ if ((UINT8)(color >> 8) == (UINT8)color && (UINT16)(color >> 16) == (UINT16)color)
+ {
+ for (y = fill.min_y; y <= fill.max_y; y++)
+ memset(BITMAP_ADDR32(dest, y, fill.min_x), (UINT8)color, (fill.max_x + 1 - fill.min_x) * 4);
+ }
+ else
+ {
+ for (y = fill.min_y; y <= fill.max_y; y++)
+ {
+ UINT32 *destrow = BITMAP_ADDR32(dest, y, 0);
+ for (x = fill.min_x; x <= fill.max_x; x++)
+ destrow[x] = (UINT32)color;
+ }
+ }
+ break;
+ }
+}
+
+
+
+/***************************************************************************
+ BITMAP UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ bitmap_format_to_bpp - given a format, return
+ the bpp
+-------------------------------------------------*/
+
+int bitmap_format_to_bpp(bitmap_format format)
+{
+ /* choose a depth for the format */
+ switch (format)
+ {
+ case BITMAP_FORMAT_INDEXED8:
+ return 8;
+
+ case BITMAP_FORMAT_INDEXED16:
+ case BITMAP_FORMAT_RGB15:
+ case BITMAP_FORMAT_YUY16:
+ return 16;
+
+ case BITMAP_FORMAT_INDEXED32:
+ case BITMAP_FORMAT_RGB32:
+ case BITMAP_FORMAT_ARGB32:
+ return 32;
+
+ default:
+ break;
+ }
+ return 0;
+}
diff --git a/src/lib/util/bitmap.h b/src/lib/util/bitmap.h
new file mode 100644
index 00000000000..5b4a5badbd0
--- /dev/null
+++ b/src/lib/util/bitmap.h
@@ -0,0 +1,169 @@
+/***************************************************************************
+
+ bitmap.h
+
+ Core bitmap routines.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __BITMAP_H__
+#define __BITMAP_H__
+
+#include "osdcore.h"
+#include "palette.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* bitmap_format describes the various bitmap formats we use */
+enum _bitmap_format
+{
+ BITMAP_FORMAT_INVALID = 0, /* invalid format */
+ BITMAP_FORMAT_INDEXED8, /* 8bpp indexed */
+ BITMAP_FORMAT_INDEXED16, /* 16bpp indexed */
+ BITMAP_FORMAT_INDEXED32, /* 32bpp indexed */
+ BITMAP_FORMAT_RGB15, /* 15bpp 5-5-5 RGB */
+ BITMAP_FORMAT_RGB32, /* 32bpp 8-8-8 RGB */
+ BITMAP_FORMAT_ARGB32, /* 32bpp 8-8-8-8 ARGB */
+ BITMAP_FORMAT_YUY16, /* 16bpp 8-8 Y/Cb, Y/Cr in sequence */
+ BITMAP_FORMAT_LAST
+};
+typedef enum _bitmap_format bitmap_format;
+
+
+/* rectangles describe a bitmap portion */
+typedef struct _rectangle rectangle;
+struct _rectangle
+{
+ int min_x; /* minimum X, or left coordinate */
+ int max_x; /* maximum X, or right coordinate (inclusive) */
+ int min_y; /* minimum Y, or top coordinate */
+ int max_y; /* maximum Y, or bottom coordinate (inclusive) */
+};
+
+
+/* bitmaps describe a rectangular array of pixels */
+typedef struct _bitmap_t bitmap_t;
+struct _bitmap_t
+{
+ void * alloc; /* pointer to allocated pixel memory */
+ void * base; /* pointer to pixel (0,0) (adjusted for padding) */
+ int rowpixels; /* pixels per row (including padding) */
+ int width; /* width of the bitmap */
+ int height; /* height of the bitmap */
+ bitmap_format format; /* format of the bitmap */
+ int bpp; /* bits per pixel */
+ palette_t * palette; /* optional palette */
+};
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* Macros for accessing bitmap pixels */
+#define BITMAP_ADDR(bitmap, type, y, x) \
+ ((type *)(bitmap)->base + (y) * (bitmap)->rowpixels + (x))
+
+#define BITMAP_ADDR8(bitmap, y, x) BITMAP_ADDR(bitmap, UINT8, y, x)
+#define BITMAP_ADDR16(bitmap, y, x) BITMAP_ADDR(bitmap, UINT16, y, x)
+#define BITMAP_ADDR32(bitmap, y, x) BITMAP_ADDR(bitmap, UINT32, y, x)
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- bitmap allocation ----- */
+
+/* allocate a new bitmap of the given dimensions and format */
+bitmap_t *bitmap_alloc(int width, int height, bitmap_format format);
+
+/* allocate a new bitmap with additional slop on the borders */
+bitmap_t *bitmap_alloc_slop(int width, int height, int xslop, int yslop, bitmap_format format);
+
+/* wrap a bitmap object around an existing array of data */
+bitmap_t *bitmap_wrap(void *base, int width, int height, int rowpixels, bitmap_format format);
+
+/* associate a palette with a bitmap */
+void bitmap_set_palette(bitmap_t *bitmap, palette_t *palette);
+
+/* free allocated data for a bitmap */
+void bitmap_free(bitmap_t *bitmap);
+
+
+
+/* ----- bitmap drawing ----- */
+
+/* fill a bitmap with a single color, clipping to the given rectangle */
+void bitmap_fill(bitmap_t *dest, const rectangle *clip, rgb_t color);
+
+
+
+/* ----- bitmap utilities ----- */
+
+/* return the number of bits per pixel for a given bitmap format */
+int bitmap_format_to_bpp(bitmap_format format);
+
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ sect_rect - compute the intersection of two
+ rectangles
+-------------------------------------------------*/
+
+INLINE void sect_rect(rectangle *dst, const rectangle *src)
+{
+ if (src->min_x > dst->min_x) dst->min_x = src->min_x;
+ if (src->max_x < dst->max_x) dst->max_x = src->max_x;
+ if (src->min_y > dst->min_y) dst->min_y = src->min_y;
+ if (src->max_y < dst->max_y) dst->max_y = src->max_y;
+}
+
+
+/*-------------------------------------------------
+ union_rect - compute the union of two
+ rectangles
+-------------------------------------------------*/
+
+INLINE void union_rect(rectangle *dst, const rectangle *src)
+{
+ if (src->min_x < dst->min_x) dst->min_x = src->min_x;
+ if (src->max_x > dst->max_x) dst->max_x = src->max_x;
+ if (src->min_y < dst->min_y) dst->min_y = src->min_y;
+ if (src->max_y > dst->max_y) dst->max_y = src->max_y;
+}
+
+
+/*-------------------------------------------------
+ plot_box - draw a filled rectangle into a
+ bitmap of arbitrary depth
+-------------------------------------------------*/
+
+INLINE void plot_box(bitmap_t *bitmap, int x, int y, int width, int height, UINT32 color)
+{
+ rectangle clip;
+ clip.min_x = x;
+ clip.min_y = y;
+ clip.max_x = x + width - 1;
+ clip.max_y = y + height - 1;
+ bitmap_fill(bitmap, &clip, color);
+}
+
+
+#endif /* __BITMAP_H__ */
diff --git a/src/lib/util/cdrom.c b/src/lib/util/cdrom.c
new file mode 100644
index 00000000000..82287ad30eb
--- /dev/null
+++ b/src/lib/util/cdrom.c
@@ -0,0 +1,617 @@
+/***************************************************************************
+
+ Generic MAME CD-ROM utilties - build IDE and SCSI CD-ROMs on top of this
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ IMPORTANT:
+ "physical" block addresses are the actual addresses on the emulated CD.
+ "chd" block addresses are the block addresses in the CHD file.
+ Because we pad each track to a hunk boundry, these addressing
+ schemes will differ after track 1!
+
+***************************************************************************/
+
+#include "cdrom.h"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define VERBOSE (0)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct _cdrom_file
+{
+ chd_file * chd; /* CHD file */
+ cdrom_toc cdtoc; /* TOC for the CD */
+ UINT32 hunksectors; /* sectors per hunk */
+ UINT32 cachehunk; /* which hunk is cached */
+ UINT8 * cache; /* cache of the current hunk */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static chd_error read_sector_into_cache(cdrom_file *file, UINT32 lbasector, UINT32 *sectoroffs, UINT32 *tracknum);
+static chd_error parse_metadata(chd_file *chd, cdrom_toc *toc);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ physical_to_chd_lba - find the CHD LBA
+ and the track number
+-------------------------------------------------*/
+
+INLINE UINT32 physical_to_chd_lba(cdrom_file *file, UINT32 physlba, UINT32 *tracknum)
+{
+ UINT32 chdlba;
+ int track;
+
+ /* loop until our current LBA is less than the start LBA of the next track */
+ for (track = 0; track < file->cdtoc.numtrks; track++)
+ if (physlba < file->cdtoc.tracks[track + 1].physframeofs)
+ {
+ chdlba = physlba - file->cdtoc.tracks[track].physframeofs + file->cdtoc.tracks[track].chdframeofs;
+ if (tracknum != NULL)
+ *tracknum = track;
+ return chdlba;
+ }
+
+ return physlba;
+}
+
+
+
+/***************************************************************************
+ BASE FUNCTIONALITY
+***************************************************************************/
+
+/*-------------------------------------------------
+ cdrom_open - "open" a CD-ROM file from an
+ already-opened CHD file
+-------------------------------------------------*/
+
+cdrom_file *cdrom_open(chd_file *chd)
+{
+ const chd_header *header = chd_get_header(chd);
+ int i;
+ cdrom_file *file;
+ UINT32 physofs, chdofs;
+ chd_error err;
+
+ /* punt if no CHD */
+ if (!chd)
+ return NULL;
+
+ /* validate the CHD information */
+ if (header->hunkbytes % CD_FRAME_SIZE != 0)
+ return NULL;
+
+ /* allocate memory for the CD-ROM file */
+ file = malloc(sizeof(cdrom_file));
+ if (file == NULL)
+ return NULL;
+
+ /* fill in the data */
+ file->chd = chd;
+ file->hunksectors = header->hunkbytes / CD_FRAME_SIZE;
+ file->cachehunk = -1;
+
+ /* read the CD-ROM metadata */
+ err = parse_metadata(chd, &file->cdtoc);
+ if (err != CHDERR_NONE)
+ {
+ free(file);
+ return NULL;
+ }
+
+ #if VERBOSE
+ logerror("CD has %d tracks\n", file->cdtoc.numtrks);
+ #endif
+
+ /* calculate the starting frame for each track, keeping in mind that CHDMAN
+ pads tracks out with extra frames to fit hunk size boundries
+ */
+ physofs = chdofs = 0;
+ for (i = 0; i < file->cdtoc.numtrks; i++)
+ {
+ file->cdtoc.tracks[i].physframeofs = physofs;
+ file->cdtoc.tracks[i].chdframeofs = chdofs;
+
+ physofs += file->cdtoc.tracks[i].frames;
+ chdofs += file->cdtoc.tracks[i].frames;
+ chdofs += file->cdtoc.tracks[i].extraframes;
+
+ #if VERBOSE
+ logerror("Track %02d is format %d subtype %d datasize %d subsize %d frames %d extraframes %d physofs %d chdofs %d\n", i+1,
+ file->cdtoc.tracks[i].trktype,
+ file->cdtoc.tracks[i].subtype,
+ file->cdtoc.tracks[i].datasize,
+ file->cdtoc.tracks[i].subsize,
+ file->cdtoc.tracks[i].frames,
+ file->cdtoc.tracks[i].extraframes,
+ file->cdtoc.tracks[i].physframeofs,
+ file->cdtoc.tracks[i].chdframeofs);
+ #endif
+ }
+
+ /* fill out dummy entries for the last track to help our search */
+ file->cdtoc.tracks[i].physframeofs = physofs;
+ file->cdtoc.tracks[i].chdframeofs = chdofs;
+
+ /* allocate a cache */
+ file->cache = malloc(chd_get_header(chd)->hunkbytes);
+ if (file->cache == NULL)
+ {
+ free(file);
+ return NULL;
+ }
+
+ return file;
+}
+
+
+/*-------------------------------------------------
+ cdrom_close - "close" a CD-ROM file
+-------------------------------------------------*/
+
+void cdrom_close(cdrom_file *file)
+{
+ if (file == NULL)
+ return;
+
+ /* free the cache */
+ if (file->cache)
+ free(file->cache);
+ free(file);
+}
+
+
+
+/***************************************************************************
+ CORE READ ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+ cdrom_read_data - read one or more sectors
+ from a CD-ROM
+-------------------------------------------------*/
+
+UINT32 cdrom_read_data(cdrom_file *file, UINT32 lbasector, void *buffer, UINT32 datatype)
+{
+ UINT32 tracktype, tracknum, sectoroffs;
+ chd_error err;
+
+ if (file == NULL)
+ return 0;
+
+ /* cache in the sector */
+ err = read_sector_into_cache(file, lbasector, &sectoroffs, &tracknum);
+ if (err != CHDERR_NONE)
+ return 0;
+
+ /* copy out the requested sector */
+ tracktype = file->cdtoc.tracks[tracknum].trktype;
+ if ((datatype == tracktype) || (datatype == CD_TRACK_RAW_DONTCARE))
+ {
+ memcpy(buffer, &file->cache[sectoroffs * CD_FRAME_SIZE], file->cdtoc.tracks[tracknum].datasize);
+ }
+ else
+ {
+ /* return 2048 bytes of mode1 data from a 2336 byte mode 1 or 2 raw sector */
+ if ((datatype == CD_TRACK_MODE1) && ((tracktype == CD_TRACK_MODE1_RAW) || (tracktype == CD_TRACK_MODE2_RAW)))
+ {
+ memcpy(buffer, &file->cache[(sectoroffs * CD_FRAME_SIZE) + 16], 2048);
+ return 1;
+ }
+
+ /* return 2048 bytes of mode1 data from a mode2 form1 sector */
+ if ((datatype == CD_TRACK_MODE1) && (tracktype == CD_TRACK_MODE2_FORM1))
+ {
+ memcpy(buffer, &file->cache[(sectoroffs * CD_FRAME_SIZE) + 24], 2048);
+ return 1;
+ }
+
+ /* return mode 2 2336 byte data from a RAW sector */
+ if ((datatype == CD_TRACK_MODE2) && ((tracktype == CD_TRACK_MODE1_RAW) || (tracktype == CD_TRACK_MODE2_RAW)))
+ {
+ memcpy(buffer, &file->cache[(sectoroffs * CD_FRAME_SIZE) + 16], 2048);
+ return 1;
+ }
+
+ #if VERBOSE
+ logerror("CDROM: Conversion from type %d to type %d not supported!\n", tracktype, datatype);
+ #endif
+ return 0;
+ }
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ cdrom_read_subcode - read subcode data for
+ a sector
+-------------------------------------------------*/
+
+UINT32 cdrom_read_subcode(cdrom_file *file, UINT32 lbasector, void *buffer)
+{
+ UINT32 sectoroffs, tracknum;
+ chd_error err;
+
+ if (file == NULL)
+ return ~0;
+
+ /* cache in the sector */
+ err = read_sector_into_cache(file, lbasector, &sectoroffs, &tracknum);
+ if (err != CHDERR_NONE)
+ return 0;
+
+ /* copy out the requested data */
+ memcpy(buffer, &file->cache[(sectoroffs * CD_FRAME_SIZE) + file->cdtoc.tracks[tracknum].datasize], file->cdtoc.tracks[tracknum].subsize);
+ return 1;
+}
+
+
+
+/***************************************************************************
+ HANDY UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ cdrom_get_track - get the track number
+ for a physical frame number
+-------------------------------------------------*/
+
+UINT32 cdrom_get_track(cdrom_file *file, UINT32 frame)
+{
+ UINT32 track = 0;
+
+ if (file == NULL)
+ return ~0;
+
+ /* convert to a CHD sector offset and get track information */
+ physical_to_chd_lba(file, frame, &track);
+ return track;
+}
+
+
+/*-------------------------------------------------
+ cdrom_get_track_start - get the frame number
+ that a track starts at
+-------------------------------------------------*/
+
+UINT32 cdrom_get_track_start(cdrom_file *file, UINT32 track)
+{
+ if (file == NULL)
+ return ~0;
+
+ /* handle lead-out specially */
+ if (track == 0xaa)
+ track = file->cdtoc.numtrks;
+
+ return file->cdtoc.tracks[track].physframeofs;
+}
+
+
+
+/***************************************************************************
+ TOC UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ cdrom_get_last_track - returns the last track
+ number
+-------------------------------------------------*/
+
+int cdrom_get_last_track(cdrom_file *file)
+{
+ if (file == NULL)
+ return -1;
+
+ return file->cdtoc.numtrks;
+}
+
+
+/*-------------------------------------------------
+ cdrom_get_adr_control - get the ADR | CONTROL
+ for a track
+-------------------------------------------------*/
+
+int cdrom_get_adr_control(cdrom_file *file, int track)
+{
+ if (file == NULL)
+ return -1;
+
+ if (track == 0xaa || file->cdtoc.tracks[track].trktype == CD_TRACK_AUDIO)
+ {
+ return 0x10; // audio track, subchannel is position
+ }
+
+ return 0x14; // data track, subchannel is position
+}
+
+
+/*-------------------------------------------------
+ cdrom_get_track_type - return the track type
+-------------------------------------------------*/
+
+int cdrom_get_track_type(cdrom_file *file, int track)
+{
+ if (file == NULL)
+ return -1;
+
+ return file->cdtoc.tracks[track].trktype;
+}
+
+
+/*-------------------------------------------------
+ cdrom_get_toc - return the TOC data for a
+ CD-ROM
+-------------------------------------------------*/
+
+const cdrom_toc *cdrom_get_toc(cdrom_file *file)
+{
+ if (file == NULL)
+ return NULL;
+
+ return &file->cdtoc;
+}
+
+
+
+/***************************************************************************
+ EXTRA UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ cdrom_convert_type_string_to_track_info -
+ take a string and convert it into track type
+ and track data size
+-------------------------------------------------*/
+
+void cdrom_convert_type_string_to_track_info(const char *typestring, cdrom_track_info *info)
+{
+ if (!strcmp(typestring, "MODE1"))
+ {
+ info->trktype = CD_TRACK_MODE1;
+ info->datasize = 2048;
+ }
+ else if (!strcmp(typestring, "MODE1_RAW"))
+ {
+ info->trktype = CD_TRACK_MODE1_RAW;
+ info->datasize = 2352;
+ }
+ else if (!strcmp(typestring, "MODE2"))
+ {
+ info->trktype = CD_TRACK_MODE2;
+ info->datasize = 2336;
+ }
+ else if (!strcmp(typestring, "MODE2_FORM1"))
+ {
+ info->trktype = CD_TRACK_MODE2_FORM1;
+ info->datasize = 2048;
+ }
+ else if (!strcmp(typestring, "MODE2_FORM2"))
+ {
+ info->trktype = CD_TRACK_MODE2_FORM2;
+ info->datasize = 2324;
+ }
+ else if (!strcmp(typestring, "MODE2_FORM_MIX"))
+ {
+ info->trktype = CD_TRACK_MODE2_FORM_MIX;
+ info->datasize = 2336;
+ }
+ else if (!strcmp(typestring, "MODE2_RAW"))
+ {
+ info->trktype = CD_TRACK_MODE2_RAW;
+ info->datasize = 2352;
+ }
+ else if (!strcmp(typestring, "AUDIO"))
+ {
+ info->trktype = CD_TRACK_AUDIO;
+ info->datasize = 2352;
+ }
+}
+
+
+/*-------------------------------------------------
+ cdrom_convert_subtype_string_to_track_info -
+ take a string and convert it into track subtype
+ and track subcode data size
+-------------------------------------------------*/
+
+void cdrom_convert_subtype_string_to_track_info(const char *typestring, cdrom_track_info *info)
+{
+ if (!strcmp(typestring, "RW"))
+ {
+ info->subtype = CD_SUB_NORMAL;
+ info->subsize = 96;
+ }
+ else if (!strcmp(typestring, "RW_RAW"))
+ {
+ info->subtype = CD_SUB_RAW;
+ info->subsize = 96;
+ }
+}
+
+
+/*-------------------------------------------------
+ cdrom_get_type_string - get the string
+ associated with the given type
+-------------------------------------------------*/
+
+const char *cdrom_get_type_string(const cdrom_track_info *info)
+{
+ switch (info->trktype)
+ {
+ case CD_TRACK_MODE1: return "MODE1";
+ case CD_TRACK_MODE1_RAW: return "MODE1_RAW";
+ case CD_TRACK_MODE2: return "MODE2";
+ case CD_TRACK_MODE2_FORM1: return "MODE2_FORM1";
+ case CD_TRACK_MODE2_FORM2: return "MODE2_FORM2";
+ case CD_TRACK_MODE2_FORM_MIX: return "MODE2_FORM_MIX";
+ case CD_TRACK_MODE2_RAW: return "MODE2_RAW";
+ case CD_TRACK_AUDIO: return "AUDIO";
+ default: return "UNKNOWN";
+ }
+}
+
+
+/*-------------------------------------------------
+ cdrom_get_subtype_string - get the string
+ associated with the given subcode type
+-------------------------------------------------*/
+
+const char *cdrom_get_subtype_string(const cdrom_track_info *info)
+{
+ switch (info->subtype)
+ {
+ case CD_SUB_NORMAL: return "RW";
+ case CD_SUB_RAW: return "RW_RAW";
+ default: return "NONE";
+ }
+}
+
+
+
+/***************************************************************************
+ INTERNAL UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ read_sector_into_cache - cache a sector at
+ the given physical LBA
+-------------------------------------------------*/
+
+static chd_error read_sector_into_cache(cdrom_file *file, UINT32 lbasector, UINT32 *sectoroffs, UINT32 *tracknum)
+{
+ UINT32 chdsector, hunknum;
+ chd_error err;
+
+ /* convert to a CHD sector offset and get track information */
+ *tracknum = 0;
+ chdsector = physical_to_chd_lba(file, lbasector, tracknum);
+ hunknum = chdsector / file->hunksectors;
+ *sectoroffs = chdsector % file->hunksectors;
+
+ /* if we haven't cached this hunk, read it now */
+ if (file->cachehunk != hunknum)
+ {
+ err = chd_read(file->chd, hunknum, file->cache);
+ if (err != CHDERR_NONE)
+ return err;
+ file->cachehunk = hunknum;
+ }
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ parse_metadata - parse metadata into the TOC
+ structure
+-------------------------------------------------*/
+
+static chd_error parse_metadata(chd_file *chd, cdrom_toc *toc)
+{
+ static UINT32 oldmetadata[CD_METADATA_WORDS], *mrp;
+ const chd_header *header = chd_get_header(chd);
+ UINT32 hunksectors = header->hunkbytes / CD_FRAME_SIZE;
+ char metadata[256];
+ chd_error err;
+ int i;
+
+ /* start with no tracks */
+ for (toc->numtrks = 0; toc->numtrks < CD_MAX_TRACKS; toc->numtrks++)
+ {
+ cdrom_track_info *track = &toc->tracks[toc->numtrks];
+ int tracknum = -1, frames = 0, hunks;
+ char type[11], subtype[11];
+
+ /* fetch the metadata for this track */
+ err = chd_get_metadata(chd, CDROM_TRACK_METADATA_TAG, toc->numtrks, metadata, sizeof(metadata), NULL, NULL);
+ if (err != CHDERR_NONE)
+ break;
+
+ /* parse the metadata */
+ type[0] = subtype[0] = 0;
+ if (sscanf(metadata, CDROM_TRACK_METADATA_FORMAT, &tracknum, type, subtype, &frames) != 4)
+ return CHDERR_INVALID_DATA;
+ if (tracknum != toc->numtrks + 1)
+ return CHDERR_INVALID_DATA;
+
+ /* extract the track type and determine the data size */
+ track->trktype = CD_TRACK_MODE1;
+ track->datasize = 0;
+ cdrom_convert_type_string_to_track_info(type, track);
+ if (track->datasize == 0)
+ return CHDERR_INVALID_DATA;
+
+ /* extract the subtype and determine the subcode data size */
+ track->subtype = CD_SUB_NONE;
+ track->subsize = 0;
+ cdrom_convert_subtype_string_to_track_info(subtype, track);
+
+ /* set the frames and extra frames data */
+ track->frames = frames;
+ hunks = (frames + hunksectors - 1) / hunksectors;
+ track->extraframes = hunks * hunksectors - frames;
+ }
+
+ /* if we got any tracks this way, we're done */
+ if (toc->numtrks > 0)
+ return CHDERR_NONE;
+
+ /* look for old-style metadata */
+ err = chd_get_metadata(chd, CDROM_OLD_METADATA_TAG, 0, oldmetadata, sizeof(oldmetadata), NULL, NULL);
+ if (err != CHDERR_NONE)
+ return err;
+
+ /* reconstruct the TOC from it */
+ mrp = &oldmetadata[0];
+ toc->numtrks = *mrp++;
+
+ for (i = 0; i < CD_MAX_TRACKS; i++)
+ {
+ toc->tracks[i].trktype = *mrp++;
+ toc->tracks[i].subtype = *mrp++;
+ toc->tracks[i].datasize = *mrp++;
+ toc->tracks[i].subsize = *mrp++;
+ toc->tracks[i].frames = *mrp++;
+ toc->tracks[i].extraframes = *mrp++;
+ }
+
+ /* TODO: I don't know why sometimes the data is one endian and sometimes another */
+ if ((toc->numtrks < 0) || (toc->numtrks > CD_MAX_TRACKS))
+ {
+ toc->numtrks = FLIPENDIAN_INT32(toc->numtrks);
+ for (i = 0; i < CD_MAX_TRACKS; i++)
+ {
+ toc->tracks[i].trktype = FLIPENDIAN_INT32(toc->tracks[i].trktype);
+ toc->tracks[i].subtype = FLIPENDIAN_INT32(toc->tracks[i].subtype);
+ toc->tracks[i].datasize = FLIPENDIAN_INT32(toc->tracks[i].datasize);
+ toc->tracks[i].subsize = FLIPENDIAN_INT32(toc->tracks[i].subsize);
+ toc->tracks[i].frames = FLIPENDIAN_INT32(toc->tracks[i].frames);
+ toc->tracks[i].extraframes = FLIPENDIAN_INT32(toc->tracks[i].extraframes);
+ }
+ }
+
+ return CHDERR_NONE;
+}
diff --git a/src/lib/util/cdrom.h b/src/lib/util/cdrom.h
new file mode 100644
index 00000000000..75f12e7099a
--- /dev/null
+++ b/src/lib/util/cdrom.h
@@ -0,0 +1,139 @@
+/***************************************************************************
+
+ cdrom.h
+
+ Generic MAME cd-rom implementation
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CDROM_H__
+#define __CDROM_H__
+
+#include "osdcore.h"
+#include "chd.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define CD_MAX_TRACKS (99) /* AFAIK the theoretical limit */
+#define CD_MAX_SECTOR_DATA (2352)
+#define CD_MAX_SUBCODE_DATA (96)
+
+#define CD_FRAME_SIZE (CD_MAX_SECTOR_DATA + CD_MAX_SUBCODE_DATA)
+#define CD_FRAMES_PER_HUNK (4)
+
+#define CD_METADATA_WORDS (1+(CD_MAX_TRACKS * 6))
+enum
+{
+ CD_TRACK_MODE1 = 0, /* mode 1 2048 bytes/sector */
+ CD_TRACK_MODE1_RAW, /* mode 1 2352 bytes/sector */
+ CD_TRACK_MODE2, /* mode 2 2336 bytes/sector */
+ CD_TRACK_MODE2_FORM1, /* mode 2 2048 bytes/sector */
+ CD_TRACK_MODE2_FORM2, /* mode 2 2324 bytes/sector */
+ CD_TRACK_MODE2_FORM_MIX, /* mode 2 2336 bytes/sector */
+ CD_TRACK_MODE2_RAW, /* mode 2 2352 bytes / sector */
+ CD_TRACK_AUDIO, /* redbook audio track 2352 bytes/sector (588 samples) */
+
+ CD_TRACK_RAW_DONTCARE /* special flag for cdrom_read_data: just return me whatever is there */
+};
+
+enum
+{
+ CD_SUB_NORMAL = 0, /* "cooked" 96 bytes per sector */
+ CD_SUB_RAW, /* raw uninterleaved 96 bytes per sector */
+ CD_SUB_NONE /* no subcode data stored */
+};
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _cdrom_file cdrom_file;
+
+
+typedef struct _cdrom_track_info cdrom_track_info;
+struct _cdrom_track_info
+{
+ /* fields used by CHDMAN and in MAME */
+ UINT32 trktype; /* track type */
+ UINT32 subtype; /* subcode data type */
+ UINT32 datasize; /* size of data in each sector of this track */
+ UINT32 subsize; /* size of subchannel data in each sector of this track */
+ UINT32 frames; /* number of frames in this track */
+ UINT32 extraframes; /* number of "spillage" frames in this track */
+
+ /* fields used in MAME only */
+ UINT32 physframeofs; /* frame number on the real CD this track starts at */
+ UINT32 chdframeofs; /* frame number this track starts at on the CHD */
+};
+
+
+typedef struct _cdrom_toc cdrom_toc;
+struct _cdrom_toc
+{
+ UINT32 numtrks; /* number of tracks */
+ cdrom_track_info tracks[CD_MAX_TRACKS];
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* base functionality */
+cdrom_file *cdrom_open(chd_file *chd);
+void cdrom_close(cdrom_file *file);
+
+/* core read access */
+UINT32 cdrom_read_data(cdrom_file *file, UINT32 lbasector, void *buffer, UINT32 datatype);
+UINT32 cdrom_read_subcode(cdrom_file *file, UINT32 lbasector, void *buffer);
+
+/* handy utilities */
+UINT32 cdrom_get_track(cdrom_file *file, UINT32 frame);
+UINT32 cdrom_get_track_start(cdrom_file *file, UINT32 track);
+
+/* TOC utilities */
+int cdrom_get_last_track(cdrom_file *file);
+int cdrom_get_adr_control(cdrom_file *file, int track);
+int cdrom_get_track_type(cdrom_file *file, int track);
+const cdrom_toc *cdrom_get_toc(cdrom_file *file);
+
+/* extra utilities */
+void cdrom_convert_type_string_to_track_info(const char *typestring, cdrom_track_info *info);
+void cdrom_convert_subtype_string_to_track_info(const char *typestring, cdrom_track_info *info);
+const char *cdrom_get_type_string(const cdrom_track_info *info);
+const char *cdrom_get_subtype_string(const cdrom_track_info *info);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE UINT32 lba_to_msf(UINT32 lba)
+{
+ UINT8 m, s, f;
+
+ m = lba / (60 * 75);
+ lba -= m * (60 * 75);
+ s = lba / 75;
+ f = lba % 75;
+
+ return ((m / 10) << 20) | ((m % 10) << 16) |
+ ((s / 10) << 12) | ((s % 10) << 8) |
+ ((f / 10) << 4) | ((f % 10) << 0);
+}
+
+#endif // __CDROM_H__
+
diff --git a/src/lib/util/chd.c b/src/lib/util/chd.c
new file mode 100644
index 00000000000..b36bd5c70fe
--- /dev/null
+++ b/src/lib/util/chd.c
@@ -0,0 +1,2860 @@
+/***************************************************************************
+
+ MAME Compressed Hunks of Data file format
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "chd.h"
+#include "avcomp.h"
+#include "md5.h"
+#include "sha1.h"
+#include <zlib.h>
+#include <time.h>
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define PRINTF_MAX_HUNK (0)
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAP_STACK_ENTRIES 512 /* max number of entries to use on the stack */
+#define MAP_ENTRY_SIZE 16 /* V3 and later */
+#define OLD_MAP_ENTRY_SIZE 8 /* V1-V2 */
+#define METADATA_HEADER_SIZE 16 /* metadata header size */
+#define CRCMAP_HASH_SIZE 4095 /* number of CRC hashtable entries */
+
+#define MAP_ENTRY_FLAG_TYPE_MASK 0x0f /* what type of hunk */
+#define MAP_ENTRY_FLAG_NO_CRC 0x10 /* no CRC is present */
+
+#define MAP_ENTRY_TYPE_INVALID 0x00 /* invalid type */
+#define MAP_ENTRY_TYPE_COMPRESSED 0x01 /* standard compression */
+#define MAP_ENTRY_TYPE_UNCOMPRESSED 0x02 /* uncompressed data */
+#define MAP_ENTRY_TYPE_MINI 0x03 /* mini: use offset as raw data */
+#define MAP_ENTRY_TYPE_SELF_HUNK 0x04 /* same as another hunk in this file */
+#define MAP_ENTRY_TYPE_PARENT_HUNK 0x05 /* same as a hunk in the parent file */
+
+#define CHD_V1_SECTOR_SIZE 512 /* size of a "sector" in the V1 header */
+
+#define COOKIE_VALUE 0xbaadf00d
+#define MAX_ZLIB_ALLOCS 64
+
+#define END_OF_LIST_COOKIE "EndOfListCookie"
+
+#define NO_MATCH (~0)
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#define EARLY_EXIT(x) do { (void)(x); goto cleanup; } while (0)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* interface to a codec */
+typedef struct _codec_interface codec_interface;
+struct _codec_interface
+{
+ UINT32 compression; /* type of compression */
+ const char *compname; /* name of the algorithm */
+ UINT8 lossy; /* is this a lossy algorithm? */
+ chd_error (*init)(chd_file *chd); /* codec initialize */
+ void (*free)(chd_file *chd); /* codec free */
+ chd_error (*compress)(chd_file *chd, const void *src, UINT32 *complen); /* compress data */
+ chd_error (*decompress)(chd_file *chd, UINT32 complen, void *dst); /* decompress data */
+ chd_error (*config)(chd_file *chd, int param, void *config); /* configure */
+};
+
+
+/* a single map entry */
+typedef struct _map_entry map_entry;
+struct _map_entry
+{
+ UINT64 offset; /* offset within the file of the data */
+ UINT32 crc; /* 32-bit CRC of the data */
+ UINT32 length; /* length of the data */
+ UINT8 flags; /* misc flags */
+};
+
+
+/* simple linked-list of hunks used for our CRC map */
+typedef struct _crcmap_entry crcmap_entry;
+struct _crcmap_entry
+{
+ UINT32 hunknum; /* hunk number */
+ crcmap_entry * next; /* next entry in list */
+};
+
+
+/* a single metadata entry */
+typedef struct _metadata_entry metadata_entry;
+struct _metadata_entry
+{
+ UINT64 offset; /* offset within the file of the header */
+ UINT64 next; /* offset within the file of the next header */
+ UINT64 prev; /* offset within the file of the previous header */
+ UINT32 length; /* length of the metadata */
+ UINT32 metatag; /* metadata tag */
+};
+
+
+/* internal representation of an open CHD file */
+struct _chd_file
+{
+ UINT32 cookie; /* cookie, should equal COOKIE_VALUE */
+
+ core_file * file; /* handle to the open core file */
+ UINT8 owns_file; /* flag indicating if this file should be closed on chd_close() */
+ chd_header header; /* header, extracted from file */
+
+ chd_file * parent; /* pointer to parent file, or NULL */
+
+ map_entry * map; /* array of map entries */
+
+ UINT8 * cache; /* hunk cache pointer */
+ UINT32 cachehunk; /* index of currently cached hunk */
+
+ UINT8 * compare; /* hunk compare pointer */
+ UINT32 comparehunk; /* index of current compare data */
+
+ UINT8 * compressed; /* pointer to buffer for compressed data */
+ const codec_interface * codecintf; /* interface to the codec */
+ void * codecdata; /* opaque pointer to codec data */
+
+ crcmap_entry * crcmap; /* CRC map entries */
+ crcmap_entry * crcfree; /* free list CRC entries */
+ crcmap_entry ** crctable; /* table of CRC entries */
+
+ UINT32 maxhunk; /* maximum hunk accessed */
+
+ UINT8 compressing; /* are we compressing? */
+ struct MD5Context compmd5; /* running MD5 during compression */
+ struct sha1_ctx compsha1; /* running SHA1 during compression */
+ UINT32 comphunk; /* next hunk we will compress */
+
+ UINT8 verifying; /* are we verifying? */
+ struct MD5Context vermd5; /* running MD5 during verification */
+ struct sha1_ctx versha1; /* running SHA1 during verification */
+ UINT32 verhunk; /* next hunk we will verify */
+
+ osd_work_queue * workqueue; /* pointer to work queue for async operations */
+ osd_work_item * workitem; /* active work item, or NULL if none */
+ UINT32 async_hunknum; /* hunk index for asynchronous operations */
+ void * async_buffer; /* buffer pointer for asynchronous operations */
+};
+
+
+/* codec-private data for the ZLIB codec */
+typedef struct _zlib_codec_data zlib_codec_data;
+struct _zlib_codec_data
+{
+ z_stream inflater;
+ z_stream deflater;
+ UINT32 * allocptr[MAX_ZLIB_ALLOCS];
+};
+
+
+/* codec-private data for the A/V codec */
+typedef struct _av_codec_data av_codec_data;
+struct _av_codec_data
+{
+ avcomp_state * compstate;
+ av_codec_decompress_config decompconfig;
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static const UINT8 nullmd5[CHD_MD5_BYTES] = { 0 };
+static const UINT8 nullsha1[CHD_SHA1_BYTES] = { 0 };
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+/* internal async operations */
+static void *async_read_callback(void *param, int threadid);
+static void *async_write_callback(void *param, int threadid);
+
+/* internal header operations */
+static chd_error header_validate(const chd_header *header);
+static chd_error header_read(core_file *file, chd_header *header);
+static chd_error header_write(core_file *file, const chd_header *header);
+
+/* internal hunk read/write */
+static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum);
+static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest);
+static chd_error hunk_write_from_memory(chd_file *chd, UINT32 hunknum, const UINT8 *src);
+
+/* internal map access */
+static chd_error map_write_initial(core_file *file, chd_file *parent, const chd_header *header);
+static chd_error map_read(chd_file *chd);
+
+/* internal CRC map access */
+static void crcmap_init(chd_file *chd, int prepopulate);
+static void crcmap_add_entry(chd_file *chd, UINT32 hunknum);
+static UINT32 crcmap_find_hunk(chd_file *chd, UINT32 hunknum, UINT32 crc, const UINT8 *rawdata);
+
+/* metadata management */
+static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry);
+static chd_error metadata_set_previous_next(chd_file *chd, UINT64 prevoffset, UINT64 nextoffset);
+static chd_error metadata_set_length(chd_file *chd, UINT64 offset, UINT32 length);
+
+/* zlib compression codec */
+static chd_error zlib_codec_init(chd_file *chd);
+static void zlib_codec_free(chd_file *chd);
+static chd_error zlib_codec_compress(chd_file *chd, const void *src, UINT32 *length);
+static chd_error zlib_codec_decompress(chd_file *chd, UINT32 srclength, void *dest);
+static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size);
+static void zlib_fast_free(voidpf opaque, voidpf address);
+
+/* A/V compression codec */
+static chd_error av_codec_init(chd_file *chd);
+static void av_codec_free(chd_file *chd);
+static chd_error av_codec_compress(chd_file *chd, const void *src, UINT32 *length);
+static chd_error av_codec_decompress(chd_file *chd, UINT32 srclength, void *dest);
+static chd_error av_codec_config(chd_file *chd, int param, void *config);
+static chd_error av_codec_postinit(chd_file *chd);
+
+
+
+/***************************************************************************
+ CODEC INTERFACES
+***************************************************************************/
+
+static const codec_interface codec_interfaces[] =
+{
+ /* "none" or no compression */
+ {
+ CHDCOMPRESSION_NONE,
+ "none",
+ FALSE,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ },
+
+ /* standard zlib compression */
+ {
+ CHDCOMPRESSION_ZLIB,
+ "zlib",
+ FALSE,
+ zlib_codec_init,
+ zlib_codec_free,
+ zlib_codec_compress,
+ zlib_codec_decompress,
+ NULL
+ },
+
+ /* zlib+ compression */
+ {
+ CHDCOMPRESSION_ZLIB_PLUS,
+ "zlib+",
+ FALSE,
+ zlib_codec_init,
+ zlib_codec_free,
+ zlib_codec_compress,
+ zlib_codec_decompress,
+ NULL
+ },
+
+ /* a/v compression */
+ {
+ CHDCOMPRESSION_AV,
+ "A/V",
+ TRUE,
+ av_codec_init,
+ av_codec_free,
+ av_codec_compress,
+ av_codec_decompress,
+ av_codec_config
+ }
+};
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ get_bigendian_uint64 - fetch a UINT64 from
+ the data stream in bigendian order
+-------------------------------------------------*/
+
+INLINE UINT64 get_bigendian_uint64(const UINT8 *base)
+{
+ return ((UINT64)base[0] << 56) | ((UINT64)base[1] << 48) | ((UINT64)base[2] << 40) | ((UINT64)base[3] << 32) |
+ ((UINT64)base[4] << 24) | ((UINT64)base[5] << 16) | ((UINT64)base[6] << 8) | (UINT64)base[7];
+}
+
+
+/*-------------------------------------------------
+ put_bigendian_uint64 - write a UINT64 to
+ the data stream in bigendian order
+-------------------------------------------------*/
+
+INLINE void put_bigendian_uint64(UINT8 *base, UINT64 value)
+{
+ base[0] = value >> 56;
+ base[1] = value >> 48;
+ base[2] = value >> 40;
+ base[3] = value >> 32;
+ base[4] = value >> 24;
+ base[5] = value >> 16;
+ base[6] = value >> 8;
+ base[7] = value;
+}
+
+
+/*-------------------------------------------------
+ get_bigendian_uint32 - fetch a UINT32 from
+ the data stream in bigendian order
+-------------------------------------------------*/
+
+INLINE UINT32 get_bigendian_uint32(const UINT8 *base)
+{
+ return (base[0] << 24) | (base[1] << 16) | (base[2] << 8) | base[3];
+}
+
+
+/*-------------------------------------------------
+ put_bigendian_uint32 - write a UINT32 to
+ the data stream in bigendian order
+-------------------------------------------------*/
+
+INLINE void put_bigendian_uint32(UINT8 *base, UINT32 value)
+{
+ base[0] = value >> 24;
+ base[1] = value >> 16;
+ base[2] = value >> 8;
+ base[3] = value;
+}
+
+
+/*-------------------------------------------------
+ get_bigendian_uint16 - fetch a UINT16 from
+ the data stream in bigendian order
+-------------------------------------------------*/
+
+INLINE UINT16 get_bigendian_uint16(const UINT8 *base)
+{
+ return (base[0] << 8) | base[1];
+}
+
+
+/*-------------------------------------------------
+ put_bigendian_uint16 - write a UINT16 to
+ the data stream in bigendian order
+-------------------------------------------------*/
+
+INLINE void put_bigendian_uint16(UINT8 *base, UINT16 value)
+{
+ base[0] = value >> 8;
+ base[1] = value;
+}
+
+
+/*-------------------------------------------------
+ map_extract - extract a single map
+ entry from the datastream
+-------------------------------------------------*/
+
+INLINE void map_extract(const UINT8 *base, map_entry *entry)
+{
+ entry->offset = get_bigendian_uint64(&base[0]);
+ entry->crc = get_bigendian_uint32(&base[8]);
+ entry->length = get_bigendian_uint16(&base[12]) | (base[14] << 16);
+ entry->flags = base[15];
+}
+
+
+/*-------------------------------------------------
+ map_assemble - write a single map
+ entry to the datastream
+-------------------------------------------------*/
+
+INLINE void map_assemble(UINT8 *base, map_entry *entry)
+{
+ put_bigendian_uint64(&base[0], entry->offset);
+ put_bigendian_uint32(&base[8], entry->crc);
+ put_bigendian_uint16(&base[12], entry->length);
+ base[14] = entry->length >> 16;
+ base[15] = entry->flags;
+}
+
+
+/*-------------------------------------------------
+ map_extract_old - extract a single map
+ entry in old format from the datastream
+-------------------------------------------------*/
+
+INLINE void map_extract_old(const UINT8 *base, map_entry *entry, UINT32 hunkbytes)
+{
+ entry->offset = get_bigendian_uint64(&base[0]);
+ entry->crc = 0;
+ entry->length = entry->offset >> 44;
+ entry->flags = MAP_ENTRY_FLAG_NO_CRC | ((entry->length == hunkbytes) ? MAP_ENTRY_TYPE_UNCOMPRESSED : MAP_ENTRY_TYPE_COMPRESSED);
+#ifdef __MWERKS__
+ entry->offset = entry->offset & 0x00000FFFFFFFFFFFLL;
+#else
+ entry->offset = (entry->offset << 20) >> 20;
+#endif
+}
+
+
+/*-------------------------------------------------
+ queue_async_operation - queue a new work
+ item
+-------------------------------------------------*/
+
+INLINE int queue_async_operation(chd_file *chd, osd_work_callback callback)
+{
+ /* if no queue yet, create one on the fly */
+ if (chd->workqueue == NULL)
+ {
+ chd->workqueue = osd_work_queue_alloc(WORK_QUEUE_FLAG_IO);
+ if (chd->workqueue == NULL)
+ return FALSE;
+ }
+
+ /* make sure we cleared out the previous item */
+ if (chd->workitem != NULL)
+ return FALSE;
+
+ /* create a new work item to run the job */
+ chd->workitem = osd_work_item_queue(chd->workqueue, callback, chd, 0);
+ if (chd->workitem == NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ wait_for_pending_async - wait for any pending
+ async
+-------------------------------------------------*/
+
+INLINE void wait_for_pending_async(chd_file *chd)
+{
+ /* if something is pending, wait for it */
+ if (chd->workitem != NULL)
+ {
+ /* 10 seconds should be enough for anything! */
+ int wait_successful = osd_work_item_wait(chd->workitem, 10 * osd_ticks_per_second());
+ if (!wait_successful)
+ osd_break_into_debugger("Pending async operation never completed!");
+ }
+}
+
+
+
+/***************************************************************************
+ CHD FILE MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ chd_create_file - create a new CHD file
+-------------------------------------------------*/
+
+chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent)
+{
+ chd_file *newchd = NULL;
+ chd_header header;
+ chd_error err;
+ int intfnum;
+
+ /* verify parameters */
+ if (file == NULL)
+ EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+ if (parent == NULL && (logicalbytes == 0 || hunkbytes == 0))
+ EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+
+ /* verify the compression type */
+ for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
+ if (codec_interfaces[intfnum].compression == compression)
+ break;
+ if (intfnum == ARRAY_LENGTH(codec_interfaces))
+ EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+
+ /* if we have a parent, the sizes come from there */
+ if (parent != NULL)
+ {
+ logicalbytes = parent->header.logicalbytes;
+ hunkbytes = parent->header.hunkbytes;
+ }
+
+ /* if we have a parent, it must be V3 or later */
+ if (parent != NULL && parent->header.version < 3)
+ EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION);
+
+ /* build the header */
+ memset(&header, 0, sizeof(header));
+ header.length = CHD_V3_HEADER_SIZE;
+ header.version = CHD_HEADER_VERSION;
+ header.flags = CHDFLAGS_IS_WRITEABLE;
+ header.compression = compression;
+ header.hunkbytes = hunkbytes;
+ header.totalhunks = (logicalbytes + hunkbytes - 1) / hunkbytes;
+ header.logicalbytes = logicalbytes;
+
+ /* tweaks if there is a parent */
+ if (parent != NULL)
+ {
+ header.flags |= CHDFLAGS_HAS_PARENT;
+ memcpy(&header.parentmd5[0], &parent->header.md5[0], sizeof(header.parentmd5));
+ memcpy(&header.parentsha1[0], &parent->header.sha1[0], sizeof(header.parentsha1));
+ }
+
+ /* validate it */
+ err = header_validate(&header);
+ if (err != CHDERR_NONE)
+ EARLY_EXIT(err);
+
+ /* write the resulting header */
+ err = header_write(file, &header);
+ if (err != CHDERR_NONE)
+ EARLY_EXIT(err);
+
+ /* create an initial map */
+ err = map_write_initial(file, parent, &header);
+ if (err != CHDERR_NONE)
+ EARLY_EXIT(err);
+
+ /* if we have a parent, clone the metadata */
+ if (parent != NULL)
+ {
+ /* open the new CHD via the standard mechanism */
+ err = chd_open_file(file, CHD_OPEN_READWRITE, parent, &newchd);
+ if (err != CHDERR_NONE)
+ EARLY_EXIT(err);
+
+ /* close the metadata */
+ err = chd_clone_metadata(parent, newchd);
+ if (err != CHDERR_NONE)
+ EARLY_EXIT(err);
+
+ /* close the CHD */
+ chd_close(newchd);
+ }
+
+ return CHDERR_NONE;
+
+cleanup:
+ if (newchd != NULL)
+ chd_close(newchd);
+ return err;
+}
+
+
+/*-------------------------------------------------
+ chd_open_file - open a CHD file for access
+-------------------------------------------------*/
+
+chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd)
+{
+ chd_file *newchd = NULL;
+ chd_error err;
+ int intfnum;
+
+ /* verify parameters */
+ if (file == NULL)
+ EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+
+ /* punt if invalid parent */
+ if (parent != NULL && parent->cookie != COOKIE_VALUE)
+ EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+
+ /* allocate memory for the final result */
+ newchd = malloc(sizeof(**chd));
+ if (newchd == NULL)
+ EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
+ memset(newchd, 0, sizeof(*newchd));
+ newchd->cookie = COOKIE_VALUE;
+ newchd->parent = parent;
+ newchd->file = file;
+
+ /* now attempt to read the header */
+ err = header_read(newchd->file, &newchd->header);
+ if (err != CHDERR_NONE)
+ EARLY_EXIT(err);
+
+ /* validate the header */
+ err = header_validate(&newchd->header);
+ if (err != CHDERR_NONE)
+ EARLY_EXIT(err);
+
+ /* make sure we don't open a read-only file writeable */
+ if (mode == CHD_OPEN_READWRITE && !(newchd->header.flags & CHDFLAGS_IS_WRITEABLE))
+ EARLY_EXIT(err = CHDERR_FILE_NOT_WRITEABLE);
+
+ /* also, never open an older version writeable */
+ if (mode == CHD_OPEN_READWRITE && newchd->header.version < CHD_HEADER_VERSION)
+ EARLY_EXIT(err = CHDERR_UNSUPPORTED_VERSION);
+
+ /* if we need a parent, make sure we have one */
+ if (parent == NULL && (newchd->header.flags & CHDFLAGS_HAS_PARENT))
+ EARLY_EXIT(err = CHDERR_REQUIRES_PARENT);
+
+ /* make sure we have a valid parent */
+ if (parent != NULL)
+ {
+ /* check MD5 if it isn't empty */
+ if (memcmp(nullmd5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0 &&
+ memcmp(nullmd5, newchd->parent->header.md5, sizeof(newchd->parent->header.md5)) != 0 &&
+ memcmp(newchd->parent->header.md5, newchd->header.parentmd5, sizeof(newchd->header.parentmd5)) != 0)
+ EARLY_EXIT(err = CHDERR_INVALID_PARENT);
+
+ /* check SHA1 if it isn't empty */
+ if (memcmp(nullsha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0 &&
+ memcmp(nullsha1, newchd->parent->header.sha1, sizeof(newchd->parent->header.sha1)) != 0 &&
+ memcmp(newchd->parent->header.sha1, newchd->header.parentsha1, sizeof(newchd->header.parentsha1)) != 0)
+ EARLY_EXIT(err = CHDERR_INVALID_PARENT);
+ }
+
+ /* now read the hunk map */
+ err = map_read(newchd);
+ if (err != CHDERR_NONE)
+ EARLY_EXIT(err);
+
+ /* allocate and init the hunk cache */
+ newchd->cache = malloc(newchd->header.hunkbytes);
+ newchd->compare = malloc(newchd->header.hunkbytes);
+ if (newchd->cache == NULL || newchd->compare == NULL)
+ EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
+ newchd->cachehunk = ~0;
+ newchd->comparehunk = ~0;
+
+ /* allocate the temporary compressed buffer */
+ newchd->compressed = malloc(newchd->header.hunkbytes);
+ if (newchd->compressed == NULL)
+ EARLY_EXIT(err = CHDERR_OUT_OF_MEMORY);
+
+ /* find the codec interface */
+ for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
+ if (codec_interfaces[intfnum].compression == newchd->header.compression)
+ {
+ newchd->codecintf = &codec_interfaces[intfnum];
+ break;
+ }
+ if (intfnum == ARRAY_LENGTH(codec_interfaces))
+ EARLY_EXIT(err = CHDERR_UNSUPPORTED_FORMAT);
+
+ /* initialize the codec */
+ if (newchd->codecintf->init != NULL)
+ err = (*newchd->codecintf->init)(newchd);
+ if (err != CHDERR_NONE)
+ EARLY_EXIT(err);
+
+ /* all done */
+ *chd = newchd;
+ return CHDERR_NONE;
+
+cleanup:
+ if (newchd != NULL)
+ chd_close(newchd);
+ return err;
+}
+
+
+/*-------------------------------------------------
+ chd_create - create a CHD file by
+ filename
+-------------------------------------------------*/
+
+chd_error chd_create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent)
+{
+ core_file *file = NULL;
+ file_error filerr;
+ chd_error chderr;
+
+ filerr = core_fopen(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE | OPEN_FLAG_CREATE, &file);
+ if (filerr != FILERR_NONE)
+ {
+ chderr = CHDERR_FILE_NOT_FOUND;
+ goto cleanup;
+ }
+
+ chderr = chd_create_file(file, logicalbytes, hunkbytes, compression, parent);
+ if (chderr != CHDERR_NONE)
+ goto cleanup;
+
+cleanup:
+ if (file != NULL)
+ core_fclose(file);
+ return chderr;
+}
+
+
+/*-------------------------------------------------
+ chd_open - open a CHD file by
+ filename
+-------------------------------------------------*/
+
+chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd)
+{
+ chd_error err;
+ file_error filerr;
+ core_file *file = NULL;
+ UINT32 openflags;
+
+ /* choose the proper mode */
+ switch(mode)
+ {
+ case CHD_OPEN_READ:
+ openflags = OPEN_FLAG_READ;
+ break;
+
+ case CHD_OPEN_READWRITE:
+ openflags = OPEN_FLAG_READ | OPEN_FLAG_WRITE;
+ break;
+
+ default:
+ err = CHDERR_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ /* open the file */
+ filerr = core_fopen(filename, openflags, &file);
+ if (filerr != FILERR_NONE)
+ {
+ err = CHDERR_FILE_NOT_FOUND;
+ goto cleanup;
+ }
+
+ /* now open the CHD */
+ err = chd_open_file(file, mode, parent, chd);
+ if (err != CHDERR_NONE)
+ goto cleanup;
+
+ /* we now own this file */
+ (*chd)->owns_file = TRUE;
+
+cleanup:
+ if ((err != CHDERR_NONE) && (file != NULL))
+ core_fclose(file);
+ return err;
+}
+
+
+/*-------------------------------------------------
+ chd_close - close a CHD file for access
+-------------------------------------------------*/
+
+void chd_close(chd_file *chd)
+{
+ /* punt if NULL or invalid */
+ if (chd == NULL || chd->cookie != COOKIE_VALUE)
+ return;
+
+ /* wait for any pending async operations */
+ wait_for_pending_async(chd);
+
+ /* kill the work queue and any work item */
+ if (chd->workitem != NULL)
+ osd_work_item_release(chd->workitem);
+ if (chd->workqueue != NULL)
+ osd_work_queue_free(chd->workqueue);
+
+ /* deinit the codec */
+ if (chd->codecintf != NULL && chd->codecintf->free != NULL)
+ (*chd->codecintf->free)(chd);
+
+ /* free the compressed data buffer */
+ if (chd->compressed != NULL)
+ free(chd->compressed);
+
+ /* free the hunk cache and compare data */
+ if (chd->compare != NULL)
+ free(chd->compare);
+ if (chd->cache != NULL)
+ free(chd->cache);
+
+ /* free the hunk map */
+ if (chd->map != NULL)
+ free(chd->map);
+
+ /* free the CRC table */
+ if (chd->crctable != NULL)
+ free(chd->crctable);
+
+ /* free the CRC map */
+ if (chd->crcmap != NULL)
+ free(chd->crcmap);
+
+ /* close the file */
+ if (chd->owns_file && chd->file != NULL)
+ core_fclose(chd->file);
+
+#if PRINTF_MAX_HUNK
+ printf("Max hunk = %d/%d\n", chd->maxhunk, chd->header.totalhunks);
+#endif
+
+ /* free our memory */
+ free(chd);
+}
+
+
+/*-------------------------------------------------
+ chd_core_file - return the associated
+ core_file
+-------------------------------------------------*/
+
+core_file *chd_core_file(chd_file *chd)
+{
+ return chd->file;
+}
+
+
+/*-------------------------------------------------
+ chd_multi_filename - compute the indexed CHD
+ filename
+-------------------------------------------------*/
+
+void chd_multi_filename(const char *origname, char *finalname, int index)
+{
+ char *extension;
+ char findex[5];
+
+ /* copy the original name */
+ strcpy(finalname, origname);
+
+ /* determine the offset of the extension period */
+ extension = strchr(finalname, '.');
+ if (extension == NULL)
+ extension = finalname + strlen(finalname);
+
+ /* compute our extension */
+ sprintf(findex, ".%3d", index);
+ if (findex[1] == ' ')
+ findex[1] = 'c';
+ if (findex[2] == ' ')
+ findex[2] = 'h';
+ strcpy(extension, findex);
+}
+
+
+
+/***************************************************************************
+ CHD HEADER MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ chd_get_header - return a pointer to the
+ extracted header data
+-------------------------------------------------*/
+
+const chd_header *chd_get_header(chd_file *chd)
+{
+ /* punt if NULL or invalid */
+ if (chd == NULL || chd->cookie != COOKIE_VALUE)
+ return NULL;
+
+ return &chd->header;
+}
+
+
+/*-------------------------------------------------
+ chd_set_header_file - write the current header to
+ the file
+-------------------------------------------------*/
+
+chd_error chd_set_header_file(core_file *file, const chd_header *header)
+{
+ chd_header oldheader;
+ chd_error err;
+
+ /* validate the header */
+ err = header_validate(header);
+ if (err != CHDERR_NONE)
+ EARLY_EXIT(err);
+
+ /* read the old header */
+ err = header_read(file, &oldheader);
+ if (err != CHDERR_NONE)
+ EARLY_EXIT(err);
+
+ /* make sure we're only making valid changes */
+ if (header->length != oldheader.length)
+ EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+ if (header->version != oldheader.version)
+ EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+ if (header->compression != oldheader.compression)
+ EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+ if (header->hunkbytes != oldheader.hunkbytes)
+ EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+ if (header->totalhunks != oldheader.totalhunks)
+ EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+ if (header->metaoffset != oldheader.metaoffset)
+ EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+ if (header->obsolete_hunksize != oldheader.obsolete_hunksize)
+ EARLY_EXIT(err = CHDERR_INVALID_PARAMETER);
+
+ /* write the new header */
+ err = header_write(file, header);
+ if (err != CHDERR_NONE)
+ EARLY_EXIT(err);
+
+ return CHDERR_NONE;
+
+cleanup:
+ return err;
+}
+
+
+/*-------------------------------------------------
+ chd_set_header - write the current
+ header to the file
+-------------------------------------------------*/
+
+chd_error chd_set_header(const char *filename, const chd_header *header)
+{
+ core_file *file = NULL;
+ file_error filerr;
+ chd_error err;
+
+ filerr = core_fopen(filename, OPEN_FLAG_READ | OPEN_FLAG_WRITE, &file);
+ if (filerr != FILERR_NONE)
+ {
+ err = CHDERR_FILE_NOT_FOUND;
+ goto cleanup;
+ }
+
+ err = chd_set_header_file(file, header);
+ if (err != CHDERR_NONE)
+ goto cleanup;
+
+cleanup:
+ if (file != NULL)
+ core_fclose(file);
+ return err;
+}
+
+
+
+/***************************************************************************
+ CORE DATA READ/WRITE
+***************************************************************************/
+
+/*-------------------------------------------------
+ chd_read - read a single hunk from the CHD
+ file
+-------------------------------------------------*/
+
+chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer)
+{
+ /* punt if NULL or invalid */
+ if (chd == NULL || chd->cookie != COOKIE_VALUE)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* if we're past the end, fail */
+ if (hunknum >= chd->header.totalhunks)
+ return CHDERR_HUNK_OUT_OF_RANGE;
+
+ /* wait for any pending async operations */
+ wait_for_pending_async(chd);
+
+ /* perform the read */
+ return hunk_read_into_memory(chd, hunknum, buffer);
+}
+
+
+/*-------------------------------------------------
+ chd_read_async - read a single hunk from the
+ CHD file asynchronously
+-------------------------------------------------*/
+
+chd_error chd_read_async(chd_file *chd, UINT32 hunknum, void *buffer)
+{
+ /* punt if NULL or invalid */
+ if (chd == NULL || chd->cookie != COOKIE_VALUE)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* if we're past the end, fail */
+ if (hunknum >= chd->header.totalhunks)
+ return CHDERR_HUNK_OUT_OF_RANGE;
+
+ /* wait for any pending async operations */
+ wait_for_pending_async(chd);
+
+ /* set the async parameters */
+ chd->async_hunknum = hunknum;
+ chd->async_buffer = buffer;
+
+ /* queue the work item */
+ if (queue_async_operation(chd, async_read_callback))
+ return CHDERR_OPERATION_PENDING;
+
+ /* if we fail, fall back on the sync version */
+ return chd_read(chd, hunknum, buffer);
+}
+
+
+/*-------------------------------------------------
+ chd_write - write a single hunk to the CHD
+ file
+-------------------------------------------------*/
+
+chd_error chd_write(chd_file *chd, UINT32 hunknum, const void *buffer)
+{
+ /* punt if NULL or invalid */
+ if (chd == NULL || chd->cookie != COOKIE_VALUE)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* if we're past the end, fail */
+ if (hunknum >= chd->header.totalhunks)
+ return CHDERR_HUNK_OUT_OF_RANGE;
+
+ /* wait for any pending async operations */
+ wait_for_pending_async(chd);
+
+ /* then write out the hunk */
+ return hunk_write_from_memory(chd, hunknum, buffer);
+}
+
+
+/*-------------------------------------------------
+ chd_write_async - write a single hunk to the
+ CHD file asynchronously
+-------------------------------------------------*/
+
+chd_error chd_write_async(chd_file *chd, UINT32 hunknum, const void *buffer)
+{
+ /* punt if NULL or invalid */
+ if (chd == NULL || chd->cookie != COOKIE_VALUE)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* if we're past the end, fail */
+ if (hunknum >= chd->header.totalhunks)
+ return CHDERR_HUNK_OUT_OF_RANGE;
+
+ /* wait for any pending async operations */
+ wait_for_pending_async(chd);
+
+ /* set the async parameters */
+ chd->async_hunknum = hunknum;
+ chd->async_buffer = (void *)buffer;
+
+ /* queue the work item */
+ if (queue_async_operation(chd, async_write_callback))
+ return CHDERR_OPERATION_PENDING;
+
+ /* if we fail, fall back on the sync version */
+ return chd_write(chd, hunknum, buffer);
+}
+
+
+/*-------------------------------------------------
+ chd_async_complete - get the result of a
+ completed work item and clear it out of the
+ system
+-------------------------------------------------*/
+
+chd_error chd_async_complete(chd_file *chd)
+{
+ void *result;
+
+ /* if nothing present, return an error */
+ if (chd->workitem == NULL)
+ return CHDERR_NO_ASYNC_OPERATION;
+
+ /* wait for the work to complete */
+ wait_for_pending_async(chd);
+
+ /* get the result and free the work item */
+ result = osd_work_item_result(chd->workitem);
+ osd_work_item_release(chd->workitem);
+ chd->workitem = NULL;
+
+ return (chd_error)result;
+}
+
+
+
+/***************************************************************************
+ METADATA MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ chd_get_metadata - get the indexed metadata
+ of the given type
+-------------------------------------------------*/
+
+chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag)
+{
+ metadata_entry metaentry;
+ chd_error err;
+ UINT32 count;
+
+ /* wait for any pending async operations */
+ wait_for_pending_async(chd);
+
+ /* if we didn't find it, just return */
+ err = metadata_find_entry(chd, searchtag, searchindex, &metaentry);
+ if (err != CHDERR_NONE)
+ {
+ /* unless we're an old version and they are requesting hard disk metadata */
+ if (chd->header.version < 3 && (searchtag == HARD_DISK_METADATA_TAG || searchtag == CHDMETATAG_WILDCARD) && searchindex == 0)
+ {
+ char faux_metadata[256];
+ UINT32 faux_length;
+
+ /* fill in the faux metadata */
+ sprintf(faux_metadata, HARD_DISK_METADATA_FORMAT, chd->header.obsolete_cylinders, chd->header.obsolete_heads, chd->header.obsolete_sectors, chd->header.hunkbytes / chd->header.obsolete_hunksize);
+ faux_length = (UINT32)strlen(faux_metadata) + 1;
+
+ /* copy the metadata itself */
+ memcpy(output, faux_metadata, MIN(outputlen, faux_length));
+
+ /* return the length of the data and the tag */
+ if (resultlen != NULL)
+ *resultlen = faux_length;
+ if (resulttag != NULL)
+ *resulttag = HARD_DISK_METADATA_TAG;
+ return CHDERR_NONE;
+ }
+ return err;
+ }
+
+ /* read the metadata */
+ outputlen = MIN(outputlen, metaentry.length);
+ core_fseek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);
+ count = core_fread(chd->file, output, outputlen);
+ if (count != outputlen)
+ return CHDERR_READ_ERROR;
+
+ /* return the length of the data and the tag */
+ if (resultlen != NULL)
+ *resultlen = metaentry.length;
+ if (resulttag != NULL)
+ *resulttag = metaentry.metatag;
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ chd_set_metadata - write the indexed metadata
+ of the given type
+-------------------------------------------------*/
+
+chd_error chd_set_metadata(chd_file *chd, UINT32 metatag, UINT32 metaindex, const void *inputbuf, UINT32 inputlen)
+{
+ UINT8 raw_meta_header[METADATA_HEADER_SIZE];
+ metadata_entry metaentry;
+ chd_error err;
+ UINT64 offset;
+ UINT32 count;
+
+ /* if the disk is an old version, punt */
+ if (chd->header.version < 3)
+ return CHDERR_NOT_SUPPORTED;
+
+ /* if the disk isn't writeable, punt */
+ if (!(chd->header.flags & CHDFLAGS_IS_WRITEABLE))
+ return CHDERR_FILE_NOT_WRITEABLE;
+
+ /* must write at least 1 byte */
+ if (inputlen < 1)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* wait for any pending async operations */
+ wait_for_pending_async(chd);
+
+ /* find the entry if it already exists */
+ err = metadata_find_entry(chd, metatag, metaindex, &metaentry);
+
+ /* if it's there and it fits, just overwrite */
+ if (err == CHDERR_NONE && inputlen <= metaentry.length)
+ {
+ /* overwrite the original data with our new input data */
+ core_fseek(chd->file, metaentry.offset + METADATA_HEADER_SIZE, SEEK_SET);
+ count = core_fwrite(chd->file, inputbuf, inputlen);
+ if (count != inputlen)
+ return CHDERR_WRITE_ERROR;
+
+ /* if the lengths don't match, we need to update the length in our header */
+ if (inputlen != metaentry.length)
+ {
+ err = metadata_set_length(chd, metaentry.offset, inputlen);
+ if (err != CHDERR_NONE)
+ return err;
+ }
+ return CHDERR_NONE;
+ }
+
+ /* if we already have an entry, unlink it */
+ if (err == CHDERR_NONE)
+ {
+ err = metadata_set_previous_next(chd, metaentry.prev, metaentry.next);
+ if (err != CHDERR_NONE)
+ return err;
+ }
+
+ /* now build us a new entry */
+ put_bigendian_uint32(&raw_meta_header[0], metatag);
+ put_bigendian_uint32(&raw_meta_header[4], inputlen);
+ put_bigendian_uint64(&raw_meta_header[8], (err == CHDERR_NONE) ? metaentry.next : 0);
+
+ /* write out the new header */
+ offset = core_fsize(chd->file);
+ core_fseek(chd->file, offset, SEEK_SET);
+ count = core_fwrite(chd->file, raw_meta_header, sizeof(raw_meta_header));
+ if (count != sizeof(raw_meta_header))
+ return CHDERR_WRITE_ERROR;
+
+ /* follow that with the data */
+ core_fseek(chd->file, offset + METADATA_HEADER_SIZE, SEEK_SET);
+ count = core_fwrite(chd->file, inputbuf, inputlen);
+ if (count != inputlen)
+ return CHDERR_WRITE_ERROR;
+
+ /* set the previous entry to point to us */
+ err = metadata_set_previous_next(chd, metaentry.prev, offset);
+ if (err != CHDERR_NONE)
+ return err;
+
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ chd_clone_metadata - clone the metadata from
+ one CHD to a second
+-------------------------------------------------*/
+
+chd_error chd_clone_metadata(chd_file *source, chd_file *dest)
+{
+ UINT32 metatag, metasize, metaindex;
+ UINT8 metabuffer[1024];
+ chd_error err;
+
+ /* clone the metadata */
+ for (metaindex = 0; ; metaindex++)
+ {
+ /* fetch the next piece of metadata */
+ err = chd_get_metadata(source, CHDMETATAG_WILDCARD, metaindex, metabuffer, sizeof(metabuffer), &metasize, &metatag);
+ if (err != CHDERR_NONE)
+ {
+ if (err == CHDERR_METADATA_NOT_FOUND)
+ err = CHDERR_NONE;
+ break;
+ }
+
+ /* if that fit, just write it back from the temporary buffer */
+ if (metasize <= sizeof(metabuffer))
+ {
+ /* write it to the target */
+ err = chd_set_metadata(dest, metatag, CHD_METAINDEX_APPEND, metabuffer, metasize);
+ if (err != CHDERR_NONE)
+ break;
+ }
+
+ /* otherwise, allocate a bigger temporary buffer */
+ else
+ {
+ UINT8 *allocbuffer = malloc(metasize);
+ if (allocbuffer == NULL)
+ {
+ err = CHDERR_OUT_OF_MEMORY;
+ break;
+ }
+
+ /* re-read the whole thing */
+ err = chd_get_metadata(source, CHDMETATAG_WILDCARD, metaindex, allocbuffer, metasize, &metasize, &metatag);
+ if (err != CHDERR_NONE)
+ {
+ free(allocbuffer);
+ break;
+ }
+
+ /* write it to the target */
+ err = chd_set_metadata(dest, metatag, CHD_METAINDEX_APPEND, allocbuffer, metasize);
+ free(allocbuffer);
+ if (err != CHDERR_NONE)
+ break;
+ }
+ }
+ return err;
+}
+
+
+
+/***************************************************************************
+ COMPRESSION MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ chd_compress_begin - begin compressing data
+ into a CHD
+-------------------------------------------------*/
+
+chd_error chd_compress_begin(chd_file *chd)
+{
+ chd_error err;
+
+ /* verify parameters */
+ if (chd == NULL)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* wait for any pending async operations */
+ wait_for_pending_async(chd);
+
+ /* mark the CHD writeable and write the updated header */
+ chd->header.flags |= CHDFLAGS_IS_WRITEABLE;
+ err = header_write(chd->file, &chd->header);
+ if (err != CHDERR_NONE)
+ return err;
+
+ /* create CRC maps for the new CHD and the parent */
+ crcmap_init(chd, FALSE);
+ if (chd->parent != NULL)
+ crcmap_init(chd->parent, TRUE);
+
+ /* init the MD5/SHA1 computations */
+ MD5Init(&chd->compmd5);
+ sha1_init(&chd->compsha1);
+ chd->compressing = TRUE;
+ chd->comphunk = 0;
+
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ chd_compress_hunk - append data to a CHD
+ that is being compressed
+-------------------------------------------------*/
+
+chd_error chd_compress_hunk(chd_file *chd, const void *data, double *curratio)
+{
+ UINT32 thishunk = chd->comphunk++;
+ UINT64 sourceoffset = (UINT64)thishunk * (UINT64)chd->header.hunkbytes;
+ UINT32 bytestochecksum;
+ const void *crcdata;
+ chd_error err;
+
+ /* error if in the wrong state */
+ if (!chd->compressing)
+ return CHDERR_INVALID_STATE;
+
+ /* write out the hunk */
+ err = hunk_write_from_memory(chd, thishunk, data);
+ if (err != CHDERR_NONE)
+ return err;
+
+ /* if we are lossy, then we need to use the decompressed version in */
+ /* the cache as our MD5/SHA1 source */
+ crcdata = chd->codecintf->lossy ? chd->cache : data;
+
+ /* update the MD5/SHA1 */
+ bytestochecksum = chd->header.hunkbytes;
+ if (sourceoffset + chd->header.hunkbytes > chd->header.logicalbytes)
+ {
+ if (sourceoffset >= chd->header.logicalbytes)
+ bytestochecksum = 0;
+ else
+ bytestochecksum = chd->header.logicalbytes - sourceoffset;
+ }
+ if (bytestochecksum > 0)
+ {
+ MD5Update(&chd->compmd5, crcdata, bytestochecksum);
+ sha1_update(&chd->compsha1, bytestochecksum, crcdata);
+ }
+
+ /* update our CRC map */
+ if ((chd->map[thishunk].flags & MAP_ENTRY_FLAG_TYPE_MASK) != MAP_ENTRY_TYPE_SELF_HUNK &&
+ (chd->map[thishunk].flags & MAP_ENTRY_FLAG_TYPE_MASK) != MAP_ENTRY_TYPE_PARENT_HUNK)
+ crcmap_add_entry(chd, thishunk);
+
+ /* update the ratio */
+ if (curratio != NULL)
+ {
+ UINT64 curlength = core_fsize(chd->file);
+ *curratio = 1.0 - (double)curlength / (double)((UINT64)chd->comphunk * (UINT64)chd->header.hunkbytes);
+ }
+
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ chd_compress_finish - complete compression of
+ a CHD
+-------------------------------------------------*/
+
+chd_error chd_compress_finish(chd_file *chd)
+{
+ /* error if in the wrong state */
+ if (!chd->compressing)
+ return CHDERR_INVALID_STATE;
+
+ /* compute the final MD5/SHA1 values */
+ MD5Final(chd->header.md5, &chd->compmd5);
+ sha1_final(&chd->compsha1);
+ sha1_digest(&chd->compsha1, SHA1_DIGEST_SIZE, chd->header.sha1);
+
+ /* turn off the writeable flag and re-write the header */
+ chd->header.flags &= ~CHDFLAGS_IS_WRITEABLE;
+ chd->compressing = FALSE;
+ return header_write(chd->file, &chd->header);
+}
+
+
+
+/***************************************************************************
+ VERIFICATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ chd_verify_begin - begin compressing data
+ into a CHD
+-------------------------------------------------*/
+
+chd_error chd_verify_begin(chd_file *chd)
+{
+ /* verify parameters */
+ if (chd == NULL)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* if this is a writeable file image, we can't verify */
+ if (chd->header.flags & CHDFLAGS_IS_WRITEABLE)
+ return CHDERR_CANT_VERIFY;
+
+ /* wait for any pending async operations */
+ wait_for_pending_async(chd);
+
+ /* init the MD5/SHA1 computations */
+ MD5Init(&chd->vermd5);
+ sha1_init(&chd->versha1);
+ chd->verifying = TRUE;
+ chd->verhunk = 0;
+
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ chd_verify_hunk - verify the next hunk in
+ the CHD
+-------------------------------------------------*/
+
+chd_error chd_verify_hunk(chd_file *chd)
+{
+ UINT32 thishunk = chd->verhunk++;
+ UINT64 hunkoffset = (UINT64)thishunk * (UINT64)chd->header.hunkbytes;
+ map_entry *entry;
+ chd_error err;
+
+ /* error if in the wrong state */
+ if (!chd->verifying)
+ return CHDERR_INVALID_STATE;
+
+ /* read the hunk into the cache */
+ err = hunk_read_into_cache(chd, thishunk);
+ if (err != CHDERR_NONE)
+ return err;
+
+ /* update the MD5/SHA1 */
+ if (hunkoffset < chd->header.logicalbytes)
+ {
+ UINT64 bytestochecksum = MIN(chd->header.hunkbytes, chd->header.logicalbytes - hunkoffset);
+ if (bytestochecksum > 0)
+ {
+ MD5Update(&chd->vermd5, chd->cache, bytestochecksum);
+ sha1_update(&chd->versha1, bytestochecksum, chd->cache);
+ }
+ }
+
+ /* validate the CRC if we have one */
+ entry = &chd->map[thishunk];
+ if (!(entry->flags & MAP_ENTRY_FLAG_NO_CRC) && entry->crc != crc32(0, chd->cache, chd->header.hunkbytes))
+ return CHDERR_DECOMPRESSION_ERROR;
+
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ chd_verify_finish - finish verification of
+ the CHD
+-------------------------------------------------*/
+
+chd_error chd_verify_finish(chd_file *chd, UINT8 *finalmd5, UINT8 *finalsha1)
+{
+ /* error if in the wrong state */
+ if (!chd->verifying)
+ return CHDERR_INVALID_STATE;
+
+ /* compute the final MD5 */
+ if (finalmd5 != NULL)
+ MD5Final(finalmd5, &chd->vermd5);
+
+ /* compute the final SHA1 */
+ if (finalsha1 != NULL)
+ {
+ sha1_final(&chd->versha1);
+ sha1_digest(&chd->versha1, SHA1_DIGEST_SIZE, finalsha1);
+ }
+
+ /* return an error */
+ chd->verifying = FALSE;
+ return (chd->verhunk < chd->header.totalhunks) ? CHDERR_VERIFY_INCOMPLETE : CHDERR_NONE;
+}
+
+
+
+/***************************************************************************
+ CODEC INTERFACES
+***************************************************************************/
+
+/*-------------------------------------------------
+ chd_codec_config - set internal codec
+ parameters
+-------------------------------------------------*/
+
+chd_error chd_codec_config(chd_file *chd, int param, void *config)
+{
+ /* wait for any pending async operations */
+ wait_for_pending_async(chd);
+
+ /* if the codec has a configuration callback, call through to it */
+ if (chd->codecintf->config != NULL)
+ return (*chd->codecintf->config)(chd, param, config);
+
+ return CHDERR_INVALID_PARAMETER;
+}
+
+
+/*-------------------------------------------------
+ chd_get_codec_name - get the name of a
+ particular codec
+-------------------------------------------------*/
+
+const char *chd_get_codec_name(UINT32 codec)
+{
+ int intfnum;
+
+ /* look for a matching codec and return its string */
+ for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
+ if (codec_interfaces[intfnum].compression == codec)
+ return codec_interfaces[intfnum].compname;
+
+ return "Unknown";
+}
+
+
+
+/***************************************************************************
+ INTERNAL ASYNC OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ async_read_callback - asynchronous reading
+ callback
+-------------------------------------------------*/
+
+static void *async_read_callback(void *param, int threadid)
+{
+ chd_file *chd = param;
+ chd_error err;
+
+ /* read the hunk into the cache */
+ err = hunk_read_into_memory(chd, chd->async_hunknum, chd->async_buffer);
+
+ /* return the error */
+ return (void *)err;
+}
+
+
+/*-------------------------------------------------
+ async_write_callback - asynchronous writing
+ callback
+-------------------------------------------------*/
+
+static void *async_write_callback(void *param, int threadid)
+{
+ chd_file *chd = param;
+ chd_error err;
+
+ /* write the hunk from memory */
+ err = hunk_write_from_memory(chd, chd->async_hunknum, chd->async_buffer);
+
+ /* return the error */
+ return (void *)err;
+}
+
+
+
+/***************************************************************************
+ INTERNAL HEADER OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ header_validate - check the validity of a
+ CHD header
+-------------------------------------------------*/
+
+static chd_error header_validate(const chd_header *header)
+{
+ int intfnum;
+
+ /* require a valid version */
+ if (header->version == 0 || header->version > CHD_HEADER_VERSION)
+ return CHDERR_UNSUPPORTED_VERSION;
+
+ /* require a valid length */
+ if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
+ (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
+ (header->version == 3 && header->length != CHD_V3_HEADER_SIZE))
+ return CHDERR_INVALID_PARAMETER;
+
+ /* require valid flags */
+ if (header->flags & CHDFLAGS_UNDEFINED)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* require a supported compression mechanism */
+ for (intfnum = 0; intfnum < ARRAY_LENGTH(codec_interfaces); intfnum++)
+ if (codec_interfaces[intfnum].compression == header->compression)
+ break;
+ if (intfnum == ARRAY_LENGTH(codec_interfaces))
+ return CHDERR_INVALID_PARAMETER;
+
+ /* require a valid hunksize */
+ if (header->hunkbytes == 0 || header->hunkbytes >= 65536 * 256)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* require a valid hunk count */
+ if (header->totalhunks == 0)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* require a valid MD5 and/or SHA1 if we're using a parent */
+ if ((header->flags & CHDFLAGS_HAS_PARENT) && memcmp(header->parentmd5, nullmd5, sizeof(nullmd5)) == 0 && memcmp(header->parentsha1, nullsha1, sizeof(nullsha1)) == 0)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* if we're V3 or later, the obsolete fields must be 0 */
+ if (header->version >= 3 &&
+ (header->obsolete_cylinders != 0 || header->obsolete_sectors != 0 ||
+ header->obsolete_heads != 0 || header->obsolete_hunksize != 0))
+ return CHDERR_INVALID_PARAMETER;
+
+ /* if we're pre-V3, the obsolete fields must NOT be 0 */
+ if (header->version < 3 &&
+ (header->obsolete_cylinders == 0 || header->obsolete_sectors == 0 ||
+ header->obsolete_heads == 0 || header->obsolete_hunksize == 0))
+ return CHDERR_INVALID_PARAMETER;
+
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ header_read - read a CHD header into the
+ internal data structure
+-------------------------------------------------*/
+
+static chd_error header_read(core_file *file, chd_header *header)
+{
+ UINT8 rawheader[CHD_MAX_HEADER_SIZE];
+ UINT32 count;
+
+ /* punt if NULL */
+ if (!header)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* punt if invalid file */
+ if (!file)
+ return CHDERR_INVALID_FILE;
+
+ /* seek and read */
+ core_fseek(file, 0, SEEK_SET);
+ count = core_fread(file, rawheader, sizeof(rawheader));
+ if (count != sizeof(rawheader))
+ return CHDERR_READ_ERROR;
+
+ /* verify the tag */
+ if (strncmp((char *)rawheader, "MComprHD", 8) != 0)
+ return CHDERR_INVALID_DATA;
+
+ /* extract the direct data */
+ memset(header, 0, sizeof(*header));
+ header->length = get_bigendian_uint32(&rawheader[8]);
+ header->version = get_bigendian_uint32(&rawheader[12]);
+
+ /* make sure it's a version we understand */
+ if (header->version == 0 || header->version > CHD_HEADER_VERSION)
+ return CHDERR_UNSUPPORTED_VERSION;
+
+ /* make sure the length is expected */
+ if ((header->version == 1 && header->length != CHD_V1_HEADER_SIZE) ||
+ (header->version == 2 && header->length != CHD_V2_HEADER_SIZE) ||
+ (header->version == 3 && header->length != CHD_V3_HEADER_SIZE))
+ return CHDERR_INVALID_DATA;
+
+ /* extract the common data */
+ header->flags = get_bigendian_uint32(&rawheader[16]);
+ header->compression = get_bigendian_uint32(&rawheader[20]);
+ memcpy(header->md5, &rawheader[44], CHD_MD5_BYTES);
+ memcpy(header->parentmd5, &rawheader[60], CHD_MD5_BYTES);
+
+ /* extract the V1/V2-specific data */
+ if (header->version < 3)
+ {
+ int seclen = (header->version == 1) ? CHD_V1_SECTOR_SIZE : get_bigendian_uint32(&rawheader[76]);
+ header->obsolete_hunksize = get_bigendian_uint32(&rawheader[24]);
+ header->totalhunks = get_bigendian_uint32(&rawheader[28]);
+ header->obsolete_cylinders = get_bigendian_uint32(&rawheader[32]);
+ header->obsolete_heads = get_bigendian_uint32(&rawheader[36]);
+ header->obsolete_sectors = get_bigendian_uint32(&rawheader[40]);
+ header->logicalbytes = (UINT64)header->obsolete_cylinders * (UINT64)header->obsolete_heads * (UINT64)header->obsolete_sectors * (UINT64)seclen;
+ header->hunkbytes = seclen * header->obsolete_hunksize;
+ header->metaoffset = 0;
+ }
+
+ /* extract the V3-specific data */
+ else
+ {
+ header->totalhunks = get_bigendian_uint32(&rawheader[24]);
+ header->logicalbytes = get_bigendian_uint64(&rawheader[28]);
+ header->metaoffset = get_bigendian_uint64(&rawheader[36]);
+ header->hunkbytes = get_bigendian_uint32(&rawheader[76]);
+ memcpy(header->sha1, &rawheader[80], CHD_SHA1_BYTES);
+ memcpy(header->parentsha1, &rawheader[100], CHD_SHA1_BYTES);
+ }
+
+ /* guess it worked */
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ header_write - write a CHD header from the
+ internal data structure
+-------------------------------------------------*/
+
+static chd_error header_write(core_file *file, const chd_header *header)
+{
+ UINT8 rawheader[CHD_MAX_HEADER_SIZE];
+ UINT32 count;
+
+ /* punt if NULL */
+ if (!header)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* punt if invalid file */
+ if (!file)
+ return CHDERR_INVALID_FILE;
+
+ /* only support writing modern headers */
+ if (header->version != 3)
+ return CHDERR_INVALID_PARAMETER;
+
+ /* assemble the data */
+ memset(rawheader, 0, sizeof(rawheader));
+ memcpy(rawheader, "MComprHD", 8);
+
+ put_bigendian_uint32(&rawheader[8], CHD_V3_HEADER_SIZE);
+ put_bigendian_uint32(&rawheader[12], header->version);
+ put_bigendian_uint32(&rawheader[16], header->flags);
+ put_bigendian_uint32(&rawheader[20], header->compression);
+ put_bigendian_uint32(&rawheader[24], header->totalhunks);
+ put_bigendian_uint64(&rawheader[28], header->logicalbytes);
+ put_bigendian_uint64(&rawheader[36], header->metaoffset);
+ memcpy(&rawheader[44], header->md5, CHD_MD5_BYTES);
+ memcpy(&rawheader[60], header->parentmd5, CHD_MD5_BYTES);
+ put_bigendian_uint32(&rawheader[76], header->hunkbytes);
+ memcpy(&rawheader[80], header->sha1, CHD_SHA1_BYTES);
+ memcpy(&rawheader[100], header->parentsha1, CHD_SHA1_BYTES);
+
+ /* seek and write */
+ core_fseek(file, 0, SEEK_SET);
+ count = core_fwrite(file, rawheader, CHD_V3_HEADER_SIZE);
+ if (count != CHD_V3_HEADER_SIZE)
+ return CHDERR_WRITE_ERROR;
+
+ return CHDERR_NONE;
+}
+
+
+
+/***************************************************************************
+ INTERNAL HUNK READ/WRITE
+***************************************************************************/
+
+/*-------------------------------------------------
+ hunk_read_into_cache - read a hunk into
+ the CHD's hunk cache
+-------------------------------------------------*/
+
+static chd_error hunk_read_into_cache(chd_file *chd, UINT32 hunknum)
+{
+ chd_error err;
+
+ /* track the max */
+ if (hunknum > chd->maxhunk)
+ chd->maxhunk = hunknum;
+
+ /* if we're already in the cache, we're done */
+ if (chd->cachehunk == hunknum)
+ return CHDERR_NONE;
+ chd->cachehunk = ~0;
+
+ /* otherwise, read the data */
+ err = hunk_read_into_memory(chd, hunknum, chd->cache);
+ if (err != CHDERR_NONE)
+ return err;
+
+ /* mark the hunk successfully cached in */
+ chd->cachehunk = hunknum;
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ hunk_read_into_memory - read a hunk into
+ memory at the given location
+-------------------------------------------------*/
+
+static chd_error hunk_read_into_memory(chd_file *chd, UINT32 hunknum, UINT8 *dest)
+{
+ map_entry *entry = &chd->map[hunknum];
+ chd_error err;
+ UINT32 bytes;
+
+ /* return an error if out of range */
+ if (hunknum >= chd->header.totalhunks)
+ return CHDERR_HUNK_OUT_OF_RANGE;
+
+ /* switch off the entry type */
+ switch (entry->flags & MAP_ENTRY_FLAG_TYPE_MASK)
+ {
+ /* compressed data */
+ case MAP_ENTRY_TYPE_COMPRESSED:
+
+ /* read it into the decompression buffer */
+ core_fseek(chd->file, entry->offset, SEEK_SET);
+ bytes = core_fread(chd->file, chd->compressed, entry->length);
+ if (bytes != entry->length)
+ return CHDERR_READ_ERROR;
+
+ /* now decompress using the codec */
+ err = CHDERR_NONE;
+ if (chd->codecintf->decompress != NULL)
+ err = (*chd->codecintf->decompress)(chd, entry->length, dest);
+ if (err != CHDERR_NONE)
+ return err;
+ break;
+
+ /* uncompressed data */
+ case MAP_ENTRY_TYPE_UNCOMPRESSED:
+ core_fseek(chd->file, entry->offset, SEEK_SET);
+ bytes = core_fread(chd->file, dest, chd->header.hunkbytes);
+ if (bytes != chd->header.hunkbytes)
+ return CHDERR_READ_ERROR;
+ break;
+
+ /* mini-compressed data */
+ case MAP_ENTRY_TYPE_MINI:
+ put_bigendian_uint64(&dest[0], entry->offset);
+ for (bytes = 8; bytes < chd->header.hunkbytes; bytes++)
+ dest[bytes] = dest[bytes - 8];
+ break;
+
+ /* self-referenced data */
+ case MAP_ENTRY_TYPE_SELF_HUNK:
+ if (chd->cachehunk == entry->offset && dest == chd->cache)
+ break;
+ return hunk_read_into_memory(chd, entry->offset, dest);
+
+ /* parent-referenced data */
+ case MAP_ENTRY_TYPE_PARENT_HUNK:
+ err = hunk_read_into_memory(chd->parent, entry->offset, dest);
+ if (err != CHDERR_NONE)
+ return err;
+ break;
+ }
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ hunk_write_from_memory - write a hunk from
+ memory into a CHD
+-------------------------------------------------*/
+
+static chd_error hunk_write_from_memory(chd_file *chd, UINT32 hunknum, const UINT8 *src)
+{
+ map_entry *entry = &chd->map[hunknum];
+ map_entry newentry;
+ UINT8 fileentry[MAP_ENTRY_SIZE];
+ const void *data = src;
+ UINT32 bytes = 0, match;
+ chd_error err;
+
+ /* track the max */
+ if (hunknum > chd->maxhunk)
+ chd->maxhunk = hunknum;
+
+ /* first compute the CRC of the original data */
+ newentry.crc = crc32(0, &src[0], chd->header.hunkbytes);
+
+ /* if we're not a lossy codec, compute the CRC and look for matches */
+ if (!chd->codecintf->lossy)
+ {
+ /* some extra stuff for zlib+ compression */
+ if (chd->header.compression >= CHDCOMPRESSION_ZLIB_PLUS)
+ {
+ /* see if we can mini-compress first */
+ for (bytes = 8; bytes < chd->header.hunkbytes; bytes++)
+ if (src[bytes] != src[bytes - 8])
+ break;
+
+ /* if so, we don't need to write any data */
+ if (bytes == chd->header.hunkbytes)
+ {
+ newentry.offset = get_bigendian_uint64(&src[0]);
+ newentry.length = 0;
+ newentry.flags = MAP_ENTRY_TYPE_MINI;
+ goto write_entry;
+ }
+
+ /* otherwise, see if we can find a match in the current file */
+ match = crcmap_find_hunk(chd, hunknum, newentry.crc, &src[0]);
+ if (match != NO_MATCH)
+ {
+ newentry.offset = match;
+ newentry.length = 0;
+ newentry.flags = MAP_ENTRY_TYPE_SELF_HUNK;
+ goto write_entry;
+ }
+
+ /* if we have a parent, see if we can find a match in there */
+ if (chd->header.flags & CHDFLAGS_HAS_PARENT)
+ {
+ match = crcmap_find_hunk(chd->parent, ~0, newentry.crc, &src[0]);
+ if (match != NO_MATCH)
+ {
+ newentry.offset = match;
+ newentry.length = 0;
+ newentry.flags = MAP_ENTRY_TYPE_PARENT_HUNK;
+ goto write_entry;
+ }
+ }
+ }
+ }
+
+ /* now try compressing the data */
+ err = CHDERR_COMPRESSION_ERROR;
+ if (chd->codecintf->compress != NULL)
+ err = (*chd->codecintf->compress)(chd, src, &bytes);
+
+ /* if that worked, and we're lossy, decompress and CRC the result */
+ if (err == CHDERR_NONE && chd->codecintf->lossy)
+ {
+ err = (*chd->codecintf->decompress)(chd, bytes, chd->cache);
+ if (err == CHDERR_NONE)
+ newentry.crc = crc32(0, chd->cache, chd->header.hunkbytes);
+ }
+
+ /* if we succeeded in compressing the data, replace our data pointer and mark it so */
+ if (err == CHDERR_NONE)
+ {
+ data = chd->compressed;
+ newentry.length = bytes;
+ newentry.flags = MAP_ENTRY_TYPE_COMPRESSED;
+ }
+
+ /* otherwise, mark it uncompressed and use the original data */
+ else
+ {
+ newentry.length = chd->header.hunkbytes;
+ newentry.flags = MAP_ENTRY_TYPE_UNCOMPRESSED;
+ }
+
+ /* if the data doesn't fit into the previous entry, make a new one at the eof */
+ newentry.offset = entry->offset;
+ if (newentry.offset == 0 || newentry.length > entry->length)
+ newentry.offset = core_fsize(chd->file);
+
+ /* write the data */
+ core_fseek(chd->file, newentry.offset, SEEK_SET);
+ bytes = core_fwrite(chd->file, data, newentry.length);
+ if (bytes != newentry.length)
+ return CHDERR_WRITE_ERROR;
+
+ /* update the entry in memory */
+write_entry:
+ *entry = newentry;
+
+ /* update the map on file */
+ map_assemble(&fileentry[0], &chd->map[hunknum]);
+ core_fseek(chd->file, chd->header.length + hunknum * sizeof(fileentry), SEEK_SET);
+ bytes = core_fwrite(chd->file, &fileentry[0], sizeof(fileentry));
+ if (bytes != sizeof(fileentry))
+ return CHDERR_WRITE_ERROR;
+
+ return CHDERR_NONE;
+}
+
+
+
+/***************************************************************************
+ INTERNAL MAP ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+ map_write_initial - write an initial map to
+ a new CHD file
+-------------------------------------------------*/
+
+static chd_error map_write_initial(core_file *file, chd_file *parent, const chd_header *header)
+{
+ UINT8 blank_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE];
+ int fullchunks, remainder, count, i, j;
+ map_entry mapentry;
+ UINT64 fileoffset;
+
+ /* create a mini hunk of 0's */
+ mapentry.offset = 0;
+ mapentry.crc = 0;
+ mapentry.length = 0;
+ mapentry.flags = MAP_ENTRY_TYPE_MINI | MAP_ENTRY_FLAG_NO_CRC;
+ for (i = 0; i < MAP_STACK_ENTRIES; i++)
+ map_assemble(&blank_map_entries[i * MAP_ENTRY_SIZE], &mapentry);
+
+ /* prepare to write a blank hunk map immediately following */
+ fileoffset = header->length;
+ fullchunks = header->totalhunks / MAP_STACK_ENTRIES;
+ remainder = header->totalhunks % MAP_STACK_ENTRIES;
+
+ /* first write full chunks of blank entries */
+ for (i = 0; i < fullchunks; i++)
+ {
+ /* parent drives need to be mapped through */
+ if (parent != NULL)
+ for (j = 0; j < MAP_STACK_ENTRIES; j++)
+ {
+ mapentry.offset = i * MAP_STACK_ENTRIES + j;
+ mapentry.crc = parent->map[i * MAP_STACK_ENTRIES + j].crc;
+ mapentry.flags = MAP_ENTRY_TYPE_PARENT_HUNK;
+ map_assemble(&blank_map_entries[j * MAP_ENTRY_SIZE], &mapentry);
+ }
+
+ /* write the chunks */
+ core_fseek(file, fileoffset, SEEK_SET);
+ count = core_fwrite(file, blank_map_entries, sizeof(blank_map_entries));
+ if (count != sizeof(blank_map_entries))
+ return CHDERR_WRITE_ERROR;
+ fileoffset += sizeof(blank_map_entries);
+ }
+
+ /* then write the remainder */
+ if (remainder > 0)
+ {
+ /* parent drives need to be mapped through */
+ if (parent != NULL)
+ for (j = 0; j < remainder; j++)
+ {
+ mapentry.offset = i * MAP_STACK_ENTRIES + j;
+ mapentry.crc = parent->map[i * MAP_STACK_ENTRIES + j].crc;
+ mapentry.flags = MAP_ENTRY_TYPE_PARENT_HUNK;
+ map_assemble(&blank_map_entries[j * MAP_ENTRY_SIZE], &mapentry);
+ }
+
+ /* write the chunks */
+ core_fseek(file, fileoffset, SEEK_SET);
+ count = core_fwrite(file, blank_map_entries, remainder * MAP_ENTRY_SIZE);
+ if (count != remainder * MAP_ENTRY_SIZE)
+ return CHDERR_WRITE_ERROR;
+ fileoffset += remainder * MAP_ENTRY_SIZE;
+ }
+
+ /* then write a special end-of-list cookie */
+ memcpy(&blank_map_entries[0], END_OF_LIST_COOKIE, MAP_ENTRY_SIZE);
+ core_fseek(file, fileoffset, SEEK_SET);
+ count = core_fwrite(file, blank_map_entries, MAP_ENTRY_SIZE);
+ if (count != MAP_ENTRY_SIZE)
+ return CHDERR_WRITE_ERROR;
+
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ map_read - read the initial sector map
+-------------------------------------------------*/
+
+static chd_error map_read(chd_file *chd)
+{
+ UINT32 entrysize = (chd->header.version < 3) ? OLD_MAP_ENTRY_SIZE : MAP_ENTRY_SIZE;
+ UINT8 raw_map_entries[MAP_STACK_ENTRIES * MAP_ENTRY_SIZE];
+ UINT64 fileoffset, maxoffset = 0;
+ UINT8 cookie[MAP_ENTRY_SIZE];
+ UINT32 count;
+ int i, err;
+
+ /* first allocate memory */
+ chd->map = malloc(sizeof(chd->map[0]) * chd->header.totalhunks);
+ if (!chd->map)
+ return CHDERR_OUT_OF_MEMORY;
+
+ /* read the map entries in in chunks and extract to the map list */
+ fileoffset = chd->header.length;
+ for (i = 0; i < chd->header.totalhunks; i += MAP_STACK_ENTRIES)
+ {
+ /* compute how many entries this time */
+ int entries = chd->header.totalhunks - i, j;
+ if (entries > MAP_STACK_ENTRIES)
+ entries = MAP_STACK_ENTRIES;
+
+ /* read that many */
+ core_fseek(chd->file, fileoffset, SEEK_SET);
+ count = core_fread(chd->file, raw_map_entries, entries * entrysize);
+ if (count != entries * entrysize)
+ {
+ err = CHDERR_READ_ERROR;
+ goto cleanup;
+ }
+ fileoffset += entries * entrysize;
+
+ /* process that many */
+ if (entrysize == MAP_ENTRY_SIZE)
+ {
+ for (j = 0; j < entries; j++)
+ map_extract(&raw_map_entries[j * MAP_ENTRY_SIZE], &chd->map[i + j]);
+ }
+ else
+ {
+ for (j = 0; j < entries; j++)
+ map_extract_old(&raw_map_entries[j * OLD_MAP_ENTRY_SIZE], &chd->map[i + j], chd->header.hunkbytes);
+ }
+
+ /* track the maximum offset */
+ for (j = 0; j < entries; j++)
+ if ((chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == MAP_ENTRY_TYPE_COMPRESSED ||
+ (chd->map[i + j].flags & MAP_ENTRY_FLAG_TYPE_MASK) == MAP_ENTRY_TYPE_UNCOMPRESSED)
+ maxoffset = MAX(maxoffset, chd->map[i + j].offset + chd->map[i + j].length);
+ }
+
+ /* verify the cookie */
+ core_fseek(chd->file, fileoffset, SEEK_SET);
+ count = core_fread(chd->file, &cookie, entrysize);
+ if (count != entrysize || memcmp(&cookie, END_OF_LIST_COOKIE, entrysize))
+ {
+ err = CHDERR_INVALID_FILE;
+ goto cleanup;
+ }
+
+ /* verify the length */
+ if (maxoffset > core_fsize(chd->file))
+ {
+ err = CHDERR_INVALID_FILE;
+ goto cleanup;
+ }
+ return CHDERR_NONE;
+
+cleanup:
+ if (chd->map)
+ free(chd->map);
+ chd->map = NULL;
+ return err;
+}
+
+
+
+/***************************************************************************
+ INTERNAL CRC MAP ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+ crcmap_init - initialize the CRC map
+-------------------------------------------------*/
+
+static void crcmap_init(chd_file *chd, int prepopulate)
+{
+ int i;
+
+ /* if we already have one, bail */
+ if (chd->crcmap != NULL)
+ return;
+
+ /* reset all pointers */
+ chd->crcmap = NULL;
+ chd->crcfree = NULL;
+ chd->crctable = NULL;
+
+ /* allocate a list; one for each hunk */
+ chd->crcmap = malloc(chd->header.totalhunks * sizeof(chd->crcmap[0]));
+ if (chd->crcmap == NULL)
+ return;
+
+ /* allocate a CRC map table */
+ chd->crctable = malloc(CRCMAP_HASH_SIZE * sizeof(chd->crctable[0]));
+ if (chd->crctable == NULL)
+ {
+ free(chd->crcmap);
+ chd->crcmap = NULL;
+ return;
+ }
+
+ /* initialize the free list */
+ for (i = 0; i < chd->header.totalhunks; i++)
+ {
+ chd->crcmap[i].next = chd->crcfree;
+ chd->crcfree = &chd->crcmap[i];
+ }
+
+ /* initialize the table */
+ memset(chd->crctable, 0, CRCMAP_HASH_SIZE * sizeof(chd->crctable[0]));
+
+ /* if we're to prepopulate, go for it */
+ if (prepopulate)
+ for (i = 0; i < chd->header.totalhunks; i++)
+ crcmap_add_entry(chd, i);
+}
+
+
+/*-------------------------------------------------
+ crcmap_add_entry - log a CRC entry
+-------------------------------------------------*/
+
+static void crcmap_add_entry(chd_file *chd, UINT32 hunknum)
+{
+ UINT32 hash = chd->map[hunknum].crc % CRCMAP_HASH_SIZE;
+ crcmap_entry *crcmap;
+
+ /* pull a free entry off the list */
+ crcmap = chd->crcfree;
+ chd->crcfree = crcmap->next;
+
+ /* set up the entry and link it into the hash table */
+ crcmap->hunknum = hunknum;
+ crcmap->next = chd->crctable[hash];
+ chd->crctable[hash] = crcmap;
+}
+
+
+/*-------------------------------------------------
+ crcmap_verify_hunk_match - verify that a
+ hunk really matches by doing a byte-for-byte
+ compare
+-------------------------------------------------*/
+
+static int crcmap_verify_hunk_match(chd_file *chd, UINT32 hunknum, const UINT8 *rawdata)
+{
+ /* we have a potential match -- better be sure */
+ /* read the hunk from disk and compare byte-for-byte */
+ if (hunknum != chd->comparehunk)
+ {
+ chd->comparehunk = ~0;
+ if (hunk_read_into_memory(chd, hunknum, chd->compare) == CHDERR_NONE)
+ chd->comparehunk = hunknum;
+ }
+ return (hunknum == chd->comparehunk && memcmp(rawdata, chd->compare, chd->header.hunkbytes) == 0);
+}
+
+
+/*-------------------------------------------------
+ crcmap_find_hunk - find a hunk with a matching
+ CRC in the map
+-------------------------------------------------*/
+
+static UINT32 crcmap_find_hunk(chd_file *chd, UINT32 hunknum, UINT32 crc, const UINT8 *rawdata)
+{
+ UINT32 lasthunk = (hunknum < chd->header.totalhunks) ? hunknum : chd->header.totalhunks;
+ int curhunk;
+
+ /* if we have a CRC map, use that */
+ if (chd->crctable)
+ {
+ crcmap_entry *curentry;
+ for (curentry = chd->crctable[crc % CRCMAP_HASH_SIZE]; curentry; curentry = curentry->next)
+ {
+ curhunk = curentry->hunknum;
+ if (chd->map[curhunk].crc == crc && !(chd->map[curhunk].flags & MAP_ENTRY_FLAG_NO_CRC) && crcmap_verify_hunk_match(chd, curhunk, rawdata))
+ return curhunk;
+ }
+ return NO_MATCH;
+ }
+
+ /* first see if the last match is a valid one */
+ if (chd->comparehunk < chd->header.totalhunks && chd->map[chd->comparehunk].crc == crc && !(chd->map[chd->comparehunk].flags & MAP_ENTRY_FLAG_NO_CRC) &&
+ memcmp(rawdata, chd->compare, chd->header.hunkbytes) == 0)
+ return chd->comparehunk;
+
+ /* scan through the CHD's hunk map looking for a match */
+ for (curhunk = 0; curhunk < lasthunk; curhunk++)
+ if (chd->map[curhunk].crc == crc && !(chd->map[curhunk].flags & MAP_ENTRY_FLAG_NO_CRC) && crcmap_verify_hunk_match(chd, curhunk, rawdata))
+ return curhunk;
+
+ return NO_MATCH;
+}
+
+
+
+/***************************************************************************
+ INTERNAL METADATA ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+ metadata_find_entry - find a metadata entry
+-------------------------------------------------*/
+
+static chd_error metadata_find_entry(chd_file *chd, UINT32 metatag, UINT32 metaindex, metadata_entry *metaentry)
+{
+ /* start at the beginning */
+ metaentry->offset = chd->header.metaoffset;
+ metaentry->prev = 0;
+
+ /* loop until we run out of options */
+ while (metaentry->offset != 0)
+ {
+ UINT8 raw_meta_header[METADATA_HEADER_SIZE];
+ UINT32 count;
+
+ /* read the raw header */
+ core_fseek(chd->file, metaentry->offset, SEEK_SET);
+ count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));
+ if (count != sizeof(raw_meta_header))
+ break;
+
+ /* extract the data */
+ metaentry->metatag = get_bigendian_uint32(&raw_meta_header[0]);
+ metaentry->length = get_bigendian_uint32(&raw_meta_header[4]);
+ metaentry->next = get_bigendian_uint64(&raw_meta_header[8]);
+
+ /* if we got a match, proceed */
+ if (metatag == CHDMETATAG_WILDCARD || metaentry->metatag == metatag)
+ if (metaindex-- == 0)
+ return CHDERR_NONE;
+
+ /* no match, fetch the next link */
+ metaentry->prev = metaentry->offset;
+ metaentry->offset = metaentry->next;
+ }
+
+ /* if we get here, we didn't find it */
+ return CHDERR_METADATA_NOT_FOUND;
+}
+
+
+/*-------------------------------------------------
+ metadata_set_previous_next - set the 'next'
+ offset of a piece of metadata
+-------------------------------------------------*/
+
+static chd_error metadata_set_previous_next(chd_file *chd, UINT64 prevoffset, UINT64 nextoffset)
+{
+ UINT8 raw_meta_header[METADATA_HEADER_SIZE];
+ chd_error err;
+ UINT32 count;
+
+ /* if we were the first entry, make the next entry the first */
+ if (prevoffset == 0)
+ {
+ chd->header.metaoffset = nextoffset;
+ err = header_write(chd->file, &chd->header);
+ if (err != CHDERR_NONE)
+ return err;
+ }
+
+ /* otherwise, update the link in the previous pointer */
+ else
+ {
+ /* read the previous raw header */
+ core_fseek(chd->file, prevoffset, SEEK_SET);
+ count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));
+ if (count != sizeof(raw_meta_header))
+ return CHDERR_READ_ERROR;
+
+ /* copy our next pointer into the previous->next offset */
+ put_bigendian_uint64(&raw_meta_header[8], nextoffset);
+
+ /* write the previous raw header */
+ core_fseek(chd->file, prevoffset, SEEK_SET);
+ count = core_fwrite(chd->file, raw_meta_header, sizeof(raw_meta_header));
+ if (count != sizeof(raw_meta_header))
+ return CHDERR_WRITE_ERROR;
+ }
+
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ metadata_set_length - set the length field of
+ a piece of metadata
+-------------------------------------------------*/
+
+static chd_error metadata_set_length(chd_file *chd, UINT64 offset, UINT32 length)
+{
+ UINT8 raw_meta_header[METADATA_HEADER_SIZE];
+ UINT32 count;
+
+ /* read the raw header */
+ core_fseek(chd->file, offset, SEEK_SET);
+ count = core_fread(chd->file, raw_meta_header, sizeof(raw_meta_header));
+ if (count != sizeof(raw_meta_header))
+ return CHDERR_READ_ERROR;
+
+ /* update the length at offset 4 */
+ put_bigendian_uint32(&raw_meta_header[4], length);
+
+ /* write the raw header */
+ core_fseek(chd->file, offset, SEEK_SET);
+ count = core_fwrite(chd->file, raw_meta_header, sizeof(raw_meta_header));
+ if (count != sizeof(raw_meta_header))
+ return CHDERR_WRITE_ERROR;
+
+ return CHDERR_NONE;
+}
+
+
+
+/***************************************************************************
+ ZLIB COMPRESSION CODEC
+***************************************************************************/
+
+/*-------------------------------------------------
+ zlib_codec_init - initialize the ZLIB codec
+-------------------------------------------------*/
+
+static chd_error zlib_codec_init(chd_file *chd)
+{
+ zlib_codec_data *data;
+ chd_error err;
+ int zerr;
+
+ /* allocate memory for the 2 stream buffers */
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return CHDERR_OUT_OF_MEMORY;
+
+ /* clear the buffers */
+ memset(data, 0, sizeof(*data));
+
+ /* init the inflater first */
+ data->inflater.next_in = (Bytef *)data; /* bogus, but that's ok */
+ data->inflater.avail_in = 0;
+ data->inflater.zalloc = zlib_fast_alloc;
+ data->inflater.zfree = zlib_fast_free;
+ data->inflater.opaque = data;
+ zerr = inflateInit2(&data->inflater, -MAX_WBITS);
+
+ /* if that worked, initialize the deflater */
+ if (zerr == Z_OK)
+ {
+ data->deflater.next_in = (Bytef *)data; /* bogus, but that's ok */
+ data->deflater.avail_in = 0;
+ data->deflater.zalloc = zlib_fast_alloc;
+ data->deflater.zfree = zlib_fast_free;
+ data->deflater.opaque = data;
+ zerr = deflateInit2(&data->deflater, Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
+ }
+
+ /* convert errors */
+ if (zerr == Z_MEM_ERROR)
+ err = CHDERR_OUT_OF_MEMORY;
+ else if (zerr != Z_OK)
+ err = CHDERR_CODEC_ERROR;
+ else
+ err = CHDERR_NONE;
+
+ /* handle an error */
+ if (err == CHDERR_NONE)
+ chd->codecdata = data;
+ else
+ free(data);
+
+ return err;
+}
+
+
+/*-------------------------------------------------
+ zlib_codec_free - free data for the ZLIB
+ codec
+-------------------------------------------------*/
+
+static void zlib_codec_free(chd_file *chd)
+{
+ zlib_codec_data *data = chd->codecdata;
+
+ /* deinit the streams */
+ if (data != NULL)
+ {
+ int i;
+
+ inflateEnd(&data->inflater);
+ deflateEnd(&data->deflater);
+
+ /* free our fast memory */
+ for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
+ if (data->allocptr[i])
+ free(data->allocptr[i]);
+ free(data);
+ }
+}
+
+
+/*-------------------------------------------------
+ zlib_codec_compress - compress data using the
+ ZLIB codec
+-------------------------------------------------*/
+
+static chd_error zlib_codec_compress(chd_file *chd, const void *src, UINT32 *length)
+{
+ zlib_codec_data *data = chd->codecdata;
+ int zerr;
+
+ /* reset the decompressor */
+ data->deflater.next_in = (void *)src;
+ data->deflater.avail_in = chd->header.hunkbytes;
+ data->deflater.total_in = 0;
+ data->deflater.next_out = chd->compressed;
+ data->deflater.avail_out = chd->header.hunkbytes;
+ data->deflater.total_out = 0;
+ zerr = deflateReset(&data->deflater);
+ if (zerr != Z_OK)
+ return CHDERR_COMPRESSION_ERROR;
+
+ /* do it */
+ zerr = deflate(&data->deflater, Z_FINISH);
+
+ /* if we ended up with more data than we started with, return an error */
+ if (zerr != Z_STREAM_END || data->deflater.total_out >= chd->header.hunkbytes)
+ return CHDERR_COMPRESSION_ERROR;
+
+ /* otherwise, fill in the length and return success */
+ *length = data->deflater.total_out;
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ zlib_codec_decompress - decomrpess data using
+ the ZLIB codec
+-------------------------------------------------*/
+
+static chd_error zlib_codec_decompress(chd_file *chd, UINT32 srclength, void *dest)
+{
+ zlib_codec_data *data = chd->codecdata;
+ int zerr;
+
+ /* reset the decompressor */
+ data->inflater.next_in = chd->compressed;
+ data->inflater.avail_in = srclength;
+ data->inflater.total_in = 0;
+ data->inflater.next_out = dest;
+ data->inflater.avail_out = chd->header.hunkbytes;
+ data->inflater.total_out = 0;
+ zerr = inflateReset(&data->inflater);
+ if (zerr != Z_OK)
+ return CHDERR_DECOMPRESSION_ERROR;
+
+ /* do it */
+ zerr = inflate(&data->inflater, Z_FINISH);
+ if (data->inflater.total_out != chd->header.hunkbytes)
+ return CHDERR_DECOMPRESSION_ERROR;
+
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ zlib_fast_alloc - fast malloc for ZLIB, which
+ allocates and frees memory frequently
+-------------------------------------------------*/
+
+static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
+{
+ zlib_codec_data *data = opaque;
+ UINT32 *ptr;
+ int i;
+
+ /* compute the size, rounding to the nearest 1k */
+ size = (size * items + 0x3ff) & ~0x3ff;
+
+ /* reuse a hunk if we can */
+ for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
+ {
+ ptr = data->allocptr[i];
+ if (ptr && size == *ptr)
+ {
+ /* set the low bit of the size so we don't match next time */
+ *ptr |= 1;
+ return ptr + 1;
+ }
+ }
+
+ /* alloc a new one */
+ ptr = malloc(size + sizeof(UINT32));
+ if (!ptr)
+ return NULL;
+
+ /* put it into the list */
+ for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
+ if (!data->allocptr[i])
+ {
+ data->allocptr[i] = ptr;
+ break;
+ }
+
+ /* set the low bit of the size so we don't match next time */
+ *ptr = size | 1;
+ return ptr + 1;
+}
+
+
+/*-------------------------------------------------
+ zlib_fast_free - fast free for ZLIB, which
+ allocates and frees memory frequently
+-------------------------------------------------*/
+
+static void zlib_fast_free(voidpf opaque, voidpf address)
+{
+ zlib_codec_data *data = opaque;
+ UINT32 *ptr = (UINT32 *)address - 1;
+ int i;
+
+ /* find the hunk */
+ for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
+ if (ptr == data->allocptr[i])
+ {
+ /* clear the low bit of the size to allow matches */
+ *ptr &= ~1;
+ return;
+ }
+}
+
+
+
+/***************************************************************************
+ AV COMPRESSION CODEC
+***************************************************************************/
+
+/*-------------------------------------------------
+ av_raw_data_size - compute the raw data size
+-------------------------------------------------*/
+
+INLINE UINT32 av_raw_data_size(const UINT8 *data)
+{
+ int size = 0;
+
+ /* make sure we have a correct header */
+ if (data[0] == 'c' && data[1] == 'h' && data[2] == 'a' && data[3] == 'v')
+ {
+ /* add in header size plus metadata length */
+ size = 12 + data[4];
+
+ /* add in channels * samples */
+ size += 2 * data[5] * ((data[6] << 8) + data[7]);
+
+ /* add in 2 * width * height */
+ size += 2 * ((data[8] << 8) + data[9]) * (((data[10] << 8) + data[11]) & 0x7fff);
+ }
+ return size;
+}
+
+
+/*-------------------------------------------------
+ av_codec_init - initialize the A/V codec
+-------------------------------------------------*/
+
+static chd_error av_codec_init(chd_file *chd)
+{
+ av_codec_data *data;
+
+ /* allocate memory for the 2 stream buffers */
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return CHDERR_OUT_OF_MEMORY;
+
+ /* clear the buffers */
+ memset(data, 0, sizeof(*data));
+ chd->codecdata = data;
+
+ /* set up the default decompression configuration */
+ data->decompconfig.decode_mask = AVCOMP_DECODE_DEFAULT;
+
+ /* attempt to do a post-init now; if we're creating a new CHD, this won't work */
+ /* but that's ok */
+ av_codec_postinit(chd);
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ av_codec_free - free data for the A/V
+ codec
+-------------------------------------------------*/
+
+static void av_codec_free(chd_file *chd)
+{
+ av_codec_data *data = chd->codecdata;
+
+ /* deinit avcomp */
+ if (data != NULL)
+ {
+ if (data->compstate != NULL)
+ avcomp_free(data->compstate);
+ free(data);
+ }
+}
+
+
+/*-------------------------------------------------
+ av_codec_compress - compress data using the
+ A/V codec
+-------------------------------------------------*/
+
+static chd_error av_codec_compress(chd_file *chd, const void *src, UINT32 *length)
+{
+ av_codec_data *data = chd->codecdata;
+ int averr;
+ int size;
+
+ /* if we haven't yet set up the avcomp code, do it now */
+ if (data->compstate == NULL)
+ {
+ chd_error chderr = av_codec_postinit(chd);
+ if (chderr != CHDERR_NONE)
+ return chderr;
+ }
+
+ /* make sure short frames are padded with 0 */
+ size = av_raw_data_size(src);
+ while (size < chd->header.hunkbytes)
+ if (((const UINT8 *)src)[size++] != 0)
+ return CHDERR_INVALID_DATA;
+
+ /* encode the audio and video */
+ averr = avcomp_encode_data(data->compstate, src, chd->compressed, length);
+ if (averr != AVCERR_NONE || *length > chd->header.hunkbytes)
+ return CHDERR_COMPRESSION_ERROR;
+
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ av_codec_decompress - decomrpess data using
+ the A/V codec
+-------------------------------------------------*/
+
+static chd_error av_codec_decompress(chd_file *chd, UINT32 srclength, void *dest)
+{
+ av_codec_data *data = chd->codecdata;
+ const UINT8 *source;
+ avcomp_error averr;
+ int size;
+
+ /* if we haven't yet set up the avcomp code, do it now */
+ if (data->compstate == NULL)
+ {
+ chd_error chderr = av_codec_postinit(chd);
+ if (chderr != CHDERR_NONE)
+ return chderr;
+ }
+
+ /* decode the audio and video */
+ source = chd->compressed;
+ averr = avcomp_decode_data(data->compstate, source, srclength, dest);
+ if (averr != AVCERR_NONE)
+ return CHDERR_DECOMPRESSION_ERROR;
+
+ /* pad short frames with 0 */
+ size = av_raw_data_size(dest);
+ while (size < chd->header.hunkbytes)
+ ((UINT8 *)dest)[size++] = 0;
+
+ return CHDERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ av_codec_config - codec-specific configuration
+ for the A/V codec
+-------------------------------------------------*/
+
+static chd_error av_codec_config(chd_file *chd, int param, void *config)
+{
+ av_codec_data *data = chd->codecdata;
+
+ /* if we're getting the decompression configuration, apply it now */
+ if (param == AV_CODEC_DECOMPRESS_CONFIG)
+ {
+ data->decompconfig = *(av_codec_decompress_config *)config;
+ if (data->compstate != NULL)
+ avcomp_decompress_config(data->compstate, data->decompconfig.decode_mask, data->decompconfig.video_buffer, data->decompconfig.video_stride, data->decompconfig.video_xor, data->decompconfig.audio_xor);
+ return CHDERR_NONE;
+ }
+
+ /* anything else is invalid */
+ return CHDERR_INVALID_PARAMETER;
+}
+
+
+/*-------------------------------------------------
+ av_codec_postinit - actual initialization of
+ avcomp happens here, on the first attempt
+ to compress or decompress data
+-------------------------------------------------*/
+
+static chd_error av_codec_postinit(chd_file *chd)
+{
+ int fps, fpsfrac, width, height, interlaced, channels, rate, metabytes;
+ UINT32 fps_times_1million, max_samples_per_frame, bytes_per_frame;
+ av_codec_data *data = chd->codecdata;
+ char metadata[256];
+ chd_error err;
+
+ /* the code below won't work asynchronously */
+ if (chd->workitem != NULL)
+ return CHDERR_OPERATION_PENDING;
+
+ /* get the metadata */
+ err = chd_get_metadata(chd, AV_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL);
+ if (err != CHDERR_NONE)
+ return err;
+
+ /* extract the info */
+ if (sscanf(metadata, AV_METADATA_FORMAT, &fps, &fpsfrac, &width, &height, &interlaced, &channels, &rate, &metabytes) != 8)
+ return CHDERR_INVALID_METADATA;
+
+ /* compute the bytes per frame */
+ fps_times_1million = fps * 1000000 + fpsfrac;
+ max_samples_per_frame = ((UINT64)rate * 1000000 + fps_times_1million - 1) / fps_times_1million;
+ bytes_per_frame = 12 + metabytes + channels * max_samples_per_frame * 2 + width * height * 2;
+ if (bytes_per_frame > chd->header.hunkbytes)
+ return CHDERR_INVALID_METADATA;
+
+ /* create the avcomp state */
+ data->compstate = avcomp_init(width, height, channels);
+
+ /* configure the codec */
+ avcomp_decompress_config(data->compstate, data->decompconfig.decode_mask, data->decompconfig.video_buffer, data->decompconfig.video_stride, data->decompconfig.video_xor, data->decompconfig.audio_xor);
+ return CHDERR_NONE;
+}
diff --git a/src/lib/util/chd.h b/src/lib/util/chd.h
new file mode 100644
index 00000000000..dd549cd76ca
--- /dev/null
+++ b/src/lib/util/chd.h
@@ -0,0 +1,325 @@
+/***************************************************************************
+
+ MAME Compressed Hunks of Data file format
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CHD_H__
+#define __CHD_H__
+
+#include "osdcore.h"
+#include "corefile.h"
+
+
+/***************************************************************************
+
+ Compressed Hunks of Data header format. All numbers are stored in
+ Motorola (big-endian) byte ordering. The header is 76 (V1) or 80 (V2)
+ bytes long.
+
+ V1 header:
+
+ [ 0] char tag[8]; // 'MComprHD'
+ [ 8] UINT32 length; // length of header (including tag and length fields)
+ [ 12] UINT32 version; // drive format version
+ [ 16] UINT32 flags; // flags (see below)
+ [ 20] UINT32 compression; // compression type
+ [ 24] UINT32 hunksize; // 512-byte sectors per hunk
+ [ 28] UINT32 totalhunks; // total # of hunks represented
+ [ 32] UINT32 cylinders; // number of cylinders on hard disk
+ [ 36] UINT32 heads; // number of heads on hard disk
+ [ 40] UINT32 sectors; // number of sectors on hard disk
+ [ 44] UINT8 md5[16]; // MD5 checksum of raw data
+ [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file
+ [ 76] (V1 header length)
+
+ V2 header:
+
+ [ 0] char tag[8]; // 'MComprHD'
+ [ 8] UINT32 length; // length of header (including tag and length fields)
+ [ 12] UINT32 version; // drive format version
+ [ 16] UINT32 flags; // flags (see below)
+ [ 20] UINT32 compression; // compression type
+ [ 24] UINT32 hunksize; // seclen-byte sectors per hunk
+ [ 28] UINT32 totalhunks; // total # of hunks represented
+ [ 32] UINT32 cylinders; // number of cylinders on hard disk
+ [ 36] UINT32 heads; // number of heads on hard disk
+ [ 40] UINT32 sectors; // number of sectors on hard disk
+ [ 44] UINT8 md5[16]; // MD5 checksum of raw data
+ [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file
+ [ 76] UINT32 seclen; // number of bytes per sector
+ [ 80] (V2 header length)
+
+ V3 header:
+
+ [ 0] char tag[8]; // 'MComprHD'
+ [ 8] UINT32 length; // length of header (including tag and length fields)
+ [ 12] UINT32 version; // drive format version
+ [ 16] UINT32 flags; // flags (see below)
+ [ 20] UINT32 compression; // compression type
+ [ 24] UINT32 totalhunks; // total # of hunks represented
+ [ 28] UINT64 logicalbytes; // logical size of the data (in bytes)
+ [ 36] UINT64 metaoffset; // offset to the first blob of metadata
+ [ 44] UINT8 md5[16]; // MD5 checksum of raw data
+ [ 60] UINT8 parentmd5[16]; // MD5 checksum of parent file
+ [ 76] UINT32 hunkbytes; // number of bytes per hunk
+ [ 80] UINT8 sha1[20]; // SHA1 checksum of raw data
+ [100] UINT8 parentsha1[20];// SHA1 checksum of parent file
+ [120] (V3 header length)
+
+ Flags:
+ 0x00000001 - set if this drive has a parent
+ 0x00000002 - set if this drive allows writes
+
+***************************************************************************/
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* header information */
+#define CHD_HEADER_VERSION 3
+#define CHD_V1_HEADER_SIZE 76
+#define CHD_V2_HEADER_SIZE 80
+#define CHD_V3_HEADER_SIZE 120
+#define CHD_MAX_HEADER_SIZE CHD_V3_HEADER_SIZE
+
+/* checksumming information */
+#define CHD_MD5_BYTES 16
+#define CHD_SHA1_BYTES 20
+
+/* CHD global flags */
+#define CHDFLAGS_HAS_PARENT 0x00000001
+#define CHDFLAGS_IS_WRITEABLE 0x00000002
+#define CHDFLAGS_UNDEFINED 0xfffffffc
+
+/* compression types */
+#define CHDCOMPRESSION_NONE 0
+#define CHDCOMPRESSION_ZLIB 1
+#define CHDCOMPRESSION_ZLIB_PLUS 2
+#define CHDCOMPRESSION_AV 3
+
+/* A/V codec configuration parameters */
+#define AV_CODEC_COMPRESS_CONFIG 0
+#define AV_CODEC_DECOMPRESS_CONFIG 1
+
+/* metadata parameters */
+#define CHDMETATAG_WILDCARD 0
+#define CHD_METAINDEX_APPEND ((UINT32)-1)
+
+/* standard hard disk metadata */
+#define HARD_DISK_METADATA_TAG 0x47444444 /* 'GDDD' */
+#define HARD_DISK_METADATA_FORMAT "CYLS:%d,HEADS:%d,SECS:%d,BPS:%d"
+
+/* standard CD-ROM metadata */
+#define CDROM_OLD_METADATA_TAG 0x43484344 /* 'CHCD' */
+#define CDROM_TRACK_METADATA_TAG 0x43485452 /* 'CHTR' */
+#define CDROM_TRACK_METADATA_FORMAT "TRACK:%d TYPE:%s SUBTYPE:%s FRAMES:%d"
+
+/* standard A/V metadata */
+#define AV_METADATA_TAG 0x41564156 /* 'AVAV' */
+#define AV_METADATA_FORMAT "FPS:%d.%06d WIDTH:%d HEIGHT:%d INTERLACED:%d CHANNELS:%d SAMPLERATE:%d META:%d"
+
+/* CHD open values */
+#define CHD_OPEN_READ 1
+#define CHD_OPEN_READWRITE 2
+
+/* error types */
+enum _chd_error
+{
+ CHDERR_NONE,
+ CHDERR_NO_INTERFACE,
+ CHDERR_OUT_OF_MEMORY,
+ CHDERR_INVALID_FILE,
+ CHDERR_INVALID_PARAMETER,
+ CHDERR_INVALID_DATA,
+ CHDERR_FILE_NOT_FOUND,
+ CHDERR_REQUIRES_PARENT,
+ CHDERR_FILE_NOT_WRITEABLE,
+ CHDERR_READ_ERROR,
+ CHDERR_WRITE_ERROR,
+ CHDERR_CODEC_ERROR,
+ CHDERR_INVALID_PARENT,
+ CHDERR_HUNK_OUT_OF_RANGE,
+ CHDERR_DECOMPRESSION_ERROR,
+ CHDERR_COMPRESSION_ERROR,
+ CHDERR_CANT_CREATE_FILE,
+ CHDERR_CANT_VERIFY,
+ CHDERR_NOT_SUPPORTED,
+ CHDERR_METADATA_NOT_FOUND,
+ CHDERR_INVALID_METADATA_SIZE,
+ CHDERR_UNSUPPORTED_VERSION,
+ CHDERR_VERIFY_INCOMPLETE,
+ CHDERR_INVALID_METADATA,
+ CHDERR_INVALID_STATE,
+ CHDERR_OPERATION_PENDING,
+ CHDERR_NO_ASYNC_OPERATION,
+ CHDERR_UNSUPPORTED_FORMAT
+};
+typedef enum _chd_error chd_error;
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* opaque types */
+typedef struct _chd_file chd_file;
+
+
+/* progress callback function */
+typedef void (*chd_progress_printf)(const char *format, ...);
+
+
+/* extract header structure (NOT the on-disk header structure) */
+typedef struct _chd_header chd_header;
+struct _chd_header
+{
+ UINT32 length; /* length of header data */
+ UINT32 version; /* drive format version */
+ UINT32 flags; /* flags field */
+ UINT32 compression; /* compression type */
+ UINT32 hunkbytes; /* number of bytes per hunk */
+ UINT32 totalhunks; /* total # of hunks represented */
+ UINT64 logicalbytes; /* logical size of the data */
+ UINT64 metaoffset; /* offset in file of first metadata */
+ UINT8 md5[CHD_MD5_BYTES]; /* MD5 checksum of raw data */
+ UINT8 parentmd5[CHD_MD5_BYTES]; /* MD5 checksum of parent file */
+ UINT8 sha1[CHD_SHA1_BYTES]; /* SHA1 checksum of raw data */
+ UINT8 parentsha1[CHD_SHA1_BYTES]; /* SHA1 checksum of parent file */
+
+ UINT32 obsolete_cylinders; /* obsolete field -- do not use! */
+ UINT32 obsolete_sectors; /* obsolete field -- do not use! */
+ UINT32 obsolete_heads; /* obsolete field -- do not use! */
+ UINT32 obsolete_hunksize; /* obsolete field -- do not use! */
+};
+
+
+/* A/V codec decompression configuration */
+typedef struct _av_codec_decompress_config av_codec_decompress_config;
+struct _av_codec_decompress_config
+{
+ UINT32 decode_mask; /* decoding mask */
+ UINT8 * video_buffer; /* pointer to alternate video buffer */
+ UINT32 video_stride; /* bytes between rows in video buffer */
+ UINT32 video_xor; /* XOR to apply to bytes in video buffer */
+ UINT32 audio_xor; /* XOR to apply to bytes in audio buffer */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- CHD file management ----- */
+
+/* create a new CHD file fitting the given description */
+chd_error chd_create(const char *filename, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent);
+
+/* same as chd_create(), but accepts an already-opened core_file object */
+chd_error chd_create_file(core_file *file, UINT64 logicalbytes, UINT32 hunkbytes, UINT32 compression, chd_file *parent);
+
+/* open an existing CHD file */
+chd_error chd_open(const char *filename, int mode, chd_file *parent, chd_file **chd);
+
+/* same as chd_open(), but accepts an already-opened core_file object */
+chd_error chd_open_file(core_file *file, int mode, chd_file *parent, chd_file **chd);
+
+/* close a CHD file */
+void chd_close(chd_file *chd);
+
+/* return the associated core_file */
+core_file *chd_core_file(chd_file *chd);
+
+
+
+/* ----- CHD header management ----- */
+
+/* return a pointer to the extracted CHD header data */
+const chd_header *chd_get_header(chd_file *chd);
+
+/* set a modified header */
+chd_error chd_set_header(const char *filename, const chd_header *header);
+
+/* same as chd_set_header(), but accepts an already-opened core_file object */
+chd_error chd_set_header_file(core_file *file, const chd_header *header);
+
+
+
+/* ----- core data read/write ----- */
+
+/* read one hunk from the CHD file */
+chd_error chd_read(chd_file *chd, UINT32 hunknum, void *buffer);
+
+/* read one hunk from the CHD file asynchronously */
+chd_error chd_read_async(chd_file *chd, UINT32 hunknum, void *buffer);
+
+/* write one hunk to a CHD file */
+chd_error chd_write(chd_file *chd, UINT32 hunknum, const void *buffer);
+
+/* write one hunk to a CHD file asynchronously */
+chd_error chd_write_async(chd_file *chd, UINT32 hunknum, const void *buffer);
+
+/* wait for a previously issued async read/write to complete and return the error */
+chd_error chd_async_complete(chd_file *chd);
+
+
+
+/* ----- metadata management ----- */
+
+/* get indexed metadata of a particular sort */
+chd_error chd_get_metadata(chd_file *chd, UINT32 searchtag, UINT32 searchindex, void *output, UINT32 outputlen, UINT32 *resultlen, UINT32 *resulttag);
+
+/* set indexed metadata of a particular sort */
+chd_error chd_set_metadata(chd_file *chd, UINT32 metatag, UINT32 metaindex, const void *inputbuf, UINT32 inputlen);
+
+/* clone all of the metadata from one CHD to another */
+chd_error chd_clone_metadata(chd_file *source, chd_file *dest);
+
+
+
+/* ----- compression management ----- */
+
+/* begin compressing data to a CHD */
+chd_error chd_compress_begin(chd_file *chd);
+
+/* compress the next hunk of data */
+chd_error chd_compress_hunk(chd_file *chd, const void *data, double *curratio);
+
+/* finish compressing data to a CHD */
+chd_error chd_compress_finish(chd_file *chd);
+
+
+
+/* ----- verification management ----- */
+
+/* begin verifying a CHD */
+chd_error chd_verify_begin(chd_file *chd);
+
+/* verify a single hunk of data */
+chd_error chd_verify_hunk(chd_file *chd);
+
+/* finish verifying a CHD, returning the computed MD5 and SHA1 */
+chd_error chd_verify_finish(chd_file *chd, UINT8 *finalmd5, UINT8 *finalsha1);
+
+
+
+/* ----- codec interfaces ----- */
+
+/* set internal codec parameters */
+chd_error chd_codec_config(chd_file *chd, int param, void *config);
+
+/* return a string description of a codec */
+const char *chd_get_codec_name(UINT32 codec);
+
+
+#endif /* __CHD_H__ */
diff --git a/src/lib/util/corefile.c b/src/lib/util/corefile.c
new file mode 100644
index 00000000000..008e919a8f7
--- /dev/null
+++ b/src/lib/util/corefile.c
@@ -0,0 +1,726 @@
+/***************************************************************************
+
+ corefile.c
+
+ File access functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "corefile.h"
+#include "unicode.h"
+
+#include <stdarg.h>
+#include <ctype.h>
+
+
+
+/***************************************************************************
+ VALIDATION
+***************************************************************************/
+
+#if !defined(CRLF) || (CRLF < 1) || (CRLF > 3)
+#error CRLF undefined: must be 1 (CR), 2 (LF) or 3 (CR/LF)
+#endif
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define FILE_BUFFER_SIZE 512
+
+#define OPEN_FLAG_HAS_CRC 0x10000
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+enum _text_file_type
+{
+ TFT_OSD = 0, /* OSD depdendent encoding format used when BOMs missing */
+ TFT_UTF8, /* UTF-8 */
+ TFT_UTF16BE, /* UTF-16 (big endian) */
+ TFT_UTF16LE, /* UTF-16 (little endian) */
+ TFT_UTF32BE, /* UTF-32 (UCS-4) (big endian) */
+ TFT_UTF32LE /* UTF-32 (UCS-4) (little endian) */
+};
+typedef enum _text_file_type text_file_type;
+
+
+/* typedef struct _core_file core_file -- declared in corefile.h */
+struct _core_file
+{
+ osd_file * file; /* OSD file handle */
+ UINT32 openflags; /* flags we were opened with */
+ UINT8 data_allocated; /* was the data allocated by us? */
+ UINT8 * data; /* file data, if RAM-based */
+ UINT64 offset; /* current file offset */
+ UINT64 length; /* total file length */
+ text_file_type text_type; /* text output format */
+ char back_chars[UTF8_CHAR_MAX]; /* buffer to hold characters for ungetc */
+ int back_char_head; /* head of ungetc buffer */
+ int back_char_tail; /* tail of ungetc buffer */
+ UINT64 bufferbase; /* base offset of internal buffer */
+ UINT32 bufferbytes; /* bytes currently loaded into buffer */
+ UINT8 buffer[FILE_BUFFER_SIZE]; /* buffer data */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* misc helpers */
+static UINT32 safe_buffer_copy(const void *source, UINT32 sourceoffs, UINT32 sourcelen, void *dest, UINT32 destoffs, UINT32 destlen);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ is_directory_separator - is a given character
+ a directory separator? The following logic
+ works for most platforms
+-------------------------------------------------*/
+
+INLINE int is_directory_separator(char c)
+{
+ return (c == '\\' || c == '/' || c == ':');
+}
+
+
+
+/***************************************************************************
+ FILE OPEN/CLOSE
+***************************************************************************/
+
+/*-------------------------------------------------
+ core_fopen - open a file for access and
+ return an error code
+-------------------------------------------------*/
+
+file_error core_fopen(const char *filename, UINT32 openflags, core_file **file)
+{
+ file_error filerr = FILERR_NOT_FOUND;
+
+ /* allocate the file itself */
+ *file = malloc(sizeof(**file));
+ if (*file == NULL)
+ return FILERR_OUT_OF_MEMORY;
+ memset(*file, 0, sizeof(**file));
+
+ /* attempt to open the file */
+ filerr = osd_open(filename, openflags, &(*file)->file, &(*file)->length);
+ (*file)->openflags = openflags;
+
+ /* handle errors and return */
+ if (filerr != FILERR_NONE)
+ {
+ core_fclose(*file);
+ *file = NULL;
+ }
+ return filerr;
+}
+
+
+/*-------------------------------------------------
+ core_fopen_ram - open a RAM-based buffer for
+ file-like access and return an error code
+-------------------------------------------------*/
+
+file_error core_fopen_ram(const void *data, size_t length, UINT32 openflags, core_file **file)
+{
+ /* can only do this for read access */
+ if ((openflags & OPEN_FLAG_WRITE) != 0)
+ return FILERR_INVALID_ACCESS;
+ if ((openflags & OPEN_FLAG_CREATE) != 0)
+ return FILERR_INVALID_ACCESS;
+
+ /* allocate the file itself */
+ *file = malloc(sizeof(**file));
+ if (*file == NULL)
+ return FILERR_OUT_OF_MEMORY;
+ memset(*file, 0, sizeof(**file));
+
+ /* claim the buffer */
+ (*file)->data = (UINT8 *)data;
+ (*file)->length = length;
+ (*file)->openflags = openflags;
+
+ return FILERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ core_fclose - closes a file
+-------------------------------------------------*/
+
+void core_fclose(core_file *file)
+{
+ /* close files and free memory */
+ if (file->file != NULL)
+ osd_close(file->file);
+ if (file->data != NULL && file->data_allocated)
+ free(file->data);
+ free(file);
+}
+
+
+
+/***************************************************************************
+ FILE POSITIONING
+***************************************************************************/
+
+/*-------------------------------------------------
+ core_fseek - seek within a file
+-------------------------------------------------*/
+
+int core_fseek(core_file *file, INT64 offset, int whence)
+{
+ int err = 0;
+
+ /* flush any buffered char */
+ file->back_char_head = 0;
+ file->back_char_tail = 0;
+
+ /* switch off the relative location */
+ switch (whence)
+ {
+ case SEEK_SET:
+ file->offset = offset;
+ break;
+
+ case SEEK_CUR:
+ file->offset += offset;
+ break;
+
+ case SEEK_END:
+ file->offset = file->length + offset;
+ break;
+ }
+ return err;
+}
+
+
+/*-------------------------------------------------
+ core_ftell - return the current file position
+-------------------------------------------------*/
+
+UINT64 core_ftell(core_file *file)
+{
+ /* return the current offset */
+ return file->offset;
+}
+
+
+/*-------------------------------------------------
+ core_feof - return 1 if we're at the end
+ of file
+-------------------------------------------------*/
+
+int core_feof(core_file *file)
+{
+ /* check for buffered chars */
+ if (file->back_char_head != file->back_char_tail)
+ return 0;
+
+ /* if the offset == length, we're at EOF */
+ return (file->offset >= file->length);
+}
+
+
+/*-------------------------------------------------
+ core_fsize - returns the size of a file
+-------------------------------------------------*/
+
+UINT64 core_fsize(core_file *file)
+{
+ return file->length;
+}
+
+
+
+/***************************************************************************
+ FILE READ
+***************************************************************************/
+
+/*-------------------------------------------------
+ core_fread - read from a file
+-------------------------------------------------*/
+
+UINT32 core_fread(core_file *file, void *buffer, UINT32 length)
+{
+ file_error filerr;
+ UINT32 bytes_read = 0;
+
+ /* flush any buffered char */
+ file->back_char_head = 0;
+ file->back_char_tail = 0;
+
+ /* handle real files */
+ if (file->data == NULL)
+ {
+ /* if we're within the buffer, consume that first */
+ if (file->offset >= file->bufferbase && file->offset < file->bufferbase + file->bufferbytes)
+ bytes_read += safe_buffer_copy(file->buffer, file->offset - file->bufferbase, file->bufferbytes, buffer, bytes_read, length);
+
+ /* if we've got a small amount left, read it into the buffer first */
+ if (bytes_read < length)
+ {
+ if (length - bytes_read < sizeof(file->buffer) / 2)
+ {
+ /* read as much as makes sense into the buffer */
+ file->bufferbase = file->offset + bytes_read;
+ file->bufferbytes = 0;
+ filerr = osd_read(file->file, file->buffer, file->bufferbase, sizeof(file->buffer), &file->bufferbytes);
+
+ /* do a bounded copy from the buffer to the destination */
+ bytes_read += safe_buffer_copy(file->buffer, 0, file->bufferbytes, buffer, bytes_read, length);
+ }
+
+ /* read the remainder directly from the file */
+ else
+ {
+ UINT32 new_bytes_read;
+ filerr = osd_read(file->file, (UINT8 *)buffer + bytes_read, file->offset + bytes_read, length - bytes_read, &new_bytes_read);
+ bytes_read += new_bytes_read;
+ }
+ }
+ }
+
+ /* handle RAM-based files */
+ else
+ bytes_read += safe_buffer_copy(file->data, (UINT32)file->offset, file->length, buffer, bytes_read, length);
+
+ /* return the number of bytes read */
+ file->offset += bytes_read;
+ return bytes_read;
+}
+
+
+/*-------------------------------------------------
+ core_fgetc - read a character from a file
+-------------------------------------------------*/
+
+int core_fgetc(core_file *file)
+{
+ int result;
+
+ /* refresh buffer, if necessary */
+ if (file->back_char_head == file->back_char_tail)
+ {
+ utf16_char utf16_buffer[UTF16_CHAR_MAX];
+ char utf8_buffer[UTF8_CHAR_MAX];
+ char default_buffer[16];
+ unicode_char uchar = (unicode_char) ~0;
+ int readlen, charlen;
+
+ /* do we need to check the byte order marks? */
+ if (file->offset == 0)
+ {
+ UINT8 bom[4];
+ int pos = 0;
+
+ if (core_fread(file, bom, 4) == 4)
+ {
+ if (bom[0] == 0xef && bom[1] == 0xbb && bom[2] == 0xbf)
+ {
+ file->text_type = TFT_UTF8;
+ pos = 3;
+ }
+ else if (bom[0] == 0x00 && bom[1] == 0x00 && bom[2] == 0xfe && bom[3] == 0xff)
+ {
+ file->text_type = TFT_UTF32BE;
+ pos = 4;
+ }
+ else if (bom[0] == 0xff && bom[1] == 0xfe && bom[2] == 0x00 && bom[3] == 0x00)
+ {
+ file->text_type = TFT_UTF32LE;
+ pos = 4;
+ }
+ else if (bom[0] == 0xfe && bom[1] == 0xff)
+ {
+ file->text_type = TFT_UTF16BE;
+ pos = 2;
+ }
+ else if (bom[0] == 0xff && bom[1] == 0xfe)
+ {
+ file->text_type = TFT_UTF16LE;
+ pos = 2;
+ }
+ else
+ {
+ file->text_type = TFT_OSD;
+ pos = 0;
+ }
+ }
+ core_fseek(file, pos, SEEK_SET);
+ }
+
+ /* fetch the next character */
+ switch (file->text_type)
+ {
+ default:
+ case TFT_OSD:
+ readlen = core_fread(file, default_buffer, sizeof(default_buffer));
+ if (readlen > 0)
+ {
+ charlen = osd_uchar_from_osdchar(&uchar, default_buffer, readlen / sizeof(default_buffer[0]));
+ core_fseek(file, (INT64) (charlen * sizeof(default_buffer[0])) - readlen, SEEK_CUR);
+ }
+ break;
+
+ case TFT_UTF8:
+ readlen = core_fread(file, utf8_buffer, sizeof(utf8_buffer));
+ if (readlen > 0)
+ {
+ charlen = uchar_from_utf8(&uchar, utf8_buffer, readlen / sizeof(utf8_buffer[0]));
+ core_fseek(file, (INT64) (charlen * sizeof(utf8_buffer[0])) - readlen, SEEK_CUR);
+ }
+ break;
+
+ case TFT_UTF16BE:
+ readlen = core_fread(file, utf16_buffer, sizeof(utf16_buffer));
+ if (readlen > 0)
+ {
+ charlen = uchar_from_utf16be(&uchar, utf16_buffer, readlen / sizeof(utf16_buffer[0]));
+ core_fseek(file, (INT64) (charlen * sizeof(utf16_buffer[0])) - readlen, SEEK_CUR);
+ }
+ break;
+
+ case TFT_UTF16LE:
+ readlen = core_fread(file, utf16_buffer, sizeof(utf16_buffer));
+ if (readlen > 0)
+ {
+ charlen = uchar_from_utf16le(&uchar, utf16_buffer, readlen / sizeof(utf16_buffer[0]));
+ core_fseek(file, (INT64) (charlen * sizeof(utf16_buffer[0])) - readlen, SEEK_CUR);
+ }
+ break;
+
+ case TFT_UTF32BE:
+ if (core_fread(file, &uchar, sizeof(uchar)) == sizeof(uchar))
+ uchar = BIG_ENDIANIZE_INT32(uchar);
+ break;
+
+ case TFT_UTF32LE:
+ if (core_fread(file, &uchar, sizeof(uchar)) == sizeof(uchar))
+ uchar = LITTLE_ENDIANIZE_INT32(uchar);
+ break;
+ }
+
+ if (uchar != ~0)
+ {
+ /* place the new character in the ring buffer */
+ file->back_char_head = 0;
+ file->back_char_tail = utf8_from_uchar(file->back_chars, ARRAY_LENGTH(file->back_chars), uchar);
+/* assert(file->back_char_tail != -1);*/
+ }
+ }
+
+ /* now read from the ring buffer */
+ if (file->back_char_head != file->back_char_tail)
+ {
+ result = file->back_chars[file->back_char_head++];
+ file->back_char_head %= ARRAY_LENGTH(file->back_chars);
+ }
+ else
+ result = EOF;
+
+ return result;
+}
+
+
+/*-------------------------------------------------
+ core_ungetc - put back a character read from
+ a file
+-------------------------------------------------*/
+
+int core_ungetc(int c, core_file *file)
+{
+ file->back_chars[file->back_char_tail++] = (char) c;
+ file->back_char_tail %= ARRAY_LENGTH(file->back_chars);
+ return c;
+}
+
+
+/*-------------------------------------------------
+ core_fgets - read a line from a text file
+-------------------------------------------------*/
+
+char *core_fgets(char *s, int n, core_file *file)
+{
+ char *cur = s;
+
+ /* loop while we have characters */
+ while (n > 0)
+ {
+ int c = core_fgetc(file);
+ if (c == EOF)
+ break;
+
+ /* if there's a CR, look for an LF afterwards */
+ if (c == 0x0d)
+ {
+ int c2 = core_fgetc(file);
+ if (c2 != 0x0a)
+ core_ungetc(c2, file);
+ *cur++ = 0x0d;
+ n--;
+ break;
+ }
+
+ /* if there's an LF, reinterp as a CR for consistency */
+ else if (c == 0x0a)
+ {
+ *cur++ = 0x0d;
+ n--;
+ break;
+ }
+
+ /* otherwise, pop the character in and continue */
+ *cur++ = c;
+ n--;
+ }
+
+ /* if we put nothing in, return NULL */
+ if (cur == s)
+ return NULL;
+
+ /* otherwise, terminate */
+ if (n > 0)
+ *cur++ = 0;
+ return s;
+}
+
+
+/*-------------------------------------------------
+ core_fbuffer - return a pointer to the file
+ buffer; if it doesn't yet exist, load the
+ file into RAM first
+-------------------------------------------------*/
+
+const void *core_fbuffer(core_file *file)
+{
+ file_error filerr;
+ UINT32 read_length;
+
+ /* if we already have data, just return it */
+ if (file->data != NULL)
+ return file->data;
+
+ /* allocate some memory */
+ file->data = malloc(file->length);
+ if (file->data == NULL)
+ return NULL;
+ file->data_allocated = TRUE;
+
+ /* read the file */
+ filerr = osd_read(file->file, file->data, 0, file->length, &read_length);
+ if (filerr != FILERR_NONE || read_length != file->length)
+ {
+ free(file->data);
+ file->data = NULL;
+ return NULL;
+ }
+
+ /* close the file because we don't need it anymore */
+ osd_close(file->file);
+ file->file = NULL;
+ return file->data;
+}
+
+
+
+/***************************************************************************
+ FILE WRITE
+***************************************************************************/
+
+/*-------------------------------------------------
+ core_fwrite - write to a file
+-------------------------------------------------*/
+
+UINT32 core_fwrite(core_file *file, const void *buffer, UINT32 length)
+{
+ UINT32 bytes_written = 0;
+ file_error filerr;
+
+ /* can't write to RAM-based stuff */
+ if (file->data != NULL)
+ return 0;
+
+ /* flush any buffered char */
+ file->back_char_head = 0;
+ file->back_char_tail = 0;
+
+ /* invalidate any buffered data */
+ file->bufferbytes = 0;
+
+ /* do the write */
+ filerr = osd_write(file->file, buffer, file->offset, length, &bytes_written);
+
+ /* return the number of bytes read */
+ file->offset += bytes_written;
+ file->length = MAX(file->length, file->offset);
+ return bytes_written;
+}
+
+
+/*-------------------------------------------------
+ core_fputs - write a line to a text file
+-------------------------------------------------*/
+
+int core_fputs(core_file *f, const char *s)
+{
+ char convbuf[1024];
+ char *pconvbuf = convbuf;
+ int count = 0;
+
+ /* is this the beginning of the file? if so, write a byte order mark */
+ if (f->offset == 0 && !(f->openflags & OPEN_FLAG_NO_BOM))
+ {
+ *pconvbuf++ = 0xef;
+ *pconvbuf++ = 0xbb;
+ *pconvbuf++ = 0xbf;
+ }
+
+ /* convert '\n' to platform dependant line endings */
+ while (*s != 0)
+ {
+ if (*s == '\n')
+ {
+ if (CRLF == 1) /* CR only */
+ *pconvbuf++ = 13;
+ else if (CRLF == 2) /* LF only */
+ *pconvbuf++ = 10;
+ else if (CRLF == 3) /* CR+LF */
+ {
+ *pconvbuf++ = 13;
+ *pconvbuf++ = 10;
+ }
+ }
+ else
+ *pconvbuf++ = *s;
+ s++;
+
+ /* if we overflow, break into chunks */
+ if (pconvbuf >= convbuf + ARRAY_LENGTH(convbuf) - 10)
+ {
+ count += core_fwrite(f, convbuf, pconvbuf - convbuf);
+ pconvbuf = convbuf;
+ }
+ }
+
+ /* final flush */
+ if (pconvbuf != convbuf)
+ count += core_fwrite(f, convbuf, pconvbuf - convbuf);
+
+ return count;
+}
+
+
+/*-------------------------------------------------
+ core_vfprintf - vfprintf to a text file
+-------------------------------------------------*/
+
+int core_vfprintf(core_file *f, const char *fmt, va_list va)
+{
+ char buf[1024];
+ vsnprintf(buf, sizeof(buf), fmt, va);
+ return core_fputs(f, buf);
+}
+
+
+/*-------------------------------------------------
+ core_fprintf - vfprintf to a text file
+-------------------------------------------------*/
+
+int CLIB_DECL core_fprintf(core_file *f, const char *fmt, ...)
+{
+ int rc;
+ va_list va;
+ va_start(va, fmt);
+ rc = core_vfprintf(f, fmt, va);
+ va_end(va);
+ return rc;
+}
+
+
+
+/***************************************************************************
+ FILENAME UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ core_filename_extract_base - extract the base
+ name from a filename; note that this makes
+ assumptions about path separators
+-------------------------------------------------*/
+
+astring *core_filename_extract_base(astring *result, const char *name, int strip_extension)
+{
+ /* find the start of the name */
+ const char *start = name + strlen(name);
+ while (start > name && !is_directory_separator(start[-1]))
+ start--;
+
+ /* copy the rest into an astring */
+ astring_cpyc(result, start);
+
+ /* chop the extension if present */
+ if (strip_extension)
+ astring_substr(result, 0, astring_rchr(result, 0, '.'));
+ return result;
+}
+
+
+/*-------------------------------------------------
+ core_filename_ends_with - does the given
+ filename end with the specified extension?
+-------------------------------------------------*/
+
+int core_filename_ends_with(const char *filename, const char *extension)
+{
+ int namelen = strlen(filename);
+ int extlen = strlen(extension);
+ int matches = TRUE;
+
+ /* work backwards checking for a match */
+ while (extlen > 0)
+ if (tolower(filename[--namelen]) != tolower(extension[--extlen]))
+ {
+ matches = FALSE;
+ break;
+ }
+
+ return matches;
+}
+
+
+
+/***************************************************************************
+ MISC HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ safe_buffer_copy - copy safely from one
+ bounded buffer to another
+-------------------------------------------------*/
+
+static UINT32 safe_buffer_copy(const void *source, UINT32 sourceoffs, UINT32 sourcelen, void *dest, UINT32 destoffs, UINT32 destlen)
+{
+ UINT32 sourceavail = sourcelen - sourceoffs;
+ UINT32 destavail = destlen - destoffs;
+ UINT32 bytes_to_copy = MIN(sourceavail, destavail);
+ if (bytes_to_copy > 0)
+ memcpy((UINT8 *)dest + destoffs, (const UINT8 *)source + sourceoffs, bytes_to_copy);
+ return bytes_to_copy;
+}
diff --git a/src/lib/util/corefile.h b/src/lib/util/corefile.h
new file mode 100644
index 00000000000..dc9e69ce9f5
--- /dev/null
+++ b/src/lib/util/corefile.h
@@ -0,0 +1,116 @@
+/***************************************************************************
+
+ corefile.h
+
+ Core file I/O interface functions and definitions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __COREFILE_H__
+#define __COREFILE_H__
+
+#include <stdarg.h>
+#include "osdcore.h"
+#include "astring.h"
+
+
+
+/***************************************************************************
+ ADDITIONAL OPEN FLAGS
+***************************************************************************/
+
+#define OPEN_FLAG_NO_BOM 0x0100 /* don't output BOM */
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _core_file core_file;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- file open/close ----- */
+
+/* open a file with the specified filename */
+file_error core_fopen(const char *filename, UINT32 openflags, core_file **file);
+
+/* open a RAM-based "file" using the given data and length (read-only) */
+file_error core_fopen_ram(const void *data, size_t length, UINT32 openflags, core_file **file);
+
+/* close an open file */
+void core_fclose(core_file *file);
+
+
+
+/* ----- file positioning ----- */
+
+/* adjust the file pointer within the file */
+int core_fseek(core_file *file, INT64 offset, int whence);
+
+/* return the current file pointer */
+UINT64 core_ftell(core_file *file);
+
+/* return true if we are at the EOF */
+int core_feof(core_file *file);
+
+/* return the total size of the file */
+UINT64 core_fsize(core_file *file);
+
+
+
+/* ----- file read ----- */
+
+/* standard binary read from a file */
+UINT32 core_fread(core_file *file, void *buffer, UINT32 length);
+
+/* read one character from the file */
+int core_fgetc(core_file *file);
+
+/* put back one character from the file */
+int core_ungetc(int c, core_file *file);
+
+/* read a full line of text from the file */
+char *core_fgets(char *s, int n, core_file *file);
+
+/* get a pointer to a buffer that holds the full file data in RAM */
+/* this function may cause the full file data to be read */
+const void *core_fbuffer(core_file *file);
+
+
+
+/* ----- file write ----- */
+
+/* standard binary write to a file */
+UINT32 core_fwrite(core_file *file, const void *buffer, UINT32 length);
+
+/* write a line of text to the file */
+int core_fputs(core_file *f, const char *s);
+
+/* printf-style text write to a file */
+int core_vfprintf(core_file *f, const char *fmt, va_list va);
+int CLIB_DECL core_fprintf(core_file *f, const char *fmt, ...);
+
+
+
+/* ----- filename utilities ----- */
+
+/* extract the base part of a filename (remove extensions and paths) */
+astring *core_filename_extract_base(astring *result, const char *name, int strip_extension);
+
+/* true if the given filename ends with a particular extension */
+int core_filename_ends_with(const char *filename, const char *extension);
+
+
+#endif /* __COREFILE_H__ */
diff --git a/src/lib/util/corestr.c b/src/lib/util/corestr.c
new file mode 100644
index 00000000000..dd7bb1610e8
--- /dev/null
+++ b/src/lib/util/corestr.c
@@ -0,0 +1,120 @@
+/***************************************************************************
+
+ corestr.c
+
+ Core string functions used throughout MAME.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************/
+
+#include "corestr.h"
+#include <ctype.h>
+#include <stdlib.h>
+
+
+/*-------------------------------------------------
+ core_stricmp - case-insensitive string compare
+-------------------------------------------------*/
+
+int core_stricmp(const char *s1, const char *s2)
+{
+ for (;;)
+ {
+ int c1 = tolower(*s1++);
+ int c2 = tolower(*s2++);
+ if (c1 == 0 || c1 != c2)
+ return c1 - c2;
+ }
+}
+
+
+/*-------------------------------------------------
+ core_strnicmp - case-insensitive string compare
+-------------------------------------------------*/
+
+int core_strnicmp(const char *s1, const char *s2, size_t n)
+{
+ size_t i;
+ for (i = 0; i < n; i++)
+ {
+ int c1 = tolower(*s1++);
+ int c2 = tolower(*s2++);
+ if (c1 == 0 || c1 != c2)
+ return c1 - c2;
+ }
+
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ core_strwildcmp - case-insensitive wildcard
+ string compare (up to 8 characters at the
+ moment)
+-------------------------------------------------*/
+
+int core_strwildcmp(const char *sp1, const char *sp2)
+{
+ char s1[9], s2[9];
+ int i, l1, l2;
+ char *p;
+
+ strncpy(s1, sp1, 8); s1[8] = 0; if (s1[0] == 0) strcpy(s1, "*");
+
+ strncpy(s2, sp2, 8); s2[8] = 0; if (s2[0] == 0) strcpy(s2, "*");
+
+ p = strchr(s1, '*');
+ if (p)
+ {
+ for (i = p - s1; i < 8; i++) s1[i] = '?';
+ s1[8] = 0;
+ }
+
+ p = strchr(s2, '*');
+ if (p)
+ {
+ for (i = p - s2; i < 8; i++) s2[i] = '?';
+ s2[8] = 0;
+ }
+
+ l1 = (int)strlen(s1);
+ if (l1 < 8)
+ {
+ for (i = l1 + 1; i < 8; i++) s1[i] = ' ';
+ s1[8] = 0;
+ }
+
+ l2 = (int)strlen(s2);
+ if (l2 < 8)
+ {
+ for (i = l2 + 1; i < 8; i++) s2[i] = ' ';
+ s2[8] = 0;
+ }
+
+ for (i = 0; i < 8; i++)
+ {
+ if (s1[i] == '?' && s2[i] != '?') s1[i] = s2[i];
+ if (s2[i] == '?' && s1[i] != '?') s2[i] = s1[i];
+ }
+
+ return core_stricmp(s1, s2);
+}
+
+
+/*-------------------------------------------------
+ core_strdup - string duplication via malloc
+-------------------------------------------------*/
+
+char *core_strdup(const char *str)
+{
+ char *cpy = NULL;
+ if (str != NULL)
+ {
+ cpy = malloc(strlen(str) + 1);
+ if (cpy != NULL)
+ strcpy(cpy, str);
+ }
+ return cpy;
+}
diff --git a/src/lib/util/corestr.h b/src/lib/util/corestr.h
new file mode 100644
index 00000000000..cd2ef4028b7
--- /dev/null
+++ b/src/lib/util/corestr.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+
+ corestr.h
+
+ Core string functions used throughout MAME.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __CORESTR_H__
+#define __CORESTR_H__
+
+#include <string.h>
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* since stricmp is not part of the standard, we use this instead */
+int core_stricmp(const char *s1, const char *s2);
+
+/* this macro prevents people from using stricmp directly */
+#undef stricmp
+#define stricmp !MUST_USE_CORE_STRICMP_INSTEAD!
+
+/* this macro prevents people from using strcasecmp directly */
+#undef strcasecmp
+#define strcasecmp !MUST_USE_CORE_STRICMP_INSTEAD!
+
+
+/* since strnicmp is not part of the standard, we use this instead */
+int core_strnicmp(const char *s1, const char *s2, size_t n);
+
+/* this macro prevents people from using strnicmp directly */
+#undef strnicmp
+#define strnicmp !MUST_USE_CORE_STRNICMP_INSTEAD!
+
+/* this macro prevents people from using strncasecmp directly */
+#undef strncasecmp
+#define strncasecmp !MUST_USE_CORE_STRNICMP_INSTEAD!
+
+
+/* since strdup is not part of the standard, we use this instead */
+char *core_strdup(const char *str);
+
+/* this macro prevents people from using strdup directly */
+#undef strdup
+#define strdup !MUST_USE_CORE_STRDUP_INSTEAD!
+
+
+/* additional string compare helper */
+int core_strwildcmp(const char *sp1, const char *sp2);
+
+
+#endif /* __CORESTR_H__ */
diff --git a/src/lib/util/coreutil.c b/src/lib/util/coreutil.c
new file mode 100644
index 00000000000..daaf116dc9c
--- /dev/null
+++ b/src/lib/util/coreutil.c
@@ -0,0 +1,102 @@
+/***************************************************************************
+
+ coreutil.c
+
+ Miscellaneous utility code
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************/
+
+#include "coreutil.h"
+
+
+/***************************************************************************
+ BINARY CODED DECIMAL HELPERS
+***************************************************************************/
+
+int bcd_adjust(int value)
+{
+ if ((value & 0xf) >= 0xa)
+ value = value + 0x10 - 0xa;
+ if ((value & 0xf0) >= 0xa0)
+ value = value - 0xa0 + 0x100;
+ return value;
+}
+
+
+UINT32 dec_2_bcd(UINT32 a)
+{
+ UINT32 result = 0;
+ int shift = 0;
+
+ while (a != 0)
+ {
+ result |= (a % 10) << shift;
+ a /= 10;
+ shift += 4;
+ }
+ return result;
+}
+
+
+UINT32 bcd_2_dec(UINT32 a)
+{
+ UINT32 result = 0;
+ UINT32 scale = 1;
+
+ while (a != 0)
+ {
+ result += (a & 0x0f) * scale;
+ a >>= 4;
+ scale *= 10;
+ }
+ return result;
+}
+
+
+
+/***************************************************************************
+ GREGORIAN CALENDAR HELPERS
+***************************************************************************/
+
+int gregorian_is_leap_year(int year)
+{
+ return !(year % 100 ? year % 4 : year % 400);
+}
+
+
+/* months are one counted */
+int gregorian_days_in_month(int month, int year)
+{
+ if (month == 2)
+ return gregorian_is_leap_year(year) ? 29 : 28;
+ else if (month == 4 || month == 6 || month == 9 || month == 11)
+ return 30;
+ else
+ return 31;
+}
+
+
+/***************************************************************************
+ MISC
+***************************************************************************/
+
+void rand_memory(void *memory, size_t length)
+{
+ UINT8 *bytes = (UINT8 *) memory;
+ UINT32 currand;
+ size_t i;
+
+ currand = rand();
+ currand <<= 15;
+ currand ^= rand();
+
+ for (i = 0; i < length; i++)
+ {
+ currand = currand * 214013 + 2531011;
+ bytes[i] = (UINT8) (currand >> 16);
+ }
+}
+
diff --git a/src/lib/util/coreutil.h b/src/lib/util/coreutil.h
new file mode 100644
index 00000000000..e251d61ca80
--- /dev/null
+++ b/src/lib/util/coreutil.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+
+ coreutil.h
+
+ Miscellaneous utility code
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __COREUTIL_H__
+#define __COREUTIL_H__
+
+#include "osdcomm.h"
+
+
+/***************************************************************************
+ BINARY CODED DECIMAL HELPERS
+***************************************************************************/
+
+int bcd_adjust(int value);
+UINT32 dec_2_bcd(UINT32 a);
+UINT32 bcd_2_dec(UINT32 a);
+
+
+/***************************************************************************
+ GREGORIAN CALENDAR HELPERS
+***************************************************************************/
+
+int gregorian_is_leap_year(int year);
+int gregorian_days_in_month(int month, int year);
+
+
+/***************************************************************************
+ MISC
+***************************************************************************/
+
+void rand_memory(void *memory, size_t length);
+
+
+#endif /* __COREUTIL_H__ */
diff --git a/src/lib/util/harddisk.c b/src/lib/util/harddisk.c
new file mode 100644
index 00000000000..a4edf8524d9
--- /dev/null
+++ b/src/lib/util/harddisk.c
@@ -0,0 +1,170 @@
+/***************************************************************************
+
+ Generic MAME hard disk implementation, with differencing files
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "harddisk.h"
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+struct _hard_disk_file
+{
+ chd_file * chd; /* CHD file */
+ hard_disk_info info; /* hard disk info */
+ UINT32 hunksectors; /* sectors per hunk */
+ UINT32 cachehunk; /* which hunk is cached */
+ UINT8 * cache; /* cache of the current hunk */
+};
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ hard_disk_open - open a hard disk handle,
+ given a chd_file
+-------------------------------------------------*/
+
+hard_disk_file *hard_disk_open(chd_file *chd)
+{
+ int cylinders, heads, sectors, sectorbytes;
+ hard_disk_file *file;
+ char metadata[256];
+ chd_error err;
+
+ /* punt if no CHD */
+ if (chd == NULL)
+ return NULL;
+
+ /* read the hard disk metadata */
+ err = chd_get_metadata(chd, HARD_DISK_METADATA_TAG, 0, metadata, sizeof(metadata), NULL, NULL);
+ if (err != CHDERR_NONE)
+ return NULL;
+
+ /* parse the metadata */
+ if (sscanf(metadata, HARD_DISK_METADATA_FORMAT, &cylinders, &heads, &sectors, &sectorbytes) != 4)
+ return NULL;
+
+ /* allocate memory for the hard disk file */
+ file = malloc(sizeof(hard_disk_file));
+ if (file == NULL)
+ return NULL;
+
+ /* fill in the data */
+ file->chd = chd;
+ file->info.cylinders = cylinders;
+ file->info.heads = heads;
+ file->info.sectors = sectors;
+ file->info.sectorbytes = sectorbytes;
+ file->hunksectors = chd_get_header(chd)->hunkbytes / file->info.sectorbytes;
+ file->cachehunk = -1;
+
+ /* allocate a cache */
+ file->cache = malloc(chd_get_header(chd)->hunkbytes);
+ if (file->cache == NULL)
+ {
+ free(file);
+ return NULL;
+ }
+
+ return file;
+}
+
+
+/*-------------------------------------------------
+ hard_disk_close - close a hard disk handle
+-------------------------------------------------*/
+
+void hard_disk_close(hard_disk_file *file)
+{
+ /* free the cache */
+ if (file->cache != NULL)
+ free(file->cache);
+ free(file);
+}
+
+
+/*-------------------------------------------------
+ hard_disk_get_chd - get a handle to a CHD
+ from a hard disk
+-------------------------------------------------*/
+
+chd_file *hard_disk_get_chd(hard_disk_file *file)
+{
+ return file->chd;
+}
+
+
+/*-------------------------------------------------
+ hard_disk_get_info - return information about
+ a hard disk
+-------------------------------------------------*/
+
+hard_disk_info *hard_disk_get_info(hard_disk_file *file)
+{
+ return &file->info;
+}
+
+
+/*-------------------------------------------------
+ hard_disk_read - read sectors from a hard
+ disk
+-------------------------------------------------*/
+
+UINT32 hard_disk_read(hard_disk_file *file, UINT32 lbasector, void *buffer)
+{
+ UINT32 hunknum = lbasector / file->hunksectors;
+ UINT32 sectoroffs = lbasector % file->hunksectors;
+
+ /* if we haven't cached this hunk, read it now */
+ if (file->cachehunk != hunknum)
+ {
+ chd_error err = chd_read(file->chd, hunknum, file->cache);
+ if (err != CHDERR_NONE)
+ return 0;
+ file->cachehunk = hunknum;
+ }
+
+ /* copy out the requested sector */
+ memcpy(buffer, &file->cache[sectoroffs * file->info.sectorbytes], file->info.sectorbytes);
+ return 1;
+}
+
+
+/*-------------------------------------------------
+ hard_disk_write - write sectors to a hard
+ disk
+-------------------------------------------------*/
+
+UINT32 hard_disk_write(hard_disk_file *file, UINT32 lbasector, const void *buffer)
+{
+ UINT32 hunknum = lbasector / file->hunksectors;
+ UINT32 sectoroffs = lbasector % file->hunksectors;
+ chd_error err;
+
+ /* if we haven't cached this hunk, read it now */
+ if (file->cachehunk != hunknum)
+ {
+ err = chd_read(file->chd, hunknum, file->cache);
+ if (err != CHDERR_NONE)
+ return 0;
+ file->cachehunk = hunknum;
+ }
+
+ /* copy in the requested data */
+ memcpy(&file->cache[sectoroffs * file->info.sectorbytes], buffer, file->info.sectorbytes);
+
+ /* write it back out */
+ err = chd_write(file->chd, hunknum, file->cache);
+ return (err == CHDERR_NONE) ? 1 : 0;
+}
diff --git a/src/lib/util/harddisk.h b/src/lib/util/harddisk.h
new file mode 100644
index 00000000000..2636fc80094
--- /dev/null
+++ b/src/lib/util/harddisk.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+
+ harddisk.h
+
+ Generic MAME hard disk implementation, with differencing files
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __HARDDISK_H__
+#define __HARDDISK_H__
+
+#include "osdcore.h"
+#include "chd.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _hard_disk_file hard_disk_file;
+
+typedef struct _hard_disk_info hard_disk_info;
+struct _hard_disk_info
+{
+ UINT32 cylinders;
+ UINT32 heads;
+ UINT32 sectors;
+ UINT32 sectorbytes;
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+hard_disk_file *hard_disk_open(chd_file *chd);
+void hard_disk_close(hard_disk_file *file);
+
+chd_file *hard_disk_get_chd(hard_disk_file *file);
+hard_disk_info *hard_disk_get_info(hard_disk_file *file);
+
+UINT32 hard_disk_read(hard_disk_file *file, UINT32 lbasector, void *buffer);
+UINT32 hard_disk_write(hard_disk_file *file, UINT32 lbasector, const void *buffer);
+
+#endif /* __HARDDISK_H__ */
diff --git a/src/lib/util/huffman.c b/src/lib/util/huffman.c
new file mode 100644
index 00000000000..0465f5d94d3
--- /dev/null
+++ b/src/lib/util/huffman.c
@@ -0,0 +1,934 @@
+/***************************************************************************
+
+ huffman.c
+
+ Video compression and decompression helpers.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Maximum codelength is officially (alphabetsize - 1). This would be 255 bits
+ (since we use 1 byte values). However, it is also dependent upon the number
+ of samples used, as follows:
+
+ 2 bits -> 3..4 samples
+ 3 bits -> 5..7 samples
+ 4 bits -> 8..12 samples
+ 5 bits -> 13..20 samples
+ 6 bits -> 21..33 samples
+ 7 bits -> 34..54 samples
+ 8 bits -> 55..88 samples
+ 9 bits -> 89..143 samples
+ 10 bits -> 144..232 samples
+ 11 bits -> 233..376 samples
+ 12 bits -> 377..609 samples
+ 13 bits -> 610..986 samples
+ 14 bits -> 987..1596 samples
+ 15 bits -> 1597..2583 samples
+ 16 bits -> 2584..4180 samples -> note that a 4k data size guarantees codelength <= 16 bits
+ 17 bits -> 4181..6764 samples
+ 18 bits -> 6765..10945 samples
+ 19 bits -> 10946..17710 samples
+ 20 bits -> 17711..28656 samples
+ 21 bits -> 28657..46367 samples
+ 22 bits -> 46368..75024 samples
+ 23 bits -> 75025..121392 samples
+ 24 bits -> 121393..196417 samples
+ 25 bits -> 196418..317810 samples
+ 26 bits -> 317811..514228 samples
+ 27 bits -> 514229..832039 samples
+ 28 bits -> 832040..1346268 samples
+ 29 bits -> 1346269..2178308 samples
+ 30 bits -> 2178309..3524577 samples
+ 31 bits -> 3524578..5702886 samples
+ 32 bits -> 5702887..9227464 samples
+
+ Looking at it differently, here is where powers of 2 fall into these buckets:
+
+ 256 samples -> 11 bits max
+ 512 samples -> 12 bits max
+ 1k samples -> 14 bits max
+ 2k samples -> 15 bits max
+ 4k samples -> 16 bits max
+ 8k samples -> 18 bits max
+ 16k samples -> 19 bits max
+ 32k samples -> 21 bits max
+ 64k samples -> 22 bits max
+ 128k samples -> 24 bits max
+ 256k samples -> 25 bits max
+ 512k samples -> 27 bits max
+ 1M samples -> 28 bits max
+ 2M samples -> 29 bits max
+ 4M samples -> 31 bits max
+ 8M samples -> 32 bits max
+
+***************************************************************************/
+
+#include "huffman.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_HUFFMAN_NODES (256 + 256)
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _bit_buffer bit_buffer;
+struct _bit_buffer
+{
+ UINT32 buffer;
+ int bits;
+ union
+ {
+ const UINT8 *read;
+ UINT8 * write;
+ } data;
+ UINT32 doffset;
+ UINT32 dlength;
+ int overflow;
+};
+
+
+typedef struct _huffman_node huffman_node;
+struct _huffman_node
+{
+ huffman_node * parent;
+ UINT32 count;
+ UINT32 weight;
+ UINT32 bits;
+ UINT8 numbits;
+};
+
+
+struct _huffman_context
+{
+ UINT8 maxbits;
+ UINT8 lookupdirty;
+ huffman_node huffnode[MAX_HUFFMAN_NODES];
+ UINT32 lookupmask;
+ huffman_lookup_value *lookup;
+};
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+static void huffman_write_rle_tree_bits(bit_buffer *bitbuf, int value, int repcount, int numbits);
+static int CLIB_DECL huffman_tree_node_compare(const void *item1, const void *item2);
+static int huffman_build_tree(huffman_context *context, const UINT32 *datahisto, UINT32 totaldata, UINT32 totalweight);
+static huffman_error huffman_assign_canonical_codes(huffman_context *context);
+static huffman_error huffman_build_lookup_table(huffman_context *context);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ bit_buffer_write_init - initialize a bit
+ buffer for writing
+-------------------------------------------------*/
+
+INLINE void bit_buffer_write_init(bit_buffer *bitbuf, UINT8 *data, UINT32 dlength)
+{
+ /* fill in the basic data structure */
+ bitbuf->buffer = 0;
+ bitbuf->bits = 0;
+ bitbuf->data.write = data;
+ bitbuf->doffset = 0;
+ bitbuf->dlength = dlength;
+ bitbuf->overflow = FALSE;
+}
+
+
+/*-------------------------------------------------
+ bit_buffer_write - write 'numbits' to the
+ bit buffer, assuming that 'newbits' is right-
+ justified
+-------------------------------------------------*/
+
+INLINE void bit_buffer_write(bit_buffer *bitbuf, UINT32 newbits, int numbits)
+{
+ /* flush the buffer if we're going to overflow it */
+ if (bitbuf->bits + numbits > 32)
+ while (bitbuf->bits >= 8)
+ {
+ if (bitbuf->doffset < bitbuf->dlength)
+ bitbuf->data.write[bitbuf->doffset] = bitbuf->buffer >> 24;
+ else
+ bitbuf->overflow = TRUE;
+ bitbuf->doffset++;
+ bitbuf->buffer <<= 8;
+ bitbuf->bits -= 8;
+ }
+
+ /* shift the bits to the top */
+ newbits <<= 32 - numbits;
+
+ /* now shift it down to account for the number of bits we already have and OR them in */
+ bitbuf->buffer |= newbits >> bitbuf->bits;
+ bitbuf->bits += numbits;
+}
+
+
+/*-------------------------------------------------
+ bit_buffer_flush - flush any bits in the write
+ buffer and return the final data offset
+-------------------------------------------------*/
+
+INLINE UINT32 bit_buffer_flush(bit_buffer *bitbuf)
+{
+ while (bitbuf->bits > 0)
+ {
+ if (bitbuf->doffset < bitbuf->dlength)
+ bitbuf->data.write[bitbuf->doffset] = bitbuf->buffer >> 24;
+ else
+ bitbuf->overflow = TRUE;
+ bitbuf->doffset++;
+ bitbuf->buffer <<= 8;
+ bitbuf->bits -= 8;
+ }
+ return bitbuf->doffset;
+}
+
+
+/*-------------------------------------------------
+ bit_buffer_read_init - initialize a bit
+ buffer for reading
+-------------------------------------------------*/
+
+INLINE void bit_buffer_read_init(bit_buffer *bitbuf, const UINT8 *data, UINT32 dlength)
+{
+ /* fill in the basic data structure */
+ bitbuf->buffer = 0;
+ bitbuf->bits = 0;
+ bitbuf->data.read = data;
+ bitbuf->doffset = 0;
+ bitbuf->dlength = dlength;
+ bitbuf->overflow = FALSE;
+}
+
+
+/*-------------------------------------------------
+ bit_buffer_read - read 'numbits' bits from
+ the buffer, returning the right-justified
+-------------------------------------------------*/
+
+INLINE UINT32 bit_buffer_read(bit_buffer *bitbuf, int numbits)
+{
+ UINT32 result;
+
+ /* fetch data if we need more */
+ if (numbits > bitbuf->bits)
+ {
+ while (bitbuf->bits <= 24)
+ {
+ if (bitbuf->doffset < bitbuf->dlength)
+ bitbuf->buffer |= bitbuf->data.read[bitbuf->doffset] << (24 - bitbuf->bits);
+ bitbuf->doffset++;
+ bitbuf->bits += 8;
+ }
+ if (numbits > bitbuf->bits)
+ bitbuf->overflow = TRUE;
+ }
+
+ /* return the data */
+ result = bitbuf->buffer >> (32 - numbits);
+ bitbuf->buffer <<= numbits;
+ bitbuf->bits -= numbits;
+ return result;
+}
+
+
+/*-------------------------------------------------
+ bit_buffer_read_offset - return the current
+ rounded byte reading offset
+-------------------------------------------------*/
+
+INLINE UINT32 bit_buffer_read_offset(bit_buffer *bitbuf)
+{
+ UINT32 result = bitbuf->doffset;
+ int bits = bitbuf->bits;
+ while (bits >= 8)
+ {
+ result--;
+ bits -= 8;
+ }
+ return result;
+}
+
+
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ huffman_create_context - create an encoding/
+ decoding context
+-------------------------------------------------*/
+
+huffman_error huffman_create_context(huffman_context **context, int maxbits)
+{
+ /* limit to 24 bits */
+ if (maxbits > 24)
+ return HUFFERR_TOO_MANY_BITS;
+
+ /* allocate a context */
+ *context = malloc(sizeof(**context));
+ if (*context == NULL)
+ return HUFFERR_OUT_OF_MEMORY;
+
+ /* set the info */
+ memset(*context, 0, sizeof(**context));
+ (*context)->maxbits = maxbits;
+ (*context)->lookupmask = (1 << maxbits) - 1;
+ (*context)->lookupdirty = TRUE;
+
+ return HUFFERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ huffman_free_context - free an encoding/
+ decoding context
+-------------------------------------------------*/
+
+void huffman_free_context(huffman_context *context)
+{
+ if (context->lookup != NULL)
+ free(context->lookup);
+ free(context);
+}
+
+
+/*-------------------------------------------------
+ huffman_compute_tree - compute an optimal
+ huffman tree for the given source data
+-------------------------------------------------*/
+
+huffman_error huffman_compute_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 sstride)
+{
+ UINT32 lowerweight, upperweight;
+ UINT32 datahisto[256];
+ int i;
+
+ /* build the data histogram */
+ memset(datahisto, 0, sizeof(datahisto));
+ for (i = 0; i < slength; i += sstride)
+ datahisto[source[i]]++;
+
+ /* binary search to achieve the optimum encoding */
+ lowerweight = 0;
+ upperweight = slength * 2;
+ while (TRUE)
+ {
+ UINT32 curweight = (upperweight + lowerweight) / 2;
+ int curmaxbits;
+
+ /* build a tree using the current weight */
+ curmaxbits = huffman_build_tree(context, datahisto, slength, curweight);
+
+ /* apply binary search here */
+ if (curmaxbits <= context->maxbits)
+ {
+ lowerweight = curweight;
+
+ /* early out if it worked with the raw weights, or if we're done searching */
+ if (curweight == slength || (upperweight - lowerweight) <= 1)
+ break;
+ }
+ else
+ upperweight = curweight;
+ }
+
+ /* assign canonical codes for all nodes based on their code lengths */
+ return huffman_assign_canonical_codes(context);
+}
+
+
+/*-------------------------------------------------
+ huffman_import_tree - import a huffman tree
+ from a source data stream
+-------------------------------------------------*/
+
+huffman_error huffman_import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength)
+{
+ huffman_error error;
+ bit_buffer bitbuf;
+ int curnode;
+ int numbits;
+
+ /* initialize the input buffer */
+ bit_buffer_read_init(&bitbuf, source, slength);
+
+ /* bits per entry depends on the maxbits */
+ if (context->maxbits >= 16)
+ numbits = 5;
+ else if (context->maxbits >= 8)
+ numbits = 4;
+ else
+ numbits = 3;
+
+ /* loop until we read all the nodes */
+ for (curnode = 0; curnode < 256; )
+ {
+ int nodebits = bit_buffer_read(&bitbuf, numbits);
+
+ /* a non-one value is just raw */
+ if (nodebits != 1)
+ context->huffnode[curnode++].numbits = nodebits;
+
+ /* a one value is an escape code */
+ else
+ {
+ nodebits = bit_buffer_read(&bitbuf, numbits);
+
+ /* a double 1 is just a single 1 */
+ if (nodebits == 1)
+ context->huffnode[curnode++].numbits = nodebits;
+
+ /* otherwise, we need one for value for the repeat count */
+ else
+ {
+ int repcount = bit_buffer_read(&bitbuf, numbits) + 3;
+ while (repcount--)
+ context->huffnode[curnode++].numbits = nodebits;
+ }
+ }
+ }
+
+ /* assign canonical codes for all nodes based on their code lengths */
+ error = huffman_assign_canonical_codes(context);
+ if (error != HUFFERR_NONE)
+ return error;
+
+ /* make sure we ended up with the right number */
+ if (curnode != 256)
+ return HUFFERR_INVALID_DATA;
+
+ *actlength = bit_buffer_read_offset(&bitbuf);
+ return bitbuf.overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ huffman_export_tree - export a huffman tree
+ to a target data stream
+-------------------------------------------------*/
+
+huffman_error huffman_export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+{
+ bit_buffer bitbuf;
+ int repcount;
+ int lastval;
+ int numbits;
+ int i;
+
+ /* initialize the output buffer */
+ bit_buffer_write_init(&bitbuf, dest, dlength);
+
+ /* bits per entry depends on the maxbits */
+ if (context->maxbits >= 16)
+ numbits = 5;
+ else if (context->maxbits >= 8)
+ numbits = 4;
+ else
+ numbits = 3;
+
+ /* RLE encode the lengths */
+ lastval = ~0;
+ repcount = 0;
+ for (i = 0; i < 256; i++)
+ {
+ int newval = context->huffnode[i].numbits;
+
+ /* if we match the previous value, just bump the repcount */
+ if (newval == lastval)
+ repcount++;
+
+ /* otherwise, we need to flush the previous repeats */
+ else
+ {
+ if (repcount != 0)
+ huffman_write_rle_tree_bits(&bitbuf, lastval, repcount, numbits);
+ lastval = newval;
+ repcount = 1;
+ }
+ }
+
+ /* flush the last value */
+ huffman_write_rle_tree_bits(&bitbuf, lastval, repcount, numbits);
+ *actlength = bit_buffer_flush(&bitbuf);
+ return bitbuf.overflow ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ huffman_get_lookup_table - return a pointer to
+ the lookup table
+-------------------------------------------------*/
+
+huffman_error huffman_get_lookup_table(huffman_context *context, const huffman_lookup_value **table)
+{
+ if (context->lookupdirty)
+ {
+ huffman_error error = huffman_build_lookup_table(context);
+ if (error != HUFFERR_NONE)
+ return error;
+ }
+ *table = context->lookup;
+ return HUFFERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ huffman_encode_data - encode data using the
+ current tree
+-------------------------------------------------*/
+
+huffman_error huffman_encode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+{
+ bit_buffer bitbuf;
+ UINT32 soffset;
+
+ /* initialize the output buffer */
+ bit_buffer_write_init(&bitbuf, dest, dlength);
+
+ /* loop over source data and encode */
+ for (soffset = 0; soffset < slength; soffset++)
+ {
+ huffman_node *node = &context->huffnode[source[soffset]];
+ bit_buffer_write(&bitbuf, node->bits, node->numbits);
+ }
+ *actlength = bit_buffer_flush(&bitbuf);
+ return bitbuf.overflow ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ huffman_encode_data_interleaved_2 - encode
+ alternating data with two contexts
+-------------------------------------------------*/
+
+huffman_error huffman_encode_data_interleaved_2(huffman_context *context1, huffman_context *context2, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+{
+ bit_buffer bitbuf;
+ UINT32 soffset;
+
+ /* initialize the output buffer */
+ bit_buffer_write_init(&bitbuf, dest, dlength);
+
+ /* loop over source data and encode */
+ for (soffset = 0; soffset < slength; soffset += 2)
+ {
+ huffman_node *node;
+
+ node = &context1->huffnode[source[soffset + 0]];
+ bit_buffer_write(&bitbuf, node->bits, node->numbits);
+
+ node = &context2->huffnode[source[soffset + 1]];
+ bit_buffer_write(&bitbuf, node->bits, node->numbits);
+ }
+ *actlength = bit_buffer_flush(&bitbuf);
+ return bitbuf.overflow ? HUFFERR_OUTPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ huffman_decode_data - decode data using the
+ current tree
+-------------------------------------------------*/
+
+huffman_error huffman_decode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+{
+ int maxbits = context->maxbits;
+ int shiftbits = 32 - maxbits;
+ const huffman_lookup_value *table;
+ int overflow = FALSE;
+ huffman_error error;
+ UINT32 doffset = 0;
+ UINT32 soffset = 0;
+ UINT32 bitbuf = 0;
+ int sbits = 0;
+
+ /* regenerate the lookup table if necessary */
+ error = huffman_get_lookup_table(context, &table);
+ if (error != HUFFERR_NONE)
+ return error;
+
+ /* decode until we process all of the destination data */
+ for (doffset = 0; doffset < dlength; doffset++)
+ {
+ huffman_lookup_value lookup;
+
+ /* if we don't have enough bits, load up the buffer */
+ if (sbits < maxbits)
+ {
+ while (sbits <= 24)
+ {
+ if (soffset < slength)
+ bitbuf |= source[soffset] << (24 - sbits);
+ soffset++;
+ sbits += 8;
+ }
+ if (sbits < maxbits)
+ overflow = TRUE;
+ }
+
+ /* lookup the data */
+ lookup = table[bitbuf >> shiftbits];
+
+ /* store the upper byte */
+ dest[doffset] = lookup >> 8;
+
+ /* count the bits */
+ lookup &= 0x1f;
+ bitbuf <<= lookup;
+ sbits -= lookup;
+ }
+
+ /* back off soffset while we have whole bytes */
+ while (sbits >= 8)
+ {
+ sbits -= 8;
+ soffset--;
+ }
+ *actlength = soffset;
+ return overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ huffman_decode_data_interleaved_2 - decode
+ interleaved data using two contexts
+-------------------------------------------------*/
+
+huffman_error huffman_decode_data_interleaved_2(huffman_context *context1, huffman_context *context2, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength)
+{
+ int maxbits1 = context1->maxbits, maxbits2 = context2->maxbits;
+ const huffman_lookup_value *table1, *table2;
+ int shiftbits1 = 32 - maxbits1;
+ int shiftbits2 = 32 - maxbits2;
+ int overflow = FALSE;
+ huffman_error error;
+ UINT32 doffset = 0;
+ UINT32 soffset = 0;
+ UINT32 bitbuf = 0;
+ int sbits = 0;
+
+ /* regenerate the lookup table if necessary */
+ error = huffman_get_lookup_table(context1, &table1);
+ if (error != HUFFERR_NONE)
+ return error;
+ error = huffman_get_lookup_table(context2, &table2);
+ if (error != HUFFERR_NONE)
+ return error;
+
+ /* decode until we process all of the destination data */
+ for (doffset = 0; doffset < dlength; doffset += 2)
+ {
+ huffman_lookup_value lookup;
+
+ /* if we don't have enough bits, load up the buffer */
+ if (sbits < maxbits1)
+ {
+ while (sbits <= 24)
+ {
+ if (soffset < slength)
+ bitbuf |= source[soffset] << (24 - sbits);
+ soffset++;
+ sbits += 8;
+ }
+ if (sbits < maxbits1)
+ overflow = TRUE;
+ }
+
+ /* lookup the data */
+ lookup = table1[bitbuf >> shiftbits1];
+
+ /* store the upper byte */
+ dest[doffset + 0] = lookup >> 8;
+
+ /* count the bits */
+ lookup &= 0x1f;
+ bitbuf <<= lookup;
+ sbits -= lookup;
+
+ /* if we don't have enough bits, load up the buffer */
+ if (sbits < maxbits2)
+ {
+ while (sbits <= 24)
+ {
+ if (soffset < slength)
+ bitbuf |= source[soffset] << (24 - sbits);
+ soffset++;
+ sbits += 8;
+ }
+ if (sbits < maxbits2)
+ overflow = TRUE;
+ }
+
+ /* lookup the data */
+ lookup = table2[bitbuf >> shiftbits2];
+
+ /* store the upper byte */
+ dest[doffset + 1] = lookup >> 8;
+
+ /* count the bits */
+ lookup &= 0x1f;
+ bitbuf <<= lookup;
+ sbits -= lookup;
+ }
+
+ /* back off soffset while we have whole bytes */
+ while (sbits >= 8)
+ {
+ sbits -= 8;
+ soffset--;
+ }
+ *actlength = soffset;
+ return overflow ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ huffman_write_rle_tree_bits - write an RLE
+ encoded set of data to a target stream
+-------------------------------------------------*/
+
+static void huffman_write_rle_tree_bits(bit_buffer *bitbuf, int value, int repcount, int numbits)
+{
+ /* loop until we have output all of the repeats */
+ while (repcount > 0)
+ {
+ /* if we have a 1, write it twice as it is an escape code */
+ if (value == 1)
+ {
+ bit_buffer_write(bitbuf, 1, numbits);
+ bit_buffer_write(bitbuf, 1, numbits);
+ repcount--;
+ }
+
+ /* if we have two or fewer in a row, write them raw */
+ else if (repcount <= 2)
+ {
+ bit_buffer_write(bitbuf, value, numbits);
+ repcount--;
+ }
+
+ /* otherwise, write a triple using 1 as the escape code */
+ else
+ {
+ int cur_reps = MIN(repcount - 3, (1 << numbits) - 1);
+ bit_buffer_write(bitbuf, 1, numbits);
+ bit_buffer_write(bitbuf, value, numbits);
+ bit_buffer_write(bitbuf, cur_reps, numbits);
+ repcount -= cur_reps + 3;
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ huffman_tree_node_compare - compare two
+ tree nodes by weight
+-------------------------------------------------*/
+
+static int CLIB_DECL huffman_tree_node_compare(const void *item1, const void *item2)
+{
+ const huffman_node *node1 = *(const huffman_node **)item1;
+ const huffman_node *node2 = *(const huffman_node **)item2;
+ return node2->weight - node1->weight;
+}
+
+
+/*-------------------------------------------------
+ huffman_build_tree - build a huffman tree
+ based on the data distribution
+-------------------------------------------------*/
+
+static int huffman_build_tree(huffman_context *context, const UINT32 *datahisto, UINT32 totaldata, UINT32 totalweight)
+{
+ huffman_node *list[256];
+ int listitems;
+ int nextalloc;
+ int maxbits;
+ int i;
+
+ /* make a list of all non-zero nodes */
+ listitems = 0;
+ memset(context->huffnode, 0, 256 * sizeof(context->huffnode[0]));
+ for (i = 0; i < 256; i++)
+ if (datahisto[i] != 0)
+ {
+ list[listitems++] = &context->huffnode[i];
+ context->huffnode[i].count = datahisto[i];
+
+ /* scale the weight by the current effective length, ensuring we don't go to 0 */
+ context->huffnode[i].weight = (UINT64)datahisto[i] * (UINT64)totalweight / (UINT64)totaldata;
+ if (context->huffnode[i].weight == 0)
+ context->huffnode[i].weight = 1;
+ }
+
+ /* sort the list by weight, largest weight first */
+ qsort(list, listitems, sizeof(list[0]), huffman_tree_node_compare);
+
+ /* now build the tree */
+ nextalloc = 256;
+ while (listitems > 1)
+ {
+ huffman_node *node0, *node1, *newnode;
+
+ /* remove lowest two items */
+ node1 = list[--listitems];
+ node0 = list[--listitems];
+
+ /* create new node */
+ newnode = &context->huffnode[nextalloc++];
+ newnode->parent = NULL;
+ node0->parent = node1->parent = newnode;
+ newnode->weight = node0->weight + node1->weight;
+
+ /* insert into list at appropriate location */
+ for (i = 0; i < listitems; i++)
+ if (newnode->weight > list[i]->weight)
+ {
+ memmove(&list[i+1], &list[i], (listitems - i) * sizeof(list[0]));
+ break;
+ }
+ list[i] = newnode;
+ listitems++;
+ }
+
+ /* compute the number of bits in each code, and fill in another histogram */
+ maxbits = 0;
+ for (i = 0; i < 256; i++)
+ {
+ huffman_node *node = &context->huffnode[i];
+ node->numbits = 0;
+
+ /* if we have a non-zero weight, compute the number of bits */
+ if (node->weight > 0)
+ {
+ huffman_node *curnode;
+
+ /* determine the number of bits for this node */
+ for (curnode = node; curnode->parent != NULL; curnode = curnode->parent)
+ node->numbits++;
+ if (node->numbits == 0)
+ node->numbits = 1;
+
+ /* keep track of the max */
+ maxbits = MAX(maxbits, node->numbits);
+ }
+ }
+
+ return maxbits;
+}
+
+
+/*-------------------------------------------------
+ huffman_assign_canonical_codes - assign
+ canonical codes to all the nodes based on the
+ number of bits in each
+-------------------------------------------------*/
+
+static huffman_error huffman_assign_canonical_codes(huffman_context *context)
+{
+ UINT32 bithisto[33];
+ int curstart;
+ int i;
+
+ /* build up a histogram of bit lengths */
+ memset(bithisto, 0, sizeof(bithisto));
+ for (i = 0; i < 256; i++)
+ {
+ huffman_node *node = &context->huffnode[i];
+ if (node->numbits > context->maxbits)
+ return HUFFERR_INTERNAL_INCONSISTENCY;
+ if (node->numbits <= 32)
+ bithisto[node->numbits]++;
+ }
+
+ /* for each code length, determine the starting code number */
+ curstart = 0;
+ for (i = 32; i > 0; i--)
+ {
+ UINT32 nextstart = (curstart + bithisto[i]) >> 1;
+ if (i != 1 && nextstart * 2 != (curstart + bithisto[i]))
+ return HUFFERR_INTERNAL_INCONSISTENCY;
+ bithisto[i] = curstart;
+ curstart = nextstart;
+ }
+
+ /* now assign canonical codes */
+ for (i = 0; i < 256; i++)
+ {
+ huffman_node *node = &context->huffnode[i];
+ if (node->numbits > 0)
+ node->bits = bithisto[node->numbits]++;
+ }
+
+ /* if there was a decoding table, get rid of it now */
+ context->lookupdirty = TRUE;
+ return HUFFERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ huffman_build_lookup_table - build a lookup
+ table for fast decoding
+-------------------------------------------------*/
+
+static huffman_error huffman_build_lookup_table(huffman_context *context)
+{
+ int i;
+
+ /* allocate a table if needed */
+ if (context->lookup == NULL)
+ context->lookup = malloc((UINT32)sizeof(context->lookup[0]) * (UINT32)(1 << context->maxbits));
+ if (context->lookup == NULL)
+ return HUFFERR_OUT_OF_MEMORY;
+
+ /* now build */
+ for (i = 0; i < 256; i++)
+ {
+ huffman_node *node = &context->huffnode[i];
+ if (node->numbits > 0)
+ {
+ huffman_lookup_value *dest, *destend;
+
+ /* left justify this node's bit values to max bits */
+ int shift = context->maxbits - node->numbits;
+ UINT32 start = node->bits << shift;
+ UINT32 end = ((node->bits + 1) << shift) - 1;
+ huffman_lookup_value value;
+
+ /* set up the entry */
+ value = (i << 8) | node->numbits;
+
+ /* fill all matching entries */
+ dest = &context->lookup[start];
+ destend = &context->lookup[end];
+ while (dest <= destend)
+ *dest++ = value;
+ }
+ }
+
+ /* no longer dirty */
+ context->lookupdirty = FALSE;
+ return HUFFERR_NONE;
+}
diff --git a/src/lib/util/huffman.h b/src/lib/util/huffman.h
new file mode 100644
index 00000000000..efc451b7483
--- /dev/null
+++ b/src/lib/util/huffman.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+
+ huffman.h
+
+ Huffman compression routines.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __HUFFMAN_H__
+
+#include "osdcore.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+enum _huffman_error
+{
+ HUFFERR_NONE = 0,
+ HUFFERR_OUT_OF_MEMORY,
+ HUFFERR_TOO_MANY_BITS,
+ HUFFERR_INVALID_DATA,
+ HUFFERR_INPUT_BUFFER_TOO_SMALL,
+ HUFFERR_OUTPUT_BUFFER_TOO_SMALL,
+ HUFFERR_INTERNAL_INCONSISTENCY
+};
+typedef enum _huffman_error huffman_error;
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef UINT16 huffman_lookup_value;
+
+typedef struct _huffman_context huffman_context;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+huffman_error huffman_create_context(huffman_context **context, int maxbits);
+void huffman_free_context(huffman_context *context);
+
+huffman_error huffman_compute_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 sstride);
+huffman_error huffman_import_tree(huffman_context *context, const UINT8 *source, UINT32 slength, UINT32 *actlength);
+huffman_error huffman_export_tree(huffman_context *context, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
+huffman_error huffman_get_lookup_table(huffman_context *context, const huffman_lookup_value **table);
+
+huffman_error huffman_encode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
+huffman_error huffman_encode_data_interleaved_2(huffman_context *context1, huffman_context *context2, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
+huffman_error huffman_decode_data(huffman_context *context, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
+huffman_error huffman_decode_data_interleaved_2(huffman_context *context1, huffman_context *context2, const UINT8 *source, UINT32 slength, UINT8 *dest, UINT32 dlength, UINT32 *actlength);
+
+#endif
diff --git a/src/lib/util/jedparse.c b/src/lib/util/jedparse.c
new file mode 100644
index 00000000000..5a06b9353a5
--- /dev/null
+++ b/src/lib/util/jedparse.c
@@ -0,0 +1,435 @@
+/***************************************************************************
+
+ jedparse.c
+
+ Parser for .JED files into raw fusemaps.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+
+ Binary file format:
+
+ Offset
+ 0 = Total number of fuses (32 bits)
+ 4 = Raw fuse data, packed 8 bits at a time, LSB to MSB
+
+***************************************************************************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "jedparse.h"
+
+
+
+/***************************************************************************
+ DEBUGGING
+***************************************************************************/
+
+#define LOG_PARSE 0
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _parse_info parse_info;
+struct _parse_info
+{
+ UINT16 checksum; /* checksum value */
+ UINT32 explicit_numfuses; /* explicitly specified number of fuses */
+};
+
+
+
+/***************************************************************************
+ UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ ishex - is a character a valid hex digit?
+-------------------------------------------------*/
+
+static int ishex(char c)
+{
+ return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F');
+}
+
+
+
+/*-------------------------------------------------
+ hexval - the hex value of a given character
+-------------------------------------------------*/
+
+static int hexval(char c)
+{
+ return (c >= '0' && c <= '9') ? (c - '0') : (10 + c - 'A');
+}
+
+
+
+/*-------------------------------------------------
+ isdelim - is a character a JEDEC delimiter?
+-------------------------------------------------*/
+
+static int isdelim(char c)
+{
+ return (c == ' ' || c == 13 || c == 10);
+}
+
+
+
+/*-------------------------------------------------
+ suck_number - read a decimal value from the
+ character stream
+-------------------------------------------------*/
+
+static UINT32 suck_number(const UINT8 **psrc)
+{
+ const UINT8 *src = *psrc;
+ UINT32 value = 0;
+
+ /* skip delimiters */
+ while (isdelim(*src))
+ src++;
+
+ /* loop over and accumulate digits */
+ while (isdigit(*src))
+ {
+ value = value * 10 + *src - '0';
+ src++;
+ }
+
+ /* return a pointer to the string afterwards */
+ *psrc = src;
+ return value;
+}
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ process_field - process a single JEDEC field
+-------------------------------------------------*/
+
+static void process_field(jed_data *data, const UINT8 *cursrc, const UINT8 *srcend, parse_info *pinfo)
+{
+ /* switch off of the field type */
+ switch (*cursrc)
+ {
+ case 'Q':
+ cursrc++;
+ switch (*cursrc)
+ {
+ /* number of fuses */
+ case 'F':
+ cursrc++;
+ pinfo->explicit_numfuses = data->numfuses = suck_number(&cursrc);
+ break;
+ }
+ break;
+
+ /* default fuse state (0 or 1) */
+ case 'F':
+ cursrc++;
+ if (LOG_PARSE) printf("F%c\n", *cursrc);
+ if (*cursrc == '0')
+ memset(data->fusemap, 0x00, sizeof(data->fusemap));
+ else
+ memset(data->fusemap, 0xff, sizeof(data->fusemap));
+ break;
+
+ /* fuse states */
+ case 'L':
+ {
+ UINT32 curfuse;
+
+ /* read the fuse number */
+ cursrc++;
+ curfuse = suck_number(&cursrc);
+ if (LOG_PARSE) printf("L%d\n", curfuse);
+
+ /* read digits, skipping delimiters */
+ for ( ; cursrc < srcend; cursrc++)
+ if (*cursrc == '0' || *cursrc == '1')
+ {
+ jed_set_fuse(data, curfuse, *cursrc - '0');
+ if (LOG_PARSE) printf(" fuse %d = %d\n", curfuse, 0);
+ if (curfuse >= data->numfuses)
+ data->numfuses = curfuse + 1;
+ curfuse++;
+ }
+ break;
+ }
+
+ /* fuse checksum */
+ case 'C':
+ cursrc++;
+ if (cursrc < srcend + 4 && ishex(cursrc[0]) && ishex(cursrc[1]) && ishex(cursrc[2]) && ishex(cursrc[3]))
+ {
+ pinfo->checksum = 0;
+ while (ishex(*cursrc) && cursrc < srcend)
+ pinfo->checksum = (pinfo->checksum << 4) | hexval(*cursrc++);
+ }
+ break;
+ }
+}
+
+
+
+/*-------------------------------------------------
+ jed_parse - parse a .JED file that has been
+ loaded raw into memory
+-------------------------------------------------*/
+
+int jed_parse(const void *data, size_t length, jed_data *result)
+{
+ const UINT8 *cursrc = data;
+ const UINT8 *srcend = cursrc + length;
+ const UINT8 *scan;
+ parse_info pinfo;
+ UINT16 checksum;
+ int i;
+
+ /* initialize the output and the intermediate info struct */
+ memset(result, 0, sizeof(*result));
+ memset(&pinfo, 0, sizeof(pinfo));
+
+ /* first scan for the STX character; ignore anything prior */
+ while (cursrc < srcend && *cursrc != 0x02)
+ cursrc++;
+ if (cursrc >= srcend)
+ return JEDERR_INVALID_DATA;
+
+ /* then scan to see if we have an ETX */
+ scan = cursrc;
+ checksum = 0;
+ while (scan < srcend && *scan != 0x03)
+ checksum += *scan++ & 0x7f;
+ if (scan >= srcend)
+ return JEDERR_INVALID_DATA;
+
+ /* see if there is a transmission checksum at the end */
+ checksum += *scan;
+ if (scan + 4 < srcend && ishex(scan[1]) && ishex(scan[2]) && ishex(scan[3]) && ishex(scan[4]))
+ {
+ UINT16 dessum = (hexval(scan[1]) << 12) | (hexval(scan[2]) << 8) | (hexval(scan[3]) << 4) | hexval(scan[4] << 0);
+ if (dessum != 0 && dessum != checksum)
+ return JEDERR_BAD_XMIT_SUM;
+ }
+
+ /* the ETX becomes the real srcend */
+ srcend = scan;
+
+ /* blast through the comment field */
+ cursrc++;
+ while (cursrc < srcend && *cursrc != '*')
+ cursrc++;
+
+ /* now loop over fields and decide which ones go in the file output */
+ cursrc++;
+ while (cursrc < srcend)
+ {
+ /* skip over delimiters */
+ while (cursrc < srcend && isdelim(*cursrc))
+ cursrc++;
+ if (cursrc >= srcend)
+ break;
+
+ /* end of field is an asterisk -- find it */
+ scan = cursrc;
+ while (scan < srcend && *scan != '*')
+ scan++;
+ if (scan >= srcend)
+ return JEDERR_INVALID_DATA;
+
+ /* process the field */
+ process_field(result, cursrc, scan, &pinfo);
+
+ /* advance past it */
+ cursrc = scan + 1;
+ }
+
+ /* if we got an explicit fuse count, override our computed count */
+ if (pinfo.explicit_numfuses != 0)
+ result->numfuses = pinfo.explicit_numfuses;
+
+ /* clear out leftover bits */
+ if (result->numfuses % 8 != 0)
+ result->fusemap[result->numfuses / 8] &= (1 << (result->numfuses % 8)) - 1;
+ memset(&result->fusemap[(result->numfuses + 7) / 8], 0, sizeof(result->fusemap) - (result->numfuses + 7) / 8);
+
+ /* validate the checksum */
+ checksum = 0;
+ for (i = 0; i < (result->numfuses + 7) / 8; i++)
+ checksum += result->fusemap[i];
+ if (pinfo.checksum != 0 && checksum != pinfo.checksum)
+ return JEDERR_BAD_FUSE_SUM;
+
+ return JEDERR_NONE;
+}
+
+
+
+/*-------------------------------------------------
+ jed_output - generate a new .JED file based
+ on the jed_data provided
+-------------------------------------------------*/
+
+size_t jed_output(const jed_data *data, void *result, size_t length)
+{
+ UINT8 *curdst = result;
+ UINT8 *dstend = curdst + length;
+ int i, zeros, ones;
+ char tempbuf[256];
+ UINT16 checksum;
+ UINT8 defbyte;
+ UINT8 *temp;
+
+ /* always start the DST with a standard header and an STX */
+ tempbuf[0] = 0x02;
+ sprintf(&tempbuf[1], "JEDEC file generated by jedutil*\n");
+ if (curdst + strlen(tempbuf) <= dstend)
+ memcpy(curdst, tempbuf, strlen(tempbuf));
+ curdst += strlen(tempbuf);
+
+ /* append the package information */
+ sprintf(tempbuf, "QF%d*\n", data->numfuses);
+ if (curdst + strlen(tempbuf) <= dstend)
+ memcpy(curdst, tempbuf, strlen(tempbuf));
+ curdst += strlen(tempbuf);
+
+ /* compute the checksum */
+ checksum = 0;
+ for (i = 0; i < data->numfuses / 8; i++)
+ checksum += data->fusemap[i];
+ if (data->numfuses % 8 != 0)
+ checksum += data->fusemap[data->numfuses / 8] & ((1 << (data->numfuses % 8)) - 1);
+
+ /* determine if we are mostly 0's or mostly 1's */
+ for (i = zeros = ones = 0; i < data->numfuses / 8; i++)
+ if (data->fusemap[i] == 0x00)
+ zeros++;
+ else if (data->fusemap[i] == 0xff)
+ ones++;
+ defbyte = (ones > zeros) ? 0xff : 0x00;
+
+ /* output the default fuse state */
+ sprintf(tempbuf, "F%d*\n", defbyte & 1);
+ if (curdst + strlen(tempbuf) <= dstend)
+ memcpy(curdst, tempbuf, strlen(tempbuf));
+ curdst += strlen(tempbuf);
+
+ /* now loop over groups of 32 fuses and output non-default groups */
+ for (i = 0; i < data->numfuses; i += 32)
+ if (data->fusemap[i / 8 + 0] != defbyte ||
+ data->fusemap[i / 8 + 1] != defbyte ||
+ data->fusemap[i / 8 + 2] != defbyte ||
+ data->fusemap[i / 8 + 3] != defbyte)
+ {
+ int stroffs;
+ int j;
+
+ /* build up a string of 32 fuses */
+ stroffs = sprintf(tempbuf, "L%05d ", i);
+ for (j = 0; j < 32 && i+j < data->numfuses; j++)
+ tempbuf[stroffs++] = '0' + jed_get_fuse(data, i + j);
+ stroffs += sprintf(&tempbuf[stroffs], "*\n");
+
+ /* append to the buffer */
+ if (curdst + strlen(tempbuf) <= dstend)
+ memcpy(curdst, tempbuf, strlen(tempbuf));
+ curdst += strlen(tempbuf);
+ }
+
+ /* write the checksum */
+ sprintf(tempbuf, "C%04X*\n", checksum);
+ if (curdst + strlen(tempbuf) <= dstend)
+ memcpy(curdst, tempbuf, strlen(tempbuf));
+ curdst += strlen(tempbuf);
+
+ /* now compute the transmission checksum */
+ checksum = 0;
+ for (temp = result; temp < curdst && temp < dstend; temp++)
+ checksum += *temp & 0x7f;
+ checksum += 0x03;
+
+ /* append the ETX and the transmission checksum */
+ tempbuf[0] = 0x03;
+ sprintf(&tempbuf[1], "%04X", checksum);
+ if (curdst + strlen(tempbuf) <= dstend)
+ memcpy(curdst, tempbuf, strlen(tempbuf));
+ curdst += strlen(tempbuf);
+
+ /* return the final size */
+ return curdst - (UINT8 *)result;
+}
+
+
+
+/*-------------------------------------------------
+ jedbin_parse - parse a binary JED file that
+ has been loaded raw into memory
+-------------------------------------------------*/
+
+int jedbin_parse(const void *data, size_t length, jed_data *result)
+{
+ const UINT8 *cursrc = data;
+
+ /* initialize the output */
+ memset(result, 0, sizeof(*result));
+
+ /* need at least 4 bytes */
+ if (length < 4)
+ return JEDERR_INVALID_DATA;
+
+ /* first unpack the number of fuses */
+ result->numfuses = (cursrc[0] << 24) | (cursrc[1] << 16) | (cursrc[2] << 8) | cursrc[3];
+ cursrc += 4;
+ if (result->numfuses == 0 || result->numfuses > JED_MAX_FUSES)
+ return JEDERR_INVALID_DATA;
+
+ /* now make sure we have enough data in the source */
+ if (length < 4 + (result->numfuses + 7) / 8)
+ return JEDERR_INVALID_DATA;
+
+ /* copy in the data */
+ memcpy(result->fusemap, cursrc, (result->numfuses + 7) / 8);
+ return JEDERR_NONE;
+}
+
+
+
+/*-------------------------------------------------
+ jedbin_output - generate a new binary JED file
+ based on the jed_data provided
+-------------------------------------------------*/
+
+size_t jedbin_output(const jed_data *data, void *result, size_t length)
+{
+ UINT8 *curdst = result;
+
+ /* ensure we have enough room */
+ if (length >= 4 + (data->numfuses + 7) / 8)
+ {
+ /* store the number of fuses */
+ *curdst++ = data->numfuses >> 24;
+ *curdst++ = data->numfuses >> 16;
+ *curdst++ = data->numfuses >> 8;
+ *curdst++ = data->numfuses >> 0;
+
+ /* copy in the rest of the data */
+ memcpy(curdst, data->fusemap, (data->numfuses + 7) / 8);
+ }
+
+ /* return the final size */
+ return 4 + (data->numfuses + 7) / 8;
+}
+
diff --git a/src/lib/util/jedparse.h b/src/lib/util/jedparse.h
new file mode 100644
index 00000000000..4697914cfac
--- /dev/null
+++ b/src/lib/util/jedparse.h
@@ -0,0 +1,89 @@
+/***************************************************************************
+
+ jedparse.h
+
+ Parser for .JED files into raw fusemaps.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __JEDPARSE_H__
+#define __JEDPARSE_H__
+
+#include "osdcore.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define JED_MAX_FUSES (65536)
+
+/* error codes */
+#define JEDERR_NONE 0
+#define JEDERR_INVALID_DATA 1
+#define JEDERR_BAD_XMIT_SUM 2
+#define JEDERR_BAD_FUSE_SUM 3
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _jed_data jed_data;
+struct _jed_data
+{
+ UINT32 numfuses; /* number of defined fuses */
+ UINT8 fusemap[JED_MAX_FUSES / 8];/* array of bit-packed data */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* parse a file (read into memory) into a jed_data structure */
+int jed_parse(const void *data, size_t length, jed_data *result);
+
+/* output a jed_data structure into a well-formatted JED file */
+size_t jed_output(const jed_data *data, void *result, size_t length);
+
+/* parse a binary JED file (read into memory) into a jed_data structure */
+int jedbin_parse(const void *data, size_t length, jed_data *result);
+
+/* output a jed_data structure into a binary JED file */
+size_t jedbin_output(const jed_data *data, void *result, size_t length);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE int jed_get_fuse(const jed_data *data, UINT32 fusenum)
+{
+ if (fusenum < JED_MAX_FUSES)
+ return (data->fusemap[fusenum / 8] >> (fusenum % 8)) & 1;
+ else
+ return 0;
+}
+
+
+INLINE void jed_set_fuse(jed_data *data, UINT32 fusenum, UINT8 value)
+{
+ if (fusenum < JED_MAX_FUSES)
+ {
+ /* set or clear the bit as appropriate */
+ if (value)
+ data->fusemap[fusenum / 8] |= (1 << (fusenum % 8));
+ else
+ data->fusemap[fusenum / 8] &= ~(1 << (fusenum % 8));
+ }
+}
+
+#endif /* __JEDPARSE_H__ */
diff --git a/src/lib/util/md5.c b/src/lib/util/md5.c
new file mode 100644
index 00000000000..28797aa811c
--- /dev/null
+++ b/src/lib/util/md5.c
@@ -0,0 +1,239 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h' header
+ * definitions; now uses stuff from dpkg's config.h.
+ * - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ */
+
+#include <string.h> /* for memcpy() */
+
+#include "md5.h"
+
+#ifndef LSB_FIRST
+void
+byteSwap(UWORD32 *buf, unsigned words)
+{
+ md5byte *p = (md5byte *)buf;
+
+ do {
+ *buf++ = (UWORD32)((unsigned)p[3] << 8 | p[2]) << 16 |
+ ((unsigned)p[1] << 8 | p[0]);
+ p += 4;
+ } while (--words);
+}
+#else
+#define byteSwap(buf,words)
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void
+MD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bytes[0] = 0;
+ ctx->bytes[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void
+MD5Update(struct MD5Context *ctx, md5byte const *buf, unsigned len)
+{
+ UWORD32 t;
+
+ /* Update byte count */
+
+ t = ctx->bytes[0];
+ if ((ctx->bytes[0] = t + len) < t)
+ ctx->bytes[1]++; /* Carry from low to high */
+
+ t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */
+ if (t > len) {
+ memcpy((md5byte *)ctx->in + 64 - t, buf, len);
+ return;
+ }
+ /* First chunk is an odd size */
+ memcpy((md5byte *)ctx->in + 64 - t, buf, t);
+ byteSwap(ctx->in, 16);
+ MD5Transform(ctx->buf, ctx->in);
+ buf += t;
+ len -= t;
+
+ /* Process data in 64-byte chunks */
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteSwap(ctx->in, 16);
+ MD5Transform(ctx->buf, ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void
+MD5Final(md5byte digest[16], struct MD5Context *ctx)
+{
+ int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */
+ md5byte *p = (md5byte *)ctx->in + count;
+
+ /* Set the first char of padding to 0x80. There is always room. */
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 56 bytes (-8..55) */
+ count = 56 - 1 - count;
+
+ if (count < 0) { /* Padding forces an extra block */
+ memset(p, 0, count + 8);
+ byteSwap(ctx->in, 16);
+ MD5Transform(ctx->buf, ctx->in);
+ p = (md5byte *)ctx->in;
+ count = 56;
+ }
+ memset(p, 0, count);
+ byteSwap(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ctx->in[14] = ctx->bytes[0] << 3;
+ ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29;
+ MD5Transform(ctx->buf, ctx->in);
+
+ byteSwap(ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f,w,x,y,z,in,s) \
+ (w += f(x,y,z) + in, w = (w<<s | w>>(32-s)) + x)
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void
+MD5Transform(UWORD32 buf[4], UWORD32 const in[16])
+{
+ register UWORD32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#endif
+
diff --git a/src/lib/util/md5.h b/src/lib/util/md5.h
new file mode 100644
index 00000000000..4a41494e718
--- /dev/null
+++ b/src/lib/util/md5.h
@@ -0,0 +1,42 @@
+/*
+ * This is the header file for the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ *
+ * Changed so as no longer to depend on Colin Plumb's `usual.h'
+ * header definitions; now uses stuff from dpkg's config.h
+ * - Ian Jackson <ijackson@nyx.cs.du.edu>.
+ * Still in the public domain.
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+typedef unsigned int UWORD32;
+
+#define md5byte unsigned char
+
+struct MD5Context {
+ UWORD32 buf[4];
+ UWORD32 bytes[2];
+ UWORD32 in[16];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, md5byte const *buf, unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+void MD5Transform(UWORD32 buf[4], UWORD32 const in[16]);
+
+#endif /* !MD5_H */
+
diff --git a/src/lib/util/options.c b/src/lib/util/options.c
new file mode 100644
index 00000000000..44534e2247d
--- /dev/null
+++ b/src/lib/util/options.c
@@ -0,0 +1,1133 @@
+/***************************************************************************
+
+ options.c
+
+ Core options code code
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include <stdarg.h>
+#include <ctype.h>
+#include "options.h"
+#include "astring.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define MAX_ENTRY_NAMES 4
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* forward references */
+typedef struct _options_data options_data;
+
+
+/* range parameter for minimum/maximum values */
+typedef union _options_range_parameter options_range_parameter;
+union _options_range_parameter
+{
+ float f;
+ int i;
+};
+
+
+/* hash table entries */
+typedef struct _options_hash_entry options_hash_entry;
+struct _options_hash_entry
+{
+ options_hash_entry * next; /* link to the next entry */
+ astring * name; /* name under the current link */
+ options_data * data; /* link to associated options_data */
+};
+
+
+/* information about a single entry in the options */
+struct _options_data
+{
+ options_hash_entry links[MAX_ENTRY_NAMES]; /* array of hash table entries (one per name) */
+ options_data * next; /* link to the next data */
+ UINT32 flags; /* flags from the entry */
+ UINT32 seqid; /* sequence ID; bumped on each change */
+ int error_reported; /* have we reported an error on this option yet? */
+ int priority; /* priority of the data set */
+ astring * data; /* data for this item */
+ astring * defdata; /* default data for this item */
+ const char * description; /* description for this item */
+ options_range_type range_type; /* the type of range to apply to this item */
+ options_range_parameter range_minimum; /* the minimum of the range */
+ options_range_parameter range_maximum; /* the maximum of the range */
+ void (*callback)(core_options *opts, const char *arg); /* callback to be invoked when parsing */
+};
+
+
+/* structure holding information about a collection of options */
+struct _core_options
+{
+ void (*output[OPTMSG_COUNT])(const char *s);/* output callbacks */
+
+ /* linked list, for sequential iteration */
+ options_data * datalist; /* linked list for sequential iteration */
+ options_data ** datalist_nextptr; /* pointer to pointer to tail entry */
+
+ /* hashtable, for fast lookup */
+ options_hash_entry * hashtable[101]; /* hash table for fast lookup */
+};
+
+
+/* information about an in-progress options enumeration */
+struct _options_enumerator
+{
+ options_data * current;
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static options_data *find_entry_data(core_options *opts, const char *string, int is_command_line);
+static void update_data(core_options *opts, options_data *data, const char *newdata, int priority);
+static int parse_option_name(core_options *opts, const char *srcstring, options_data *data);
+
+static void message(core_options *opts, options_message msgtype, const char *format, ...);
+static UINT32 hash_value(core_options *opts, const char *str);
+static void output_printf(void (*output)(const char *s), const char *format, ...);
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+const char *option_unadorned[MAX_UNADORNED_OPTIONS] =
+{
+ "<UNADORNED0>",
+ "<UNADORNED1>",
+ "<UNADORNED2>",
+ "<UNADORNED3>",
+ "<UNADORNED4>",
+ "<UNADORNED5>",
+ "<UNADORNED6>",
+ "<UNADORNED7>",
+ "<UNADORNED8>",
+ "<UNADORNED9>",
+ "<UNADORNED10>",
+ "<UNADORNED11>",
+ "<UNADORNED12>",
+ "<UNADORNED13>",
+ "<UNADORNED14>",
+ "<UNADORNED15>"
+};
+
+
+
+/***************************************************************************
+ OPTIONS COLLECTION MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ options_create - creates a new instance of
+ core options
+-------------------------------------------------*/
+
+core_options *options_create(void (*fail)(const char *message))
+{
+ /* allocate memory for the option block */
+ core_options *opts = (core_options *)malloc(sizeof(*opts));
+ if (opts == NULL)
+ goto error;
+
+ /* and set up the structure */
+ memset(opts, 0, sizeof(*opts));
+ opts->datalist_nextptr = &opts->datalist;
+ return opts;
+
+error:
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ options_free - frees an options object
+-------------------------------------------------*/
+
+void options_free(core_options *opts)
+{
+ options_data *data, *next;
+
+ /* loop over data items and free them */
+ for (data = opts->datalist; data != NULL; data = next)
+ {
+ int linknum;
+
+ next = data->next;
+
+ /* free names */
+ for (linknum = 0; linknum < ARRAY_LENGTH(data->links); linknum++)
+ if (data->links[linknum].name != NULL)
+ astring_free(data->links[linknum].name);
+
+ /* free strings */
+ astring_free(data->data);
+ astring_free(data->defdata);
+
+ /* free the data itself */
+ free(data);
+ }
+
+ /* free the options itself */
+ free(opts);
+}
+
+
+/*-------------------------------------------------
+ options_set_output_callback - installs a callback
+ to be invoked when data is outputted in the
+ process of outputting options
+-------------------------------------------------*/
+
+void options_set_output_callback(core_options *opts, options_message msgtype, void (*callback)(const char *s))
+{
+ opts->output[msgtype] = callback;
+}
+
+
+/*-------------------------------------------------
+ options_revert - revert options at or below
+ a certain priority back to their defaults
+-------------------------------------------------*/
+
+void options_revert(core_options *opts, int priority)
+{
+ options_data *data;
+
+ /* iterate over options and revert to defaults if below the given priority */
+ for (data = opts->datalist; data != NULL; data = data->next)
+ if (data->priority <= priority)
+ {
+ astring_cpy(data->data, data->defdata);
+ data->priority = OPTION_PRIORITY_DEFAULT;
+ }
+}
+
+
+/*-------------------------------------------------
+ options_copy - copy options from one core_options
+ to another
+-------------------------------------------------*/
+
+int options_copy(core_options *dest_opts, core_options *src_opts)
+{
+ options_data *data;
+
+ /* iterate over options in the destination */
+ for (data = dest_opts->datalist; data != NULL; data = data->next)
+ if (!(data->flags & OPTION_HEADER))
+ {
+ options_data *srcdata = find_entry_data(src_opts, astring_c(data->links[0].name), FALSE);
+
+ /* if the option exists in the source, set it in the destination */
+ if (srcdata != NULL)
+ options_set_string(dest_opts, astring_c(srcdata->links[0].name), astring_c(srcdata->data), srcdata->priority);
+ }
+
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ options_equal - compare two sets of options
+-------------------------------------------------*/
+
+int options_equal(core_options *opts1, core_options *opts2)
+{
+ options_data *data;
+
+ /* iterate over options in the first list */
+ for (data = opts1->datalist; data != NULL; data = data->next)
+ if (!(data->flags & OPTION_HEADER))
+ {
+ const char *value1 = options_get_string(opts1, astring_c(data->links[0].name));
+ const char *value2 = options_get_string(opts2, astring_c(data->links[0].name));
+
+ /* if the values differ, return false */
+ if (strcmp(value1, value2) != 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+/***************************************************************************
+ OPTION DEFINITIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ options_add_entries - add entries to the
+ current options sets
+-------------------------------------------------*/
+
+int options_add_entries(core_options *opts, const options_entry *entrylist)
+{
+ /* loop over entries until we hit a NULL name */
+ for ( ; entrylist->name != NULL || (entrylist->flags & OPTION_HEADER); entrylist++)
+ {
+ options_data *match = NULL;
+ int i;
+
+ /* allocate a new item */
+ options_data *data = malloc(sizeof(*data));
+ if (data == NULL)
+ return FALSE;
+ memset(data, 0, sizeof(*data));
+
+ /* parse the option name */
+ if (entrylist->name != NULL)
+ parse_option_name(opts, entrylist->name, data);
+
+ /* do we match an existing entry? */
+ for (i = 0; i < ARRAY_LENGTH(data->links) && match == NULL; i++)
+ if (data->links[i].name != NULL)
+ match = find_entry_data(opts, astring_c(data->links[i].name), FALSE);
+
+ /* if so, throw away this entry and replace the data */
+ if (match != NULL)
+ {
+ /* free what we've allocated so far */
+ for (i = 0; i < ARRAY_LENGTH(data->links); i++)
+ if (data->links[i].name != NULL)
+ astring_free(data->links[i].name);
+ free(data);
+
+ /* use the matching entry as our data */
+ data = match;
+ }
+
+ /* otherwise, finish making the new entry */
+ else
+ {
+ /* allocate strings */
+ data->data = astring_alloc();
+ data->defdata = astring_alloc();
+
+ /* copy the flags, and set the value equal to the default */
+ data->flags = entrylist->flags;
+ data->description = entrylist->description;
+
+ /* add us to the end of the sequential list */
+ *opts->datalist_nextptr = data;
+ opts->datalist_nextptr = &data->next;
+
+ /* add each name to the appropriate hash table with a link back to us */
+ for (i = 0; i < ARRAY_LENGTH(data->links); i++)
+ if (data->links[i].name != NULL)
+ {
+ int hash_entry = hash_value(opts, astring_c(data->links[i].name));
+
+ /* set up link */
+ data->links[i].data = data;
+ data->links[i].next = opts->hashtable[hash_entry];
+ opts->hashtable[hash_entry] = &data->links[i];
+ }
+ }
+
+ /* copy in the data and default data values */
+ if (entrylist->defvalue != NULL)
+ {
+ astring_cpyc(data->data, entrylist->defvalue);
+ astring_cpyc(data->defdata, entrylist->defvalue);
+ }
+ data->priority = OPTION_PRIORITY_DEFAULT;
+ }
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ options_set_option_default_value - change the
+ default value of an option
+-------------------------------------------------*/
+
+int options_set_option_default_value(core_options *opts, const char *name, const char *defvalue)
+{
+ options_data *data = find_entry_data(opts, name, TRUE);
+
+ /* if we don't have an entry for this, fail */
+ if (data == NULL)
+ return FALSE;
+
+ /* update the data and default data; note that we assume that data == defdata */
+ astring_cpyc(data->data, defvalue);
+ astring_cpyc(data->defdata, defvalue);
+ data->priority = OPTION_PRIORITY_DEFAULT;
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ options_set_option_callback - specifies a
+ callback to be invoked when parsing options
+-------------------------------------------------*/
+
+int options_set_option_callback(core_options *opts, const char *name, void (*callback)(core_options *opts, const char *arg))
+{
+ options_data *data = find_entry_data(opts, name, TRUE);
+
+ /* if we don't find an entry, fail */
+ if (data == NULL)
+ return FALSE;
+
+ /* set the callback */
+ data->callback = callback;
+ return TRUE;
+}
+
+
+
+/***************************************************************************
+ OPTION DATA EXTRACTION
+***************************************************************************/
+
+/*-------------------------------------------------
+ options_parse_command_line - parse a series
+ of command line arguments
+-------------------------------------------------*/
+
+int options_parse_command_line(core_options *opts, int argc, char **argv, int priority)
+{
+ int unadorned_index = 0;
+ int arg;
+
+ /* loop over commands, looking for options */
+ for (arg = 1; arg < argc; arg++)
+ {
+ const char *optionname, *newdata;
+ options_data *data;
+ int is_unadorned;
+
+ /* determine the entry name to search for */
+ is_unadorned = (argv[arg][0] != '-');
+ if (!is_unadorned)
+ optionname = &argv[arg][1];
+ else
+ optionname = OPTION_UNADORNED(unadorned_index);
+
+ /* find our entry */
+ data = find_entry_data(opts, optionname, TRUE);
+ if (data == NULL)
+ {
+ message(opts, OPTMSG_ERROR, "Error: unknown option: %s\n", argv[arg]);
+ return 1;
+ }
+
+ /* if unadorned, we have to bump the count (unless if the option repeats) */
+ if (is_unadorned && !(data->flags & OPTION_REPEATS))
+ unadorned_index++;
+
+ /* get the data for this argument, special casing booleans */
+ if ((data->flags & (OPTION_BOOLEAN | OPTION_COMMAND)) != 0)
+ newdata = (strncmp(&argv[arg][1], "no", 2) == 0) ? "0" : "1";
+ else if (argv[arg][0] != '-')
+ newdata = argv[arg];
+ else if (arg + 1 < argc)
+ newdata = argv[++arg];
+ else
+ {
+ message(opts, OPTMSG_ERROR, "Error: option %s expected a parameter\n", argv[arg]);
+ return 1;
+ }
+
+ /* if the option is deprecated or internal, don't process further */
+ if ((data->flags & (OPTION_DEPRECATED | OPTION_INTERNAL)) != 0)
+ continue;
+
+ /* invoke callback, if present */
+ if (data->callback != NULL)
+ (*data->callback)(opts, newdata);
+
+ /* allocate a new copy of data for this */
+ update_data(opts, data, newdata, priority);
+ }
+ return 0;
+}
+
+
+/*-------------------------------------------------
+ options_parse_ini_file - parse a series
+ of entries in an INI file
+-------------------------------------------------*/
+
+int options_parse_ini_file(core_options *opts, core_file *inifile, int priority)
+{
+ char buffer[4096];
+
+ /* loop over data */
+ while (core_fgets(buffer, ARRAY_LENGTH(buffer), inifile) != NULL)
+ {
+ char *optionname, *optiondata, *temp;
+ options_data *data;
+ int inquotes = FALSE;
+
+ /* find the name */
+ for (optionname = buffer; *optionname != 0; optionname++)
+ if (!isspace(*optionname))
+ break;
+
+ /* skip comments */
+ if (*optionname == 0 || *optionname == '#')
+ continue;
+
+ /* scan forward to find the first space */
+ for (temp = optionname; *temp != 0; temp++)
+ if (isspace(*temp))
+ break;
+
+ /* if we hit the end early, print a warning and continue */
+ if (*temp == 0)
+ {
+ message(opts, OPTMSG_WARNING, "Warning: invalid line in INI: %s", buffer);
+ continue;
+ }
+
+ /* NULL-terminate */
+ *temp++ = 0;
+ optiondata = temp;
+
+ /* scan the data, stopping when we hit a comment */
+ for (temp = optiondata; *temp != 0; temp++)
+ {
+ if (*temp == '"')
+ inquotes = !inquotes;
+ if (*temp == '#' && !inquotes)
+ break;
+ }
+ *temp = 0;
+
+ /* find our entry */
+ data = find_entry_data(opts, optionname, FALSE);
+ if (data == NULL)
+ {
+ message(opts, OPTMSG_WARNING, "Warning: unknown option in INI: %s\n", optionname);
+ continue;
+ }
+ if ((data->flags & (OPTION_DEPRECATED | OPTION_INTERNAL)) != 0)
+ continue;
+
+ /* allocate a new copy of data for this */
+ update_data(opts, data, optiondata, priority);
+ }
+ return 0;
+}
+
+
+
+/***************************************************************************
+ OPTIONS OUTPUT
+***************************************************************************/
+
+/*-------------------------------------------------
+ options_output_diff_ini_file - output the diff
+ of the current state from a base state to an
+ INI file
+-------------------------------------------------*/
+
+void options_output_diff_ini_file(core_options *opts, core_options *baseopts, core_file *inifile)
+{
+ options_data *data;
+ const char *last_header = NULL;
+ const char *name;
+ const char *value;
+ options_data *basedata;
+
+ /* loop over all items */
+ for (data = opts->datalist; data != NULL; data = data->next)
+ {
+ /* header: record description */
+ if ((data->flags & OPTION_HEADER) != 0)
+ last_header = data->description;
+
+ /* otherwise, output entries for all non-deprecated and non-command items (if not in baseopts) */
+ else if ((data->flags & (OPTION_DEPRECATED | OPTION_INTERNAL | OPTION_COMMAND)) == 0)
+ {
+ /* get name and data of this value */
+ name = astring_c(data->links[0].name);
+ value = astring_c(data->data);
+
+ /* look up counterpart in baseopts, if baseopts is specified */
+ basedata = (baseopts != NULL) ? find_entry_data(baseopts, name, FALSE) : NULL;
+
+ /* is our data different, or not in baseopts? */
+ if ((basedata == NULL) || (strcmp(value, astring_c(basedata->data)) != 0))
+ {
+ /* output header, if we have one */
+ if (last_header != NULL)
+ {
+ core_fprintf(inifile, "\n#\n# %s\n#\n", last_header);
+ last_header = NULL;
+ }
+
+ /* and finally output the data */
+ if (strchr(value, ' ') != NULL)
+ core_fprintf(inifile, "%-25s \"%s\"\n", name, value);
+ else
+ core_fprintf(inifile, "%-25s %s\n", name, value);
+ }
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ options_output_ini_file - output the current
+ state to an INI file
+-------------------------------------------------*/
+
+void options_output_ini_file(core_options *opts, core_file *inifile)
+{
+ options_output_diff_ini_file(opts, NULL, inifile);
+}
+
+
+/*-------------------------------------------------
+ options_output_ini_file - output the current
+ state to an INI file
+-------------------------------------------------*/
+
+void options_output_ini_stdfile(core_options *opts, FILE *inifile)
+{
+ options_data *data;
+
+ /* loop over all items */
+ for (data = opts->datalist; data != NULL; data = data->next)
+ {
+ /* header: just print */
+ if ((data->flags & OPTION_HEADER) != 0)
+ fprintf(inifile, "\n#\n# %s\n#\n", data->description);
+
+ /* otherwise, output entries for all non-deprecated and non-command items */
+ else if ((data->flags & (OPTION_DEPRECATED | OPTION_INTERNAL | OPTION_COMMAND)) == 0)
+ {
+ if (astring_chr(data->data, 0, ' ') != -1)
+ fprintf(inifile, "%-25s \"%s\"\n", astring_c(data->links[0].name), astring_c(data->data));
+ else
+ fprintf(inifile, "%-25s %s\n", astring_c(data->links[0].name), astring_c(data->data));
+ }
+ }
+}
+
+
+/*-------------------------------------------------
+ options_output_help - output option help to
+ a file
+-------------------------------------------------*/
+
+void options_output_help(core_options *opts, void (*output)(const char *))
+{
+ options_data *data;
+
+ /* loop over all items */
+ for (data = opts->datalist; data != NULL; data = data->next)
+ {
+ /* header: just print */
+ if ((data->flags & OPTION_HEADER) != 0)
+ output_printf(output, "\n#\n# %s\n#\n", data->description);
+
+ /* otherwise, output entries for all non-deprecated items */
+ else if ((data->flags & (OPTION_DEPRECATED | OPTION_INTERNAL)) == 0 && data->description != NULL)
+ output_printf(output, "-%-20s%s\n", astring_c(data->links[0].name), data->description);
+ }
+}
+
+
+
+/***************************************************************************
+ OPTIONS READING
+***************************************************************************/
+
+/*-------------------------------------------------
+ options_get_string - return data formatted
+ as a string
+-------------------------------------------------*/
+
+const char *options_get_string(core_options *opts, const char *name)
+{
+ options_data *data = find_entry_data(opts, name, FALSE);
+ const char *value = "";
+
+ /* error if not found */
+ if (data == NULL)
+ message(opts, OPTMSG_ERROR, "Unexpected option %s queried\n", name);
+
+ /* copy if non-NULL */
+ else
+ value = astring_c(data->data);
+
+ return value;
+}
+
+
+/*-------------------------------------------------
+ options_get_bool - return data formatted as
+ a boolean
+-------------------------------------------------*/
+
+int options_get_bool(core_options *opts, const char *name)
+{
+ options_data *data = find_entry_data(opts, name, FALSE);
+ int value = FALSE;
+
+ /* error if not found */
+ if (data == NULL)
+ message(opts, OPTMSG_ERROR, "Unexpected boolean option %s queried\n", name);
+
+ /* also error if we don't have a valid boolean value */
+ else if (sscanf(astring_c(data->data), "%d", &value) != 1 || value < 0 || value > 1)
+ {
+ options_set_string(opts, name, astring_c(data->defdata), 0);
+ sscanf(astring_c(data->data), "%d", &value);
+ if (!data->error_reported)
+ {
+ message(opts, OPTMSG_ERROR, "Illegal boolean value for %s; reverting to %d\n", astring_c(data->links[0].name), value);
+ data->error_reported = TRUE;
+ }
+ }
+ return value;
+}
+
+
+/*-------------------------------------------------
+ options_get_int - return data formatted as
+ an integer
+-------------------------------------------------*/
+
+int options_get_int(core_options *opts, const char *name)
+{
+ options_data *data = find_entry_data(opts, name, FALSE);
+ int value = 0;
+
+ /* error if not found */
+ if (data == NULL)
+ message(opts, OPTMSG_ERROR, "Unexpected integer option %s queried\n", name);
+
+ /* also error if we don't have a valid integer value */
+ else if (sscanf(astring_c(data->data), "%d", &value) != 1)
+ {
+ options_set_string(opts, name, astring_c(data->defdata), 0);
+ sscanf(astring_c(data->data), "%d", &value);
+ if (!data->error_reported)
+ {
+ message(opts, OPTMSG_ERROR, "Illegal integer value for %s; reverting to %d\n", astring_c(data->links[0].name), value);
+ data->error_reported = TRUE;
+ }
+ }
+ return value;
+}
+
+
+/*-------------------------------------------------
+ options_get_float - return data formatted as
+ a float
+-------------------------------------------------*/
+
+float options_get_float(core_options *opts, const char *name)
+{
+ options_data *data = find_entry_data(opts, name, FALSE);
+ float value = 0;
+
+ /* error if not found */
+ if (data == NULL)
+ message(opts, OPTMSG_ERROR, "Unexpected float option %s queried\n", name);
+
+ /* also error if we don't have a valid floating point value */
+ else if (sscanf(astring_c(data->data), "%f", &value) != 1)
+ {
+ options_set_string(opts, name, astring_c(data->defdata), 0);
+ sscanf(astring_c(data->data), "%f", &value);
+ if (!data->error_reported)
+ {
+ message(opts, OPTMSG_ERROR, "Illegal float value for %s; reverting to %f\n", astring_c(data->links[0].name), (double)value);
+ data->error_reported = TRUE;
+ }
+ }
+ return value;
+}
+
+
+/*-------------------------------------------------
+ options_get_seqid - return the seqid for an
+ entry
+-------------------------------------------------*/
+
+UINT32 options_get_seqid(core_options *opts, const char *name)
+{
+ options_data *data = find_entry_data(opts, name, FALSE);
+ return (data == NULL) ? 0 : data->seqid;
+}
+
+
+
+/***************************************************************************
+ OPTIONS SETTING
+***************************************************************************/
+
+/*-------------------------------------------------
+ options_set_string - set a string value
+-------------------------------------------------*/
+
+void options_set_string(core_options *opts, const char *name, const char *value, int priority)
+{
+ options_data *data = find_entry_data(opts, name, FALSE);
+ update_data(opts, data, value, priority);
+}
+
+
+/*-------------------------------------------------
+ options_set_bool - set a boolean value
+-------------------------------------------------*/
+
+void options_set_bool(core_options *opts, const char *name, int value, int priority)
+{
+ char temp[4];
+ sprintf(temp, "%d", value ? 1 : 0);
+ options_set_string(opts, name, temp, priority);
+}
+
+
+/*-------------------------------------------------
+ options_set_int - set an integer value
+-------------------------------------------------*/
+
+void options_set_int(core_options *opts, const char *name, int value, int priority)
+{
+ char temp[20];
+ sprintf(temp, "%d", value);
+ options_set_string(opts, name, temp, priority);
+}
+
+
+/*-------------------------------------------------
+ options_set_float - set a float value
+-------------------------------------------------*/
+
+void options_set_float(core_options *opts, const char *name, float value, int priority)
+{
+ char temp[100];
+ sprintf(temp, "%f", value);
+ options_set_string(opts, name, temp, priority);
+}
+
+
+
+/***************************************************************************
+ OPTION DEFINITION QUERIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ options_enumerator_begin - retrieve the range of
+ a float option
+-------------------------------------------------*/
+
+options_enumerator *options_enumerator_begin(core_options *opts)
+{
+ options_enumerator *enumerator;
+
+ /* allocate memory for the enumerator */
+ enumerator = malloc(sizeof(*enumerator));
+ if (enumerator == NULL)
+ return NULL;
+
+ /* start at the head of the list */
+ enumerator->current = opts->datalist;
+ return enumerator;
+}
+
+
+
+/*-------------------------------------------------
+ options_enumerator_next - returns the current
+ option and advances the enumerator
+-------------------------------------------------*/
+
+const char *options_enumerator_next(options_enumerator *enumerator)
+{
+ astring *option_name = NULL;
+
+ /* be sure to skip over false options */
+ while (option_name == NULL && enumerator->current != NULL)
+ {
+ /* retrieve the current option name and advance the enumerator */
+ option_name = enumerator->current->links[0].name;
+ enumerator->current = enumerator->current->next;
+ }
+ return (option_name != NULL) ? astring_c(option_name) : NULL;
+}
+
+
+
+/*-------------------------------------------------
+ options_enumerator_free - disposes an options
+ enumerator
+-------------------------------------------------*/
+
+void options_enumerator_free(options_enumerator *enumerator)
+{
+ free(enumerator);
+}
+
+
+/*-------------------------------------------------
+ options_get_range_type - determine the type
+ of range for a particular option
+-------------------------------------------------*/
+
+options_range_type options_get_range_type(core_options *opts, const char *name)
+{
+ options_data *data = find_entry_data(opts, name, FALSE);
+ return data->range_type;
+}
+
+
+/*-------------------------------------------------
+ options_get_range_int - retrieve the range of
+ an integer option
+-------------------------------------------------*/
+
+void options_get_range_int(core_options *opts, const char *name, int *minval, int *maxval)
+{
+ options_data *data = find_entry_data(opts, name, FALSE);
+ *minval = data->range_minimum.i;
+ *maxval = data->range_maximum.i;
+}
+
+
+
+/*-------------------------------------------------
+ options_get_range_float - retrieve the range of
+ a float option
+-------------------------------------------------*/
+
+void options_get_range_float(core_options *opts, const char *name, float *minval, float *maxval)
+{
+ options_data *data = find_entry_data(opts, name, FALSE);
+ *minval = data->range_minimum.f;
+ *maxval = data->range_maximum.f;
+}
+
+
+
+/***************************************************************************
+ INTERNAL UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ find_entry_data - locate an entry whose name
+ matches the given string
+-------------------------------------------------*/
+
+static options_data *find_entry_data(core_options *opts, const char *string, int is_command_line)
+{
+ int hash_entry = hash_value(opts, string);
+ options_hash_entry *link;
+
+ /* scan all entries */
+ for (link = opts->hashtable[hash_entry]; link != NULL; link = link->next)
+ if (!(link->data->flags & OPTION_HEADER) && link->name != NULL && astring_cmpc(link->name, string) == 0)
+ return link->data;
+
+ /* haven't found it? if we are prefixed with "no", then try to search for that */
+ if (is_command_line && string[0] == 'n' && string[1] == 'o')
+ {
+ options_data *data = find_entry_data(opts, &string[2], FALSE);
+ if (data != NULL && (data->flags & OPTION_BOOLEAN))
+ return data;
+ }
+
+ /* didn't find it at all */
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ update_data - update the data value for a
+ given entry
+-------------------------------------------------*/
+
+static void update_data(core_options *opts, options_data *data, const char *newdata, int priority)
+{
+ const char *dataend = newdata + strlen(newdata) - 1;
+ const char *datastart = newdata;
+ float f;
+ int i;
+
+ /* strip off leading/trailing spaces */
+ while (isspace(*datastart) && datastart <= dataend)
+ datastart++;
+ while (isspace(*dataend) && datastart <= dataend)
+ dataend--;
+
+ /* strip off quotes */
+ if (datastart != dataend && *datastart == '"' && *dataend == '"')
+ datastart++, dataend--;
+
+ /* check against range */
+ switch (data->range_type)
+ {
+ case OPTION_RANGE_NONE:
+ /* do nothing */
+ break;
+
+ case OPTION_RANGE_INT:
+ /* check against integer range */
+ i = 0;
+ if (sscanf(datastart, "%d", &i) != 1)
+ {
+ message(opts, OPTMSG_ERROR, "Illegal integer value for %s; keeping value of %s\n", astring_c(data->links[0].name), astring_c(data->data));
+ data->error_reported = TRUE;
+ return;
+ }
+ if (i < data->range_minimum.i || i > data->range_maximum.i)
+ {
+ message(opts, OPTMSG_ERROR, "Invalid %s value (must be between %i and %i); keeping value of %s\n",
+ astring_c(data->links[0].name), data->range_minimum.i, data->range_maximum.i, astring_c(data->data));
+ data->error_reported = TRUE;
+ return;
+ }
+ break;
+
+ case OPTION_RANGE_FLOAT:
+ /* check against float range */
+ f = 0;
+ if (sscanf(datastart, "%f", &f) != 1)
+ {
+ message(opts, OPTMSG_ERROR, "Illegal float value for %s; keeping value of %s\n", astring_c(data->links[0].name), astring_c(data->data));
+ data->error_reported = TRUE;
+ return;
+ }
+ if (f < data->range_minimum.f || f > data->range_maximum.f)
+ {
+ message(opts, OPTMSG_ERROR, "Invalid %s value (must be between %f and %f); keeping value of %s\n",
+ astring_c(data->links[0].name), data->range_minimum.f, data->range_maximum.f, astring_c(data->data));
+ data->error_reported = TRUE;
+ return;
+ }
+ break;
+ }
+
+ /* ignore if we don't have priority */
+ if (priority < data->priority)
+ return;
+
+ /* allocate a copy of the data */
+ astring_cpych(data->data, datastart, dataend + 1 - datastart);
+ data->priority = priority;
+
+ /* bump the seqid and clear the error reporting */
+ data->seqid++;
+ data->error_reported = FALSE;
+}
+
+
+/*-------------------------------------------------
+ parse_option_name - read data from an option_entry
+ name into an option_data structure
+-------------------------------------------------*/
+
+static int parse_option_name(core_options *opts, const char *srcstring, options_data *data)
+{
+ const char *start;
+ const char *end = NULL;
+ int curentry;
+
+ /* start with the original string and loop over entries */
+ start = srcstring;
+ for (curentry = 0; curentry < ARRAY_LENGTH(data->links); curentry++)
+ {
+ /* find the end of this entry and copy the string */
+ for (end = start; *end != 0 && *end != ';' && *end != '('; end++)
+ ;
+ data->links[curentry].name = astring_dupch(start, end - start);
+
+ /* if we hit the end of the source, stop */
+ if (*end != ';')
+ break;
+ start = end + 1;
+ }
+
+ /* have we found a range? */
+ if (end != NULL && *end == '(')
+ {
+ if (sscanf(end, "(%d-%d)", &data->range_minimum.i, &data->range_maximum.i) == 2)
+ data->range_type = OPTION_RANGE_INT;
+ else if (sscanf(end, "(%f-%f)", &data->range_minimum.f, &data->range_maximum.f) == 2)
+ data->range_type = OPTION_RANGE_FLOAT;
+ }
+ return curentry;
+}
+
+
+/*-------------------------------------------------
+ message - outputs a message to a listener
+-------------------------------------------------*/
+
+static void message(core_options *opts, options_message msgtype, const char *format, ...)
+{
+ char buf[1024];
+ va_list argptr;
+
+ /* output a message if there is a non-NULL handler for it */
+ if (opts->output[msgtype] != NULL)
+ {
+ va_start(argptr, format);
+ vsprintf(buf, format, argptr);
+ va_end(argptr);
+
+ (*opts->output[msgtype])(buf);
+ }
+}
+
+
+/*-------------------------------------------------
+ hash_value - computes the hash value for a string
+-------------------------------------------------*/
+
+static UINT32 hash_value(core_options *opts, const char *str)
+{
+ UINT32 hash = 5381;
+ int c;
+
+ while ((c = *str++) != 0)
+ hash = ((hash << 5) + hash) + c;
+
+ return hash % ARRAY_LENGTH(opts->hashtable);
+}
+
+
+/*-------------------------------------------------
+ output_printf - outputs an arbitrary message
+ to a callback
+-------------------------------------------------*/
+
+static void output_printf(void (*output)(const char *s), const char *format, ...)
+{
+ char buf[1024];
+ va_list argptr;
+
+ va_start(argptr, format);
+ vsprintf(buf, format, argptr);
+ va_end(argptr);
+
+ output(buf);
+}
diff --git a/src/lib/util/options.h b/src/lib/util/options.h
new file mode 100644
index 00000000000..35abc73f226
--- /dev/null
+++ b/src/lib/util/options.h
@@ -0,0 +1,216 @@
+/***************************************************************************
+
+ options.h
+
+ Core options code code
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __OPTIONS_H__
+#define __OPTIONS_H__
+
+#include "osdcore.h"
+#include "corefile.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* unadorned option names */
+#define MAX_UNADORNED_OPTIONS 16
+#define OPTION_UNADORNED(x) (((x) < MAX_UNADORNED_OPTIONS) ? option_unadorned[x] : "")
+
+/* option flags */
+#define OPTION_BOOLEAN 0x0001 /* option is a boolean value */
+#define OPTION_DEPRECATED 0x0002 /* option is deprecated */
+#define OPTION_COMMAND 0x0004 /* option is a command */
+#define OPTION_HEADER 0x0008 /* text-only header */
+#define OPTION_INTERNAL 0x0010 /* option is internal-only */
+#define OPTION_REPEATS 0x0020 /* unadorned option repeats */
+
+/* option priorities */
+#define OPTION_PRIORITY_DEFAULT 0 /* defaults are at 0 priority */
+#define OPTION_PRIORITY_LOW 50 /* low priority */
+#define OPTION_PRIORITY_NORMAL 100 /* normal priority */
+#define OPTION_PRIORITY_HIGH 150 /* high priority */
+#define OPTION_PRIORITY_MAXIMUM 255 /* maximum priority */
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* opaque type representing a collection of options */
+typedef struct _core_options core_options;
+
+/* opaque type use for enumeration of options */
+typedef struct _options_enumerator options_enumerator;
+
+/* describes a single option with its description and default value */
+typedef struct _options_entry options_entry;
+struct _options_entry
+{
+ const char * name; /* name on the command line */
+ const char * defvalue; /* default value of this argument */
+ UINT32 flags; /* flags to describe the option */
+ const char * description; /* description for -showusage */
+};
+
+/* output messages are one of the following types */
+enum _options_message
+{
+ OPTMSG_INFO,
+ OPTMSG_WARNING,
+ OPTMSG_ERROR,
+ OPTMSG_COUNT
+};
+typedef enum _options_message options_message;
+
+/* option ranges are one of the following types */
+enum _options_range_type
+{
+ OPTION_RANGE_NONE,
+ OPTION_RANGE_INT,
+ OPTION_RANGE_FLOAT
+};
+typedef enum _options_range_type options_range_type;
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+extern const char *option_unadorned[MAX_UNADORNED_OPTIONS];
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- options collection management ----- */
+
+/* create a new collection of options */
+core_options *options_create(void (*fail)(const char *message));
+
+/* free a collection of options */
+void options_free(core_options *opts);
+
+/* set a callback for a particular class of message */
+void options_set_output_callback(core_options *opts, options_message msgtype, void (*callback)(const char *s));
+
+/* revert options at or below a certain priority back to their defaults */
+void options_revert(core_options *opts, int priority);
+
+/* copy one collection of options into another */
+int options_copy(core_options *dest_opts, core_options *src_opts);
+
+/* compare two collections of options */
+int options_equal(core_options *opts1, core_options *opts2);
+
+
+
+/* ----- option definitions ----- */
+
+/* add a set of entries to an options collection */
+int options_add_entries(core_options *opts, const options_entry *entrylist);
+
+/* set the default value for a particular option entry */
+int options_set_option_default_value(core_options *opts, const char *name, const char *defvalue);
+
+/* set a callback for a particular option entry */
+int options_set_option_callback(core_options *opts, const char *name, void (*callback)(core_options *opts, const char *arg));
+
+
+
+/* ----- option data extraction ----- */
+
+/* parse option data from a command line */
+int options_parse_command_line(core_options *opts, int argc, char **argv, int priority);
+
+/* parse option data from an INI file */
+int options_parse_ini_file(core_options *opts, core_file *inifile, int priority);
+
+
+
+/* ----- options output ----- */
+
+/* output option data to an INI file */
+void options_output_ini_file(core_options *opts, core_file *inifile);
+
+/* output differing option data to an INI file */
+void options_output_diff_ini_file(core_options *opts, core_options *baseopts, core_file *inifile);
+
+/* output option data to a standard file handle */
+void options_output_ini_stdfile(core_options *opts, FILE *inifile);
+
+/* output help using the specified output function */
+void options_output_help(core_options *opts, void (*output)(const char *s));
+
+
+
+/* ----- options reading ----- */
+
+/* read an option as a string */
+const char *options_get_string(core_options *opts, const char *name);
+
+/* read an option as a boolean */
+int options_get_bool(core_options *opts, const char *name);
+
+/* read an option as an integer */
+int options_get_int(core_options *opts, const char *name);
+
+/* read an option as a floating point value */
+float options_get_float(core_options *opts, const char *name);
+
+/* read an option as a string */
+UINT32 options_get_seqid(core_options *opts, const char *name);
+
+
+
+/* ----- options setting ----- */
+
+/* set an option as a string */
+void options_set_string(core_options *opts, const char *name, const char *value, int priority);
+
+/* set an option as a boolean */
+void options_set_bool(core_options *opts, const char *name, int value, int priority);
+
+/* set an option as an integer */
+void options_set_int(core_options *opts, const char *name, int value, int priority);
+
+/* set an option as a floating point value */
+void options_set_float(core_options *opts, const char *name, float value, int priority);
+
+
+
+/* ----- option definition queries ----- */
+
+/* begin enumerating option definitions */
+options_enumerator *options_enumerator_begin(core_options *opts);
+
+/* get the next option in sequence */
+const char *options_enumerator_next(options_enumerator *enumerator);
+
+/* free memory allocated for enumeration */
+void options_enumerator_free(options_enumerator *enumerator);
+
+/* get the type of range for a given option */
+options_range_type options_get_range_type(core_options *opts, const char *name);
+
+/* return an integer range for a given option */
+void options_get_range_int(core_options *opts, const char *name, int *minval, int *maxval);
+
+/* return a floating point range for a given option */
+void options_get_range_float(core_options *opts, const char *name, float *minval, float *maxval);
+
+
+#endif /* __OPTIONS_H__ */
diff --git a/src/lib/util/palette.c b/src/lib/util/palette.c
new file mode 100644
index 00000000000..83b1a851b02
--- /dev/null
+++ b/src/lib/util/palette.c
@@ -0,0 +1,651 @@
+/******************************************************************************
+
+ palette.c
+
+ Palette handling functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+******************************************************************************/
+
+#include "palette.h"
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* object to track dirty states */
+typedef struct _dirty_state dirty_state;
+struct _dirty_state
+{
+ UINT32 * dirty; /* bitmap of dirty entries */
+ UINT32 mindirty; /* minimum dirty entry */
+ UINT32 maxdirty; /* minimum dirty entry */
+};
+
+
+/* a single palette client */
+struct _palette_client
+{
+ palette_client *next; /* pointer to next client */
+ palette_t * palette; /* reference to the palette */
+ dirty_state live; /* live dirty state */
+ dirty_state previous; /* previous dirty state */
+};
+
+
+/* a palette object */
+struct _palette_t
+{
+ UINT32 refcount; /* reference count on the palette */
+ UINT32 numcolors; /* number of colors in the palette */
+ UINT32 numgroups; /* number of groups in the palette */
+
+ rgb_t * entry_color; /* array of raw colors */
+ float * entry_contrast; /* contrast value for each entry */
+ rgb_t * adjusted_color; /* array of adjusted colors */
+ rgb_t * adjusted_rgb15; /* array of adjusted colors as RGB15 */
+
+ float * group_bright; /* brightness value for each group */
+ float * group_contrast; /* contrast value for each group */
+
+ palette_client *client_list; /* list of clients for this palette */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void internal_palette_free(palette_t *palette);
+static void update_adjusted_color(palette_t *palette, UINT32 group, UINT32 index);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ adjust_palette_entry - adjust a palette
+ entry for brightness
+-------------------------------------------------*/
+
+INLINE rgb_t adjust_palette_entry(rgb_t entry, float brightness, float contrast)
+{
+ int r = rgb_clamp((float)RGB_RED(entry) * contrast + brightness);
+ int g = rgb_clamp((float)RGB_GREEN(entry) * contrast + brightness);
+ int b = rgb_clamp((float)RGB_BLUE(entry) * contrast + brightness);
+ return MAKE_RGB(r,g,b);
+}
+
+
+
+/***************************************************************************
+ PALETTE ALLOCATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ palette_alloc - allocate a new palette object
+ and take a single reference on it
+-------------------------------------------------*/
+
+palette_t *palette_alloc(UINT32 numcolors, UINT32 numgroups)
+{
+ palette_t *palette;
+ UINT32 index;
+
+ /* allocate memory */
+ palette = malloc(sizeof(*palette));
+ if (palette == NULL)
+ goto error;
+ memset(palette, 0, sizeof(*palette));
+
+ /* allocate an array of palette entries and individual contrasts for each */
+ palette->entry_color = malloc(sizeof(*palette->entry_color) * numcolors);
+ palette->entry_contrast = malloc(sizeof(*palette->entry_contrast) * numcolors);
+ if (palette->entry_color == NULL || palette->entry_contrast == NULL)
+ goto error;
+
+ /* initialize the entries */
+ for (index = 0; index < numcolors; index++)
+ {
+ palette->entry_color[index] = RGB_BLACK;
+ palette->entry_contrast[index] = 1.0f;
+ }
+
+ /* allocate an array of brightness and contrast for each group */
+ palette->group_bright = malloc(sizeof(*palette->group_bright) * numgroups);
+ palette->group_contrast = malloc(sizeof(*palette->group_contrast) * numgroups);
+ if (palette->group_bright == NULL || palette->group_contrast == NULL)
+ goto error;
+
+ /* initialize the entries */
+ for (index = 0; index < numgroups; index++)
+ {
+ palette->group_bright[index] = 0.0f;
+ palette->group_contrast[index] = 1.0f;
+ }
+
+ /* allocate arrays for the adjusted colors */
+ palette->adjusted_color = malloc(sizeof(*palette->adjusted_color) * (numcolors * numgroups + 2));
+ palette->adjusted_rgb15 = malloc(sizeof(*palette->adjusted_rgb15) * (numcolors * numgroups + 2));
+ if (palette->adjusted_color == NULL || palette->adjusted_rgb15 == NULL)
+ goto error;
+
+ /* initialize the arrays */
+ for (index = 0; index < numcolors * numgroups; index++)
+ {
+ palette->adjusted_color[index] = RGB_BLACK;
+ palette->adjusted_rgb15[index] = rgb_to_rgb15(RGB_BLACK);
+ }
+
+ /* add black and white as the last two colors */
+ palette->adjusted_color[index] = RGB_BLACK;
+ palette->adjusted_rgb15[index++] = rgb_to_rgb15(RGB_BLACK);
+ palette->adjusted_color[index] = RGB_WHITE;
+ palette->adjusted_rgb15[index++] = rgb_to_rgb15(RGB_WHITE);
+
+ /* initialize the remainder of the structure */
+ palette->refcount = 1;
+ palette->numcolors = numcolors;
+ palette->numgroups = numgroups;
+ return palette;
+
+error:
+ if (palette != NULL)
+ internal_palette_free(palette);
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ palette_ref - reference a palette object,
+ incrementing its reference count
+-------------------------------------------------*/
+
+void palette_ref(palette_t *palette)
+{
+ palette->refcount++;
+}
+
+
+/*-------------------------------------------------
+ palette_deref - dereference a palette object;
+ if the reference count goes to 0, it is freed
+-------------------------------------------------*/
+
+void palette_deref(palette_t *palette)
+{
+ /* if the reference count goes to 0, free */
+ if (--palette->refcount == 0)
+ internal_palette_free(palette);
+}
+
+
+
+/***************************************************************************
+ PALETTE INFORMATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ palette_get_num_colors - return the number of
+ colors allocated in the palette
+-------------------------------------------------*/
+
+int palette_get_num_colors(palette_t *palette)
+{
+ return palette->numcolors;
+}
+
+
+/*-------------------------------------------------
+ palette_get_num_groups - return the number of
+ groups managed by the palette
+-------------------------------------------------*/
+
+int palette_get_num_groups(palette_t *palette)
+{
+ return palette->numgroups;
+}
+
+
+/*-------------------------------------------------
+ palette_get_black_entry - return the index of
+ the black entry
+-------------------------------------------------*/
+
+UINT32 palette_get_black_entry(palette_t *palette)
+{
+ return palette->numcolors * palette->numgroups + 0;
+}
+
+
+/*-------------------------------------------------
+ palette_get_white_entry - return the index of
+ the white entry
+-------------------------------------------------*/
+
+UINT32 palette_get_white_entry(palette_t *palette)
+{
+ return palette->numcolors * palette->numgroups + 1;
+}
+
+
+
+/***************************************************************************
+ PALETTE CLIENTS
+***************************************************************************/
+
+/*-------------------------------------------------
+ palette_client_alloc - add a new client to a
+ palette
+-------------------------------------------------*/
+
+palette_client *palette_client_alloc(palette_t *palette)
+{
+ UINT32 total_colors = palette->numcolors * palette->numgroups;
+ UINT32 dirty_dwords = (total_colors + 31) / 32;
+ palette_client *client;
+
+ /* allocate memory for the client */
+ client = malloc(sizeof(*client));
+ if (client == NULL)
+ goto error;
+ memset(client, 0, sizeof(*client));
+
+ /* allocate dirty lists */
+ client->live.dirty = malloc(dirty_dwords * sizeof(UINT32));
+ client->previous.dirty = malloc(dirty_dwords * sizeof(UINT32));
+ if (client->live.dirty == NULL || client->previous.dirty == NULL)
+ goto error;
+
+ /* mark everything dirty to start with */
+ memset(client->live.dirty, 0xff, dirty_dwords * sizeof(UINT32));
+ memset(client->previous.dirty, 0xff, dirty_dwords * sizeof(UINT32));
+ client->live.dirty[dirty_dwords - 1] &= (1 << (total_colors % 32)) - 1;
+ client->previous.dirty[dirty_dwords - 1] &= (1 << (total_colors % 32)) - 1;
+
+ /* initialize the rest of the structure and add a reference to a palette */
+ client->palette = palette;
+ palette_ref(palette);
+ client->live.mindirty = 0;
+ client->live.maxdirty = total_colors - 1;
+
+ /* now add us to the list of clients */
+ client->next = palette->client_list;
+ palette->client_list = client;
+ return client;
+
+error:
+ if (client != NULL)
+ {
+ if (client->live.dirty != NULL)
+ free(client->live.dirty);
+ if (client->previous.dirty != NULL)
+ free(client->previous.dirty);
+ free(client);
+ }
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ palette_client_free - remove a client from a
+ palette
+-------------------------------------------------*/
+
+void palette_client_free(palette_client *client)
+{
+ palette_client **curptr;
+
+ /* first locate and remove ourself from the palette's list */
+ for (curptr = &client->palette->client_list; *curptr != NULL; curptr = &(*curptr)->next)
+ if (*curptr == client)
+ {
+ *curptr = client->next;
+ break;
+ }
+
+ /* now deref the palette */
+ palette_deref(client->palette);
+
+ /* free our data */
+ if (client->live.dirty != NULL)
+ free(client->live.dirty);
+ if (client->previous.dirty != NULL)
+ free(client->previous.dirty);
+ free(client);
+}
+
+
+/*-------------------------------------------------
+ palette_client_get_palette - return a pointer
+ to the palette for this client
+-------------------------------------------------*/
+
+palette_t *palette_client_get_palette(palette_client *client)
+{
+ return client->palette;
+}
+
+
+/*-------------------------------------------------
+ palette_client_get_dirty_list - atomically get
+ the current dirty list for a client
+-------------------------------------------------*/
+
+const UINT32 *palette_client_get_dirty_list(palette_client *client, UINT32 *mindirty, UINT32 *maxdirty)
+{
+ dirty_state temp;
+
+ /* fill in the mindirty/maxdirty */
+ if (mindirty != NULL)
+ *mindirty = client->live.mindirty;
+ if (maxdirty != NULL)
+ *maxdirty = client->live.maxdirty;
+
+ /* if nothing to report, report nothing and don't swap */
+ if (client->live.mindirty > client->live.maxdirty)
+ return NULL;
+
+ /* swap the live and previous lists */
+ temp = client->live;
+ client->live = client->previous;
+ client->previous = temp;
+
+ /* erase relevant entries in the new live one */
+ if (client->live.mindirty <= client->live.maxdirty)
+ memset(client->live.dirty, client->live.mindirty / 8, (client->live.maxdirty / 8) + 1 - (client->live.mindirty / 8));
+ client->live.mindirty = client->palette->numcolors * client->palette->numgroups;
+ client->live.maxdirty = 0;
+
+ /* return a pointer to the previous table */
+ return client->previous.dirty;
+}
+
+
+
+/***************************************************************************
+ PALETTE COLOR MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ palette_entry_set_color - set the raw RGB
+ color for a given palette index
+-------------------------------------------------*/
+
+void palette_entry_set_color(palette_t *palette, UINT32 index, rgb_t rgb)
+{
+ int groupnum;
+
+ /* if out of range, or unchanged, ignore */
+ if (index >= palette->numcolors || palette->entry_color[index] == rgb)
+ return;
+
+ /* set the color */
+ palette->entry_color[index] = rgb;
+
+ /* update across all groups */
+ for (groupnum = 0; groupnum < palette->numgroups; groupnum++)
+ update_adjusted_color(palette, groupnum, index);
+}
+
+
+/*-------------------------------------------------
+ palette_entry_get_color - return the raw RGB
+ color for a given palette index
+-------------------------------------------------*/
+
+rgb_t palette_entry_get_color(palette_t *palette, UINT32 index)
+{
+ return (index < palette->numcolors) ? palette->entry_color[index] : RGB_BLACK;
+}
+
+
+/*-------------------------------------------------
+ palette_entry_get_adjusted_color - return the
+ adjusted RGB color (after all adjustments) for
+ a given palette index
+-------------------------------------------------*/
+
+rgb_t palette_entry_get_adjusted_color(palette_t *palette, UINT32 index)
+{
+ return (index < palette->numcolors * palette->numgroups) ? palette->adjusted_color[index] : RGB_BLACK;
+}
+
+
+/*-------------------------------------------------
+ palette_entry_list_raw - return the entire
+ palette as an array of raw RGB values
+-------------------------------------------------*/
+
+const rgb_t *palette_entry_list_raw(palette_t *palette)
+{
+ return palette->entry_color;
+}
+
+
+/*-------------------------------------------------
+ palette_entry_list_adjusted - return the
+ entire palette as an array of adjusted RGB
+ values
+-------------------------------------------------*/
+
+const rgb_t *palette_entry_list_adjusted(palette_t *palette)
+{
+ return palette->adjusted_color;
+}
+
+
+/*-------------------------------------------------
+ palette_entry_list_adjusted_rgb15 - return the
+ entire palette as an array of adjusted RGB-15
+ values
+-------------------------------------------------*/
+
+const rgb_t *palette_entry_list_adjusted_rgb15(palette_t *palette)
+{
+ return palette->adjusted_rgb15;
+}
+
+
+
+/***************************************************************************
+ PALETTE ADJUSTMENTS
+***************************************************************************/
+
+/*-------------------------------------------------
+ palette_entry_set_contrast - set the contrast
+ adjustment for a single palette index
+-------------------------------------------------*/
+
+void palette_entry_set_contrast(palette_t *palette, UINT32 index, float contrast)
+{
+ int groupnum;
+
+ /* if out of range, or unchanged, ignore */
+ if (index >= palette->numcolors || palette->entry_contrast[index] == contrast)
+ return;
+
+ /* set the contrast */
+ palette->entry_contrast[index] = contrast;
+
+ /* update across all groups */
+ for (groupnum = 0; groupnum < palette->numgroups; groupnum++)
+ update_adjusted_color(palette, groupnum, index);
+}
+
+
+/*-------------------------------------------------
+ palette_entry_get_contrast - return the
+ contrast adjustment for a single palette index
+-------------------------------------------------*/
+
+float palette_entry_get_contrast(palette_t *palette, UINT32 index)
+{
+ return (index < palette->numcolors) ? palette->entry_contrast[index] : 1.0f;
+}
+
+
+/*-------------------------------------------------
+ palette_group_set_brightness - configure
+ overall brightness for a palette group
+-------------------------------------------------*/
+
+void palette_group_set_brightness(palette_t *palette, UINT32 group, float brightness)
+{
+ int index;
+
+ /* if out of range, or unchanged, ignore */
+ if (group >= palette->numgroups || palette->group_bright[group] == brightness)
+ return;
+
+ /* set the contrast */
+ palette->group_bright[group] = brightness;
+
+ /* update across all colors */
+ for (index = 0; index < palette->numcolors; index++)
+ update_adjusted_color(palette, group, index);
+}
+
+
+/*-------------------------------------------------
+ palette_group_set_contrast - configure
+ overall contrast for a palette group
+-------------------------------------------------*/
+
+void palette_group_set_contrast(palette_t *palette, UINT32 group, float contrast)
+{
+ int index;
+
+ /* if out of range, or unchanged, ignore */
+ if (group >= palette->numgroups || palette->group_contrast[group] == contrast)
+ return;
+
+ /* set the contrast */
+ palette->group_contrast[group] = contrast;
+
+ /* update across all colors */
+ for (index = 0; index < palette->numcolors; index++)
+ update_adjusted_color(palette, group, index);
+}
+
+
+
+/***************************************************************************
+ PALETTE UTILITIES
+***************************************************************************/
+
+/*-------------------------------------------------
+ palette_normalize_range - normalize a range
+ of palette entries
+-------------------------------------------------*/
+
+void palette_normalize_range(palette_t *palette, UINT32 start, UINT32 end, int lum_min, int lum_max)
+{
+ UINT32 ymin = 1000 * 255, ymax = 0;
+ UINT32 tmin, tmax;
+ UINT32 index;
+
+ /* clamp within range */
+ start = MAX(start, 0);
+ end = MIN(end, palette->numcolors - 1);
+
+ /* find the minimum and maximum brightness of all the colors in the range */
+ for (index = start; index <= end; index++)
+ {
+ rgb_t rgb = palette->entry_color[index];
+ UINT32 y = 299 * RGB_RED(rgb) + 587 * RGB_GREEN(rgb) + 114 * RGB_BLUE(rgb);
+ ymin = MIN(ymin, y);
+ ymax = MAX(ymax, y);
+ }
+
+ /* determine target minimum/maximum */
+ tmin = (lum_min < 0) ? ((ymin + 500) / 1000) : lum_min;
+ tmax = (lum_max < 0) ? ((ymax + 500) / 1000) : lum_max;
+
+ /* now normalize the palette */
+ for (index = start; index <= end; index++)
+ {
+ rgb_t rgb = palette->entry_color[index];
+ UINT32 y = 299 * RGB_RED(rgb) + 587 * RGB_GREEN(rgb) + 114 * RGB_BLUE(rgb);
+ UINT32 target = tmin + ((y - ymin) * (tmax - tmin + 1)) / (ymax - ymin);
+ UINT8 r = (y == 0) ? 0 : rgb_clamp(RGB_RED(rgb) * 1000 * target / y);
+ UINT8 g = (y == 0) ? 0 : rgb_clamp(RGB_GREEN(rgb) * 1000 * target / y);
+ UINT8 b = (y == 0) ? 0 : rgb_clamp(RGB_BLUE(rgb) * 1000 * target / y);
+ palette_entry_set_color(palette, index, MAKE_RGB(r, g, b));
+ }
+}
+
+
+
+/***************************************************************************
+ INTERNAL ROUTINES
+***************************************************************************/
+
+/*-------------------------------------------------
+ internal_palette_free - free all allocations
+ from a palette
+-------------------------------------------------*/
+
+static void internal_palette_free(palette_t *palette)
+{
+ /* free per-color data */
+ if (palette->entry_color != NULL)
+ free(palette->entry_color);
+ if (palette->entry_contrast != NULL)
+ free(palette->entry_contrast);
+
+ /* free per-group data */
+ if (palette->group_bright != NULL)
+ free(palette->group_bright);
+ if (palette->group_contrast != NULL)
+ free(palette->group_contrast);
+
+ /* free adjusted data */
+ if (palette->adjusted_color != NULL)
+ free(palette->adjusted_color);
+ if (palette->adjusted_rgb15 != NULL)
+ free(palette->adjusted_rgb15);
+
+ /* and the palette itself */
+ free(palette);
+}
+
+
+/*-------------------------------------------------
+ update_adjusted_color - update a color index
+ by group and index pair
+-------------------------------------------------*/
+
+static void update_adjusted_color(palette_t *palette, UINT32 group, UINT32 index)
+{
+ UINT32 finalindex = group * palette->numcolors + index;
+ palette_client *client;
+ rgb_t adjusted;
+
+ /* compute the adjusted value */
+ adjusted = adjust_palette_entry(palette->entry_color[index], palette->group_bright[group], palette->group_contrast[group] * palette->entry_contrast[index]);
+
+ /* if not different, ignore */
+ if (palette->adjusted_color[finalindex] == adjusted)
+ return;
+
+ /* otherwise, modify the adjusted color array */
+ palette->adjusted_color[finalindex] = adjusted;
+ palette->adjusted_rgb15[finalindex] = rgb_to_rgb15(adjusted);
+
+ /* mark dirty in all clients */
+ for (client = palette->client_list; client != NULL; client = client->next)
+ {
+ client->live.dirty[finalindex / 32] |= 1 << (finalindex % 32);
+ client->live.mindirty = MIN(client->live.mindirty, finalindex);
+ client->live.maxdirty = MAX(client->live.maxdirty, finalindex);
+ }
+}
diff --git a/src/lib/util/palette.h b/src/lib/util/palette.h
new file mode 100644
index 00000000000..cef180c1262
--- /dev/null
+++ b/src/lib/util/palette.h
@@ -0,0 +1,259 @@
+/******************************************************************************
+
+ palette.c
+
+ Core palette routines.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __PALETTE_H__
+#define __PALETTE_H__
+
+#include "osdcore.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* an rgb_t is a single combined R,G,B (and optionally alpha) value */
+typedef UINT32 rgb_t;
+
+/* an rgb15_t is a single combined 15-bit R,G,B value */
+typedef UINT16 rgb15_t;
+
+/* a palette is an opaque, reference counted object */
+typedef struct _palette_t palette_t;
+
+/* a palette client is someone who is tracking the dirty state of a palette */
+typedef struct _palette_client palette_client;
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* macros to assemble rgb_t values */
+#define MAKE_RGB(r,g,b) ((((rgb_t)(r) & 0xff) << 16) | (((rgb_t)(g) & 0xff) << 8) | ((rgb_t)(b) & 0xff))
+#define MAKE_ARGB(a,r,g,b) (MAKE_RGB(r,g,b) | (((rgb_t)(a) & 0xff) << 24))
+
+/* macros to extract components from rgb_t values */
+#define RGB_ALPHA(rgb) (((rgb) >> 24) & 0xff)
+#define RGB_RED(rgb) (((rgb) >> 16) & 0xff)
+#define RGB_GREEN(rgb) (((rgb) >> 8) & 0xff)
+#define RGB_BLUE(rgb) ((rgb) & 0xff)
+
+/* common colors */
+#define RGB_BLACK (MAKE_RGB(0,0,0))
+#define RGB_WHITE (MAKE_RGB(255,255,255))
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- palette allocation ----- */
+
+/* allocate a new palette object and take a single reference on it */
+palette_t *palette_alloc(UINT32 numcolors, UINT32 numgroups);
+
+/* reference a palette object, incrementing its reference count */
+void palette_ref(palette_t *palette);
+
+/* dereference a palette object; if the reference count goes to 0, it is freed */
+void palette_deref(palette_t *palette);
+
+
+
+/* ----- palette information ----- */
+
+/* return the number of colors managed by the palette */
+int palette_get_num_colors(palette_t *palette);
+
+/* return the number of groups managed by the palette */
+int palette_get_num_groups(palette_t *palette);
+
+/* return the index of the black entry */
+UINT32 palette_get_black_entry(palette_t *palette);
+
+/* return the index of the white entry */
+UINT32 palette_get_white_entry(palette_t *palette);
+
+
+
+/* ----- palette clients ----- */
+
+/* add a new client to a palette */
+palette_client *palette_client_alloc(palette_t *palette);
+
+/* remove a client from a palette */
+void palette_client_free(palette_client *client);
+
+/* return a pointer to the palette for this client */
+palette_t *palette_client_get_palette(palette_client *client);
+
+/* atomically get the current dirty list for a client */
+const UINT32 *palette_client_get_dirty_list(palette_client *client, UINT32 *mindirty, UINT32 *maxdirty);
+
+
+
+/* ----- color management ----- */
+
+/* set the raw RGB color for a given palette index */
+void palette_entry_set_color(palette_t *palette, UINT32 index, rgb_t rgb);
+
+/* return the raw RGB color for a given palette index */
+rgb_t palette_entry_get_color(palette_t *palette, UINT32 index);
+
+/* return the adjusted RGB color (after all adjustments) for a given palette index */
+rgb_t palette_entry_get_adjusted_color(palette_t *palette, UINT32 index);
+
+/* return the entire palette as an array of raw RGB values */
+const rgb_t *palette_entry_list_raw(palette_t *palette);
+
+/* return the entire palette as an array of adjusted RGB values */
+const rgb_t *palette_entry_list_adjusted(palette_t *palette);
+
+/* return the entire palette as an array of adjusted RGB-15 values */
+const rgb_t *palette_entry_list_adjusted_rgb15(palette_t *palette);
+
+
+
+/* ----- palette adjustments ----- */
+
+/* set the contrast adjustment for a single palette index */
+void palette_entry_set_contrast(palette_t *palette, UINT32 index, float contrast);
+
+/* return the contrast adjustment for a single palette index */
+float palette_entry_get_contrast(palette_t *palette, UINT32 index);
+
+/* configure overall brightness for a palette group */
+void palette_group_set_brightness(palette_t *palette, UINT32 group, float brightness);
+
+/* configure overall contrast for a palette group */
+void palette_group_set_contrast(palette_t *palette, UINT32 group, float contrast);
+
+
+
+/* ----- palette utilities ----- */
+
+/* normalize a range of palette entries, mapping minimum brightness to lum_min and maximum
+ brightness to lum_max; if either value is < 0, that boundary value is not modified */
+void palette_normalize_range(palette_t *palette, UINT32 start, UINT32 end, int lum_min, int lum_max);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ rgb_to_rgb15 - convert an RGB triplet to
+ a 15-bit OSD-specified RGB value
+-------------------------------------------------*/
+
+INLINE rgb15_t rgb_to_rgb15(rgb_t rgb)
+{
+ return ((RGB_RED(rgb) >> 3) << 10) | ((RGB_GREEN(rgb) >> 3) << 5) | ((RGB_BLUE(rgb) >> 3) << 0);
+}
+
+
+/*-------------------------------------------------
+ rgb_clamp - clamp an RGB component to 0-255
+-------------------------------------------------*/
+
+INLINE UINT8 rgb_clamp(INT32 value)
+{
+ if (value < 0)
+ return 0;
+ if (value > 255)
+ return 255;
+ return value;
+}
+
+
+/*-------------------------------------------------
+ pal1bit - convert a 1-bit value to 8 bits
+-------------------------------------------------*/
+
+INLINE UINT8 pal1bit(UINT8 bits)
+{
+ return (bits & 1) ? 0xff : 0x00;
+}
+
+
+/*-------------------------------------------------
+ pal2bit - convert a 2-bit value to 8 bits
+-------------------------------------------------*/
+
+INLINE UINT8 pal2bit(UINT8 bits)
+{
+ bits &= 3;
+ return (bits << 6) | (bits << 4) | (bits << 2) | bits;
+}
+
+
+/*-------------------------------------------------
+ pal3bit - convert a 3-bit value to 8 bits
+-------------------------------------------------*/
+
+INLINE UINT8 pal3bit(UINT8 bits)
+{
+ bits &= 7;
+ return (bits << 5) | (bits << 2) | (bits >> 1);
+}
+
+
+/*-------------------------------------------------
+ pal4bit - convert a 4-bit value to 8 bits
+-------------------------------------------------*/
+
+INLINE UINT8 pal4bit(UINT8 bits)
+{
+ bits &= 0xf;
+ return (bits << 4) | bits;
+}
+
+
+/*-------------------------------------------------
+ pal5bit - convert a 5-bit value to 8 bits
+-------------------------------------------------*/
+
+INLINE UINT8 pal5bit(UINT8 bits)
+{
+ bits &= 0x1f;
+ return (bits << 3) | (bits >> 2);
+}
+
+
+/*-------------------------------------------------
+ pal6bit - convert a 6-bit value to 8 bits
+-------------------------------------------------*/
+
+INLINE UINT8 pal6bit(UINT8 bits)
+{
+ bits &= 0x3f;
+ return (bits << 2) | (bits >> 4);
+}
+
+
+/*-------------------------------------------------
+ pal7bit - convert a 7-bit value to 8 bits
+-------------------------------------------------*/
+
+INLINE UINT8 pal7bit(UINT8 bits)
+{
+ bits &= 0x7f;
+ return (bits << 1) | (bits >> 6);
+}
+
+
+#endif /* __PALETTE_H__ */
diff --git a/src/lib/util/png.c b/src/lib/util/png.c
new file mode 100644
index 00000000000..865703c0d73
--- /dev/null
+++ b/src/lib/util/png.c
@@ -0,0 +1,1143 @@
+/*********************************************************************
+
+ png.c
+
+ PNG reading functions.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+
+*********************************************************************/
+
+#include <math.h>
+#include <zlib.h>
+#include "png.h"
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _image_data_chunk image_data_chunk;
+struct _image_data_chunk
+{
+ image_data_chunk * next;
+ int length;
+ UINT8 * data;
+};
+
+
+typedef struct _png_private png_private;
+struct _png_private
+{
+ png_info * pnginfo;
+ image_data_chunk * idata;
+ image_data_chunk ** idata_next;
+ UINT8 bpp;
+ UINT32 rowbytes;
+};
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static const int samples[] = { 1, 0, 3, 1, 2, 0, 4 };
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE UINT8 fetch_8bit(UINT8 *v)
+{
+ return *v;
+}
+
+
+INLINE UINT16 fetch_16bit(UINT8 *v)
+{
+ return BIG_ENDIANIZE_INT16(*(UINT16 *)v);
+}
+
+
+INLINE UINT32 fetch_32bit(UINT8 *v)
+{
+ return BIG_ENDIANIZE_INT32(*(UINT32 *)v);
+}
+
+
+INLINE void put_8bit(UINT8 *v, UINT8 data)
+{
+ *v = data;
+}
+
+
+INLINE void put_16bit(UINT8 *v, UINT16 data)
+{
+ *(UINT16 *)v = BIG_ENDIANIZE_INT16(data);
+}
+
+
+INLINE void put_32bit(UINT8 *v, UINT32 data)
+{
+ *(UINT32 *)v = BIG_ENDIANIZE_INT32(data);
+}
+
+
+INLINE int compute_bpp(const png_info *pnginfo)
+{
+ return samples[pnginfo->color_type] * pnginfo->bit_depth / 8;
+}
+
+
+INLINE int compute_rowbytes(const png_info *pnginfo)
+{
+ return (pnginfo->width * samples[pnginfo->color_type] * pnginfo->bit_depth + 7) / 8;
+}
+
+
+
+/***************************************************************************
+ GENERAL FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ png_free - free all memory allocated in a
+ pnginfo structure
+-------------------------------------------------*/
+
+void png_free(png_info *pnginfo)
+{
+ while (pnginfo->textlist != NULL)
+ {
+ png_text *temp = pnginfo->textlist;
+ pnginfo->textlist = temp->next;
+ if (temp->keyword != NULL)
+ free((void *)temp->keyword);
+ free(temp);
+ }
+
+ if (pnginfo->palette != NULL)
+ free(pnginfo->palette);
+ pnginfo->palette = NULL;
+
+ if (pnginfo->trans != NULL)
+ free(pnginfo->trans);
+ pnginfo->trans = NULL;
+
+ if (pnginfo->image != NULL)
+ free(pnginfo->image);
+ pnginfo->image = NULL;
+}
+
+
+
+/***************************************************************************
+ PNG READING FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ verify_header - verify the PNG
+ header at the current file location
+-------------------------------------------------*/
+
+static png_error verify_header(core_file *fp)
+{
+ UINT8 signature[8];
+
+ /* read 8 bytes */
+ if (core_fread(fp, signature, 8) != 8)
+ return PNGERR_FILE_TRUNCATED;
+
+ /* return an error if we don't match */
+ if (memcmp(signature, PNG_Signature, 8) != 0)
+ return PNGERR_BAD_SIGNATURE;
+
+ return PNGERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ read_chunk - read the next PNG chunk
+-------------------------------------------------*/
+
+static png_error read_chunk(core_file *fp, UINT8 **data, UINT32 *type, UINT32 *length)
+{
+ UINT32 crc, chunk_crc;
+ UINT8 tempbuff[4];
+
+ /* fetch the length of this chunk */
+ if (core_fread(fp, tempbuff, 4) != 4)
+ return PNGERR_FILE_TRUNCATED;
+ *length = fetch_32bit(tempbuff);
+
+ /* fetch the type of this chunk */
+ if (core_fread(fp, tempbuff, 4) != 4)
+ return PNGERR_FILE_TRUNCATED;
+ *type = fetch_32bit(tempbuff);
+
+ /* stop when we hit an IEND chunk */
+ if (*type == PNG_CN_IEND)
+ return PNGERR_NONE;
+
+ /* start the CRC with the chunk type (but not the length) */
+ crc = crc32(0, tempbuff, 4);
+
+ /* read the chunk itself into an allocated memory buffer */
+ *data = NULL;
+ if (*length != 0)
+ {
+ /* allocate memory for this chunk */
+ *data = (UINT8 *)malloc(*length);
+ if (*data == NULL)
+ return PNGERR_OUT_OF_MEMORY;
+
+ /* read the data from the file */
+ if (core_fread(fp, *data, *length) != *length)
+ {
+ free(*data);
+ *data = NULL;
+ return PNGERR_FILE_TRUNCATED;
+ }
+
+ /* update the CRC */
+ crc = crc32(crc, *data, *length);
+ }
+
+ /* read the CRC */
+ if (core_fread(fp, tempbuff, 4) != 4)
+ {
+ free(*data);
+ *data = NULL;
+ return PNGERR_FILE_TRUNCATED;
+ }
+ chunk_crc = fetch_32bit(tempbuff);
+
+ /* validate the CRC */
+ if (crc != chunk_crc)
+ {
+ free(*data);
+ *data = NULL;
+ return PNGERR_FILE_CORRUPT;
+ }
+ return PNGERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ process_chunk - process a PNG chunk
+-------------------------------------------------*/
+
+static png_error process_chunk(png_private *png, UINT8 *data, UINT32 type, UINT32 length, int *keepmem)
+{
+ /* default to not keeping memory */
+ *keepmem = FALSE;
+
+ /* switch off of the type */
+ switch (type)
+ {
+ /* image header */
+ case PNG_CN_IHDR:
+ png->pnginfo->width = fetch_32bit(data);
+ png->pnginfo->height = fetch_32bit(data + 4);
+ png->pnginfo->bit_depth = fetch_8bit(data + 8);
+ png->pnginfo->color_type = fetch_8bit(data + 9);
+ png->pnginfo->compression_method = fetch_8bit(data + 10);
+ png->pnginfo->filter_method = fetch_8bit(data + 11);
+ png->pnginfo->interlace_method = fetch_8bit(data + 12);
+ break;
+
+ /* palette */
+ case PNG_CN_PLTE:
+ png->pnginfo->num_palette = length / 3;
+ png->pnginfo->palette = data;
+ *keepmem = TRUE;
+ break;
+
+ /* transparency information */
+ case PNG_CN_tRNS:
+ png->pnginfo->num_trans = length;
+ png->pnginfo->trans = data;
+ *keepmem = TRUE;
+ break;
+
+ /* image data */
+ case PNG_CN_IDAT:
+
+ /* allocate a new image data descriptor */
+ *png->idata_next = malloc(sizeof(**png->idata_next));
+ if (*png->idata_next == NULL)
+ return PNGERR_OUT_OF_MEMORY;
+
+ /* add it to the tail of the list */
+ (*png->idata_next)->next = NULL;
+ (*png->idata_next)->length = length;
+ (*png->idata_next)->data = data;
+ png->idata_next = &(*png->idata_next)->next;
+ *keepmem = TRUE;
+ break;
+
+ /* gamma */
+ case PNG_CN_gAMA:
+ png->pnginfo->source_gamma = fetch_32bit(data) / 100000.0;
+ break;
+
+ /* physical information */
+ case PNG_CN_pHYs:
+ png->pnginfo->xres = fetch_32bit(data);
+ png->pnginfo->yres = fetch_32bit(data + 4);
+ png->pnginfo->resolution_unit = fetch_8bit(data + 8);
+ break;
+
+ /* text */
+ case PNG_CN_tEXt:
+ {
+ png_text *text, *pt, *ct;
+
+ /* allocate a new text item */
+ text = malloc(sizeof(*text));
+ if (text == NULL)
+ return PNGERR_OUT_OF_MEMORY;
+
+ /* set the elements */
+ text->keyword = (char *)data;
+ text->text = text->keyword + strlen(text->keyword) + 1;
+ text->next = NULL;
+
+ /* add to the end of the list */
+ for (pt = NULL, ct = png->pnginfo->textlist; ct != NULL; pt = ct, ct = ct->next) ;
+ if (pt == NULL)
+ png->pnginfo->textlist = text;
+ else
+ pt->next = text;
+
+ *keepmem = TRUE;
+ break;
+ }
+
+ /* anything else */
+ default:
+ if ((type & 0x20000000) == 0)
+ return PNGERR_UNKNOWN_CHUNK;
+ break;
+ }
+ return PNGERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ unfilter_row - unfilter a single row of pixels
+-------------------------------------------------*/
+
+static png_error unfilter_row(int type, UINT8 *src, UINT8 *dst, UINT8 *dstprev, int bpp, int rowbytes)
+{
+ int x;
+
+ /* switch off of it */
+ switch (type)
+ {
+ /* no filter, just copy */
+ case PNG_PF_None:
+ for (x = 0; x < rowbytes; x++)
+ *dst++ = *src++;
+ break;
+
+ /* SUB = previous pixel */
+ case PNG_PF_Sub:
+ for (x = 0; x < bpp; x++)
+ *dst++ = *src++;
+ for (x = bpp; x < rowbytes; x++, dst++)
+ *dst = *src++ + dst[-bpp];
+ break;
+
+ /* UP = pixel above */
+ case PNG_PF_Up:
+ if (dstprev == NULL)
+ return unfilter_row(PNG_PF_None, src, dst, dstprev, bpp, rowbytes);
+ for (x = 0; x < rowbytes; x++, dst++)
+ *dst = *src++ + *dstprev++;
+ break;
+
+ /* AVERAGE = average of pixel above and previous pixel */
+ case PNG_PF_Average:
+ if (dstprev == NULL)
+ {
+ for (x = 0; x < bpp; x++)
+ *dst++ = *src++;
+ for (x = bpp; x < rowbytes; x++, dst++)
+ *dst = *src++ + dst[-bpp] / 2;
+ }
+ else
+ {
+ for (x = 0; x < bpp; x++, dst++)
+ *dst = *src++ + *dstprev++ / 2;
+ for (x = bpp; x < rowbytes; x++, dst++)
+ *dst = *src++ + (*dstprev++ + dst[-bpp]) / 2;
+ }
+ break;
+
+ /* PAETH = special filter */
+ case PNG_PF_Paeth:
+ for (x = 0; x < rowbytes; x++)
+ {
+ INT32 pa = (x < bpp) ? 0 : dst[-bpp];
+ INT32 pc = (x < bpp || dstprev == NULL) ? 0 : dstprev[-bpp];
+ INT32 pb = (dstprev == NULL) ? 0 : *dstprev++;
+ INT32 prediction = pa + pb - pc;
+ INT32 da = abs(prediction - pa);
+ INT32 db = abs(prediction - pb);
+ INT32 dc = abs(prediction - pc);
+ if (da <= db && da <= dc)
+ *dst++ = *src++ + pa;
+ else if (db <= dc)
+ *dst++ = *src++ + pb;
+ else
+ *dst++ = *src++ + pc;
+ }
+ break;
+
+ /* unknown filter type */
+ default:
+ return PNGERR_UNKNOWN_FILTER;
+ }
+
+ return PNGERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ process_image - post-process a loaded iamge
+-------------------------------------------------*/
+
+static png_error process_image(png_private *png)
+{
+ int rowbytes, bpp, imagesize;
+ png_error error = PNGERR_NONE;
+ image_data_chunk *idat;
+ UINT8 *src, *dst;
+ z_stream stream;
+ int zerr, y;
+
+ /* compute some basic parameters */
+ bpp = compute_bpp(png->pnginfo);
+ rowbytes = compute_rowbytes(png->pnginfo);
+ imagesize = png->pnginfo->height * (rowbytes + 1);
+
+ /* allocate memory for the filtered image */
+ png->pnginfo->image = (UINT8 *)malloc(imagesize);
+ if (png->pnginfo->image == NULL)
+ return PNGERR_OUT_OF_MEMORY;
+
+ /* initialize the stream */
+ memset(&stream, 0, sizeof(stream));
+ stream.next_out = png->pnginfo->image;
+ stream.avail_out = imagesize;
+ zerr = inflateInit(&stream);
+ if (zerr != Z_OK)
+ {
+ error = PNGERR_DECOMPRESS_ERROR;
+ goto handle_error;
+ }
+
+ /* loop over IDAT and decompress each as part of a larger stream */
+ for (idat = png->idata; idat != NULL; idat = idat->next)
+ {
+ /* decompress this chunk */
+ stream.next_in = idat->data;
+ stream.avail_in = idat->length;
+ zerr = inflate(&stream, Z_NO_FLUSH);
+
+ /* stop at the end of the stream */
+ if (zerr == Z_STREAM_END)
+ break;
+
+ /* other errors are fatal */
+ if (zerr != Z_OK)
+ {
+ error = PNGERR_DECOMPRESS_ERROR;
+ goto handle_error;
+ }
+ }
+
+ /* clean up */
+ zerr = inflateEnd(&stream);
+ if (zerr != Z_OK)
+ {
+ error = PNGERR_DECOMPRESS_ERROR;
+ goto handle_error;
+ }
+
+ /* we de-filter in place */
+ src = dst = png->pnginfo->image;
+
+ /* iterate over rows */
+ for (y = 0; y < png->pnginfo->height && error == PNGERR_NONE; y++)
+ {
+ /* first byte of each row is the filter type */
+ int filter = *src++;
+ error = unfilter_row(filter, src, dst, (y == 0) ? NULL : &dst[-rowbytes], bpp, rowbytes);
+ src += rowbytes;
+ dst += rowbytes;
+ }
+
+handle_error:
+ /* if we errored, free the image data */
+ if (error != PNGERR_NONE)
+ {
+ free(png->pnginfo->image);
+ png->pnginfo->image = NULL;
+ }
+ return error;
+}
+
+
+/*-------------------------------------------------
+ png_read_file - read a PNG from a core stream
+-------------------------------------------------*/
+
+png_error png_read_file(core_file *fp, png_info *pnginfo)
+{
+ UINT8 *chunk_data = NULL;
+ png_private png;
+ png_error error;
+
+ /* initialize the data structures */
+ memset(&png, 0, sizeof(png));
+ memset(pnginfo, 0, sizeof(*pnginfo));
+ png.pnginfo = pnginfo;
+ png.idata_next = &png.idata;
+
+ /* verify the signature at the start of the file */
+ error = verify_header(fp);
+ if (error != PNGERR_NONE)
+ goto handle_error;
+
+ /* loop until we hit an IEND chunk */
+ for ( ; ; )
+ {
+ UINT32 chunk_type, chunk_length;
+ int keepmem;
+
+ /* read a chunk */
+ error = read_chunk(fp, &chunk_data, &chunk_type, &chunk_length);
+ if (error != PNGERR_NONE)
+ goto handle_error;
+
+ /* stop when we hit an IEND chunk */
+ if (chunk_type == PNG_CN_IEND)
+ break;
+
+ /* process the chunk */
+ error = process_chunk(&png, chunk_data, chunk_type, chunk_length, &keepmem);
+ if (error != PNGERR_NONE)
+ goto handle_error;
+
+ /* free memory if we didn't want to keep it */
+ if (!keepmem)
+ free(chunk_data);
+ chunk_data = NULL;
+ }
+
+ /* finish processing the image */
+ error = process_image(&png);
+ if (error != PNGERR_NONE)
+ goto handle_error;
+
+handle_error:
+
+ /* free all intermediate data */
+ while (png.idata != NULL)
+ {
+ image_data_chunk *next = png.idata->next;
+ if (png.idata->data != NULL)
+ free(png.idata->data);
+ free(png.idata);
+ png.idata = next;
+ }
+ if (chunk_data != NULL)
+ free(chunk_data);
+
+ /* if we have an error, free all the other data as well */
+ if (error != PNGERR_NONE)
+ {
+ png_free(pnginfo);
+ memset(pnginfo, 0, sizeof(*pnginfo));
+ }
+ return error;
+}
+
+
+/*-------------------------------------------------
+ png_read_bitmap - load a PNG file into a
+ bitmap_t
+-------------------------------------------------*/
+
+png_error png_read_bitmap(core_file *fp, bitmap_t **bitmap)
+{
+ png_error result;
+ png_info png;
+ UINT8 *src;
+ int x, y;
+
+ /* read the PNG data */
+ result = png_read_file(fp, &png);
+ if (result != PNGERR_NONE)
+ return result;
+
+ /* verify we can handle this PNG */
+ if (png.bit_depth > 8 || png.interlace_method != 0 ||
+ (png.color_type != 0 && png.color_type != 3 && png.color_type != 2 && png.color_type != 6))
+ {
+ png_free(&png);
+ return PNGERR_UNSUPPORTED_FORMAT;
+ }
+
+ /* if less than 8 bits, upsample */
+ png_expand_buffer_8bit(&png);
+
+ /* allocate a bitmap of the appropriate size and copy it */
+ *bitmap = bitmap_alloc(png.width, png.height, BITMAP_FORMAT_ARGB32);
+ if (*bitmap == NULL)
+ {
+ png_free(&png);
+ return PNGERR_OUT_OF_MEMORY;
+ }
+
+ /* handle 8bpp palettized case */
+ src = png.image;
+ if (png.color_type == 3)
+ {
+ /* loop over width/height */
+ for (y = 0; y < png.height; y++)
+ for (x = 0; x < png.width; x++, src++)
+ {
+ /* determine alpha and expand to 32bpp */
+ UINT8 alpha = (*src < png.num_trans) ? png.trans[*src] : 0xff;
+ *BITMAP_ADDR32(*bitmap, y, x) = (alpha << 24) | (png.palette[*src * 3] << 16) | (png.palette[*src * 3 + 1] << 8) | png.palette[*src * 3 + 2];
+ }
+ }
+
+ /* handle 8bpp grayscale case */
+ else if (png.color_type == 0)
+ {
+ for (y = 0; y < png.height; y++)
+ for (x = 0; x < png.width; x++, src++)
+ *BITMAP_ADDR32(*bitmap, y, x) = 0xff000000 | (*src << 16) | (*src << 8) | *src;
+ }
+
+ /* handle 32bpp non-alpha case */
+ else if (png.color_type == 2)
+ {
+ for (y = 0; y < png.height; y++)
+ for (x = 0; x < png.width; x++, src += 3)
+ *BITMAP_ADDR32(*bitmap, y, x) = 0xff000000 | (src[0] << 16) | (src[1] << 8) | src[2];
+ }
+
+ /* handle 32bpp alpha case */
+ else if (png.color_type == 6)
+ {
+ for (y = 0; y < png.height; y++)
+ for (x = 0; x < png.width; x++, src += 4)
+ *BITMAP_ADDR32(*bitmap, y, x) = (src[3] << 24) | (src[0] << 16) | (src[1] << 8) | src[2];
+ }
+
+ /* free our temporary data and return */
+ png_free(&png);
+ return PNGERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ png_expand_buffer_8bit - expand a buffer from
+ sub 8-bit to 8-bit
+-------------------------------------------------*/
+
+png_error png_expand_buffer_8bit(png_info *pnginfo)
+{
+ int i,j, k;
+ UINT8 *inp, *outp, *outbuf;
+
+ /* nothing to do if we're at 8 or greater already */
+ if (pnginfo->bit_depth >= 8)
+ return PNGERR_NONE;
+
+ /* allocate a new buffer at 8-bit */
+ outbuf = malloc(pnginfo->width * pnginfo->height);
+ if (outbuf == NULL)
+ return PNGERR_OUT_OF_MEMORY;
+
+ inp = pnginfo->image;
+ outp = outbuf;
+
+ for (i = 0; i < pnginfo->height; i++)
+ {
+ for(j = 0; j < pnginfo->width / ( 8 / pnginfo->bit_depth); j++)
+ {
+ for (k = 8 / pnginfo->bit_depth-1; k >= 0; k--)
+ *outp++ = (*inp >> k * pnginfo->bit_depth) & (0xff >> (8 - pnginfo->bit_depth));
+ inp++;
+ }
+ if (pnginfo->width % (8 / pnginfo->bit_depth))
+ {
+ for (k = pnginfo->width % (8 / pnginfo->bit_depth)-1; k >= 0; k--)
+ *outp++ = (*inp >> k * pnginfo->bit_depth) & (0xff >> (8 - pnginfo->bit_depth));
+ inp++;
+ }
+ }
+ free (pnginfo->image);
+ pnginfo->image = outbuf;
+
+ return PNGERR_NONE;
+}
+
+
+
+/***************************************************************************
+ PNG WRITING FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ png_add_text - add a text entry to the png_info
+-------------------------------------------------*/
+
+png_error png_add_text(png_info *pnginfo, const char *keyword, const char *text)
+{
+ png_text *newtext, *pt, *ct;
+ char *textdata;
+ int keylen;
+
+ /* allocate a new text element */
+ newtext = malloc(sizeof(*newtext));
+ if (newtext == NULL)
+ return PNGERR_OUT_OF_MEMORY;
+
+ /* allocate a string long enough to hold both */
+ keylen = (int)strlen(keyword);
+ textdata = malloc(keylen + 1 + strlen(text) + 1);
+ if (textdata == NULL)
+ {
+ free(newtext);
+ return PNGERR_OUT_OF_MEMORY;
+ }
+
+ /* copy in the data */
+ strcpy(textdata, keyword);
+ strcpy(textdata + keylen + 1, text);
+
+ /* text follows a trailing NULL */
+ newtext->keyword = textdata;
+ newtext->text = textdata + keylen + 1;
+ newtext->next = NULL;
+
+ /* add us to the end of the linked list */
+ for (pt = NULL, ct = pnginfo->textlist; ct != NULL; pt = ct, ct = ct->next) ;
+ if (pt == NULL)
+ pnginfo->textlist = newtext;
+ else
+ pt->next = newtext;
+
+ return PNGERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ write_chunk - write an in-memory chunk to
+ the given file
+-------------------------------------------------*/
+
+static png_error write_chunk(core_file *fp, const UINT8 *data, UINT32 type, UINT32 length)
+{
+ UINT8 tempbuff[8];
+ UINT32 crc;
+
+ /* stuff the length/type into the buffer */
+ put_32bit(tempbuff + 0, length);
+ put_32bit(tempbuff + 4, type);
+ crc = crc32(0, tempbuff + 4, 4);
+
+ /* write that data */
+ if (core_fwrite(fp, tempbuff, 8) != 8)
+ return PNGERR_FILE_ERROR;
+
+ /* append the actual data */
+ if (length > 0)
+ {
+ if (core_fwrite(fp, data, length) != length)
+ return PNGERR_FILE_ERROR;
+ crc = crc32(crc, data, length);
+ }
+
+ /* write the CRC */
+ put_32bit(tempbuff, crc);
+ if (core_fwrite(fp, tempbuff, 4) != 4)
+ return PNGERR_FILE_ERROR;
+
+ return PNGERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ write_deflated_chunk - write an in-memory
+ chunk to the given file by deflating it
+-------------------------------------------------*/
+
+static png_error write_deflated_chunk(core_file *fp, UINT8 *data, UINT32 type, UINT32 length)
+{
+ UINT64 lengthpos = core_ftell(fp);
+ UINT8 tempbuff[8192];
+ UINT32 zlength = 0;
+ z_stream stream;
+ UINT32 crc;
+ int zerr;
+
+ /* stuff the length/type into the buffer */
+ put_32bit(tempbuff + 0, length);
+ put_32bit(tempbuff + 4, type);
+ crc = crc32(0, tempbuff + 4, 4);
+
+ /* write that data */
+ if (core_fwrite(fp, tempbuff, 8) != 8)
+ return PNGERR_FILE_ERROR;
+
+ /* initialize the stream */
+ memset(&stream, 0, sizeof(stream));
+ stream.next_in = data;
+ stream.avail_in = length;
+ zerr = deflateInit(&stream, Z_DEFAULT_COMPRESSION);
+ if (zerr != Z_OK)
+ return PNGERR_COMPRESS_ERROR;
+
+ /* now loop until we run out of data */
+ for ( ; ; )
+ {
+ /* compress this chunk */
+ stream.next_out = tempbuff;
+ stream.avail_out = sizeof(tempbuff);
+ zerr = deflate(&stream, Z_FINISH);
+
+ /* if there's data to write, do it */
+ if (stream.avail_out < sizeof(tempbuff))
+ {
+ int bytes = sizeof(tempbuff) - stream.avail_out;
+ if (core_fwrite(fp, tempbuff, bytes) != bytes)
+ {
+ deflateEnd(&stream);
+ return PNGERR_FILE_ERROR;
+ }
+ crc = crc32(crc, tempbuff, bytes);
+ zlength += bytes;
+ }
+
+ /* stop at the end of the stream */
+ if (zerr == Z_STREAM_END)
+ break;
+
+ /* other errors are fatal */
+ if (zerr != Z_OK)
+ {
+ deflateEnd(&stream);
+ return PNGERR_COMPRESS_ERROR;
+ }
+ }
+
+ /* clean up deflater(maus) */
+ zerr = deflateEnd(&stream);
+ if (zerr != Z_OK)
+ return PNGERR_COMPRESS_ERROR;
+
+ /* write the CRC */
+ put_32bit(tempbuff, crc);
+ if (core_fwrite(fp, tempbuff, 4) != 4)
+ return PNGERR_FILE_ERROR;
+
+ /* seek back and update the length */
+ core_fseek(fp, lengthpos, SEEK_SET);
+ put_32bit(tempbuff + 0, zlength);
+ if (core_fwrite(fp, tempbuff, 4) != 4)
+ return PNGERR_FILE_ERROR;
+
+ /* return to the end */
+ core_fseek(fp, lengthpos + 8 + zlength + 4, SEEK_SET);
+ return PNGERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ convert_bitmap_to_image_palette - convert a
+ bitmap to a palettized image
+-------------------------------------------------*/
+
+static png_error convert_bitmap_to_image_palette(png_info *pnginfo, const bitmap_t *bitmap, int palette_length, const rgb_t *palette)
+{
+ int rowbytes;
+ int x, y;
+
+ /* set the common info */
+ pnginfo->width = bitmap->width;
+ pnginfo->height = bitmap->height;
+ pnginfo->bit_depth = 8;
+ pnginfo->color_type = 3;
+ pnginfo->num_palette = 256;
+ rowbytes = pnginfo->width;
+
+ /* allocate memory for the palette */
+ pnginfo->palette = malloc(3 * 256);
+ if (pnginfo->palette == NULL)
+ return PNGERR_OUT_OF_MEMORY;
+
+ /* build the palette */
+ memset(pnginfo->palette, 0, 3 * 256);
+ for (x = 0; x < palette_length; x++)
+ {
+ rgb_t color = palette[x];
+ pnginfo->palette[3 * x + 0] = RGB_RED(color);
+ pnginfo->palette[3 * x + 1] = RGB_GREEN(color);
+ pnginfo->palette[3 * x + 2] = RGB_BLUE(color);
+ }
+
+ /* allocate memory for the image */
+ pnginfo->image = malloc(pnginfo->height * (rowbytes + 1));
+ if (pnginfo->image == NULL)
+ {
+ free(pnginfo->palette);
+ return PNGERR_OUT_OF_MEMORY;
+ }
+
+ /* copy in the pixels, specifying a NULL filter */
+ for (y = 0; y < pnginfo->height; y++)
+ {
+ UINT16 *src = (UINT16 *)bitmap->base + y * bitmap->rowpixels;
+ UINT8 *dst = pnginfo->image + y * (rowbytes + 1);
+
+ /* store the filter byte, then copy the data */
+ *dst++ = 0;
+ for (x = 0; x < pnginfo->width; x++)
+ *dst++ = *src++;
+ }
+
+ return PNGERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ convert_bitmap_to_image_rgb - convert a
+ bitmap to an RGB image
+-------------------------------------------------*/
+
+static png_error convert_bitmap_to_image_rgb(png_info *pnginfo, const bitmap_t *bitmap, int palette_length, const rgb_t *palette)
+{
+ int alpha = (bitmap->format == BITMAP_FORMAT_ARGB32);
+ int rowbytes;
+ int x, y;
+
+ /* set the common info */
+ pnginfo->width = bitmap->width;
+ pnginfo->height = bitmap->height;
+ pnginfo->bit_depth = 8;
+ pnginfo->color_type = alpha ? 6 : 2;
+ rowbytes = pnginfo->width * (alpha ? 4 : 3);
+
+ /* allocate memory for the image */
+ pnginfo->image = malloc(pnginfo->height * (rowbytes + 1));
+ if (pnginfo->image == NULL)
+ return PNGERR_OUT_OF_MEMORY;
+
+ /* copy in the pixels, specifying a NULL filter */
+ for (y = 0; y < pnginfo->height; y++)
+ {
+ UINT32 *src32 = BITMAP_ADDR32(bitmap, y, 0);
+ UINT16 *src16 = BITMAP_ADDR16(bitmap, y, 0);
+ UINT8 *dst = pnginfo->image + y * (rowbytes + 1);
+
+ /* store the filter byte, then copy the data */
+ *dst++ = 0;
+
+ /* 16bpp palettized format */
+ if (bitmap->format == BITMAP_FORMAT_INDEXED16)
+ {
+ for (x = 0; x < pnginfo->width; x++)
+ {
+ rgb_t color = palette[*src16++];
+ *dst++ = RGB_RED(color);
+ *dst++ = RGB_GREEN(color);
+ *dst++ = RGB_BLUE(color);
+ }
+ }
+
+ /* RGB formats */
+ else if (bitmap->format == BITMAP_FORMAT_RGB15)
+ {
+ for (x = 0; x < pnginfo->width; x++)
+ {
+ UINT16 raw = *src16++;
+ *dst++ = pal5bit(raw >> 10);
+ *dst++ = pal5bit(raw >> 5);
+ *dst++ = pal5bit(raw >> 0);
+ }
+ }
+
+ /* 32-bit RGB direct */
+ else if (bitmap->format == BITMAP_FORMAT_RGB32)
+ {
+ for (x = 0; x < pnginfo->width; x++)
+ {
+ UINT32 raw = *src32++;
+ *dst++ = RGB_RED(raw);
+ *dst++ = RGB_GREEN(raw);
+ *dst++ = RGB_BLUE(raw);
+ }
+ }
+
+ /* 32-bit ARGB direct */
+ else if (bitmap->format == BITMAP_FORMAT_ARGB32)
+ {
+ for (x = 0; x < pnginfo->width; x++)
+ {
+ UINT32 raw = *src32++;
+ *dst++ = RGB_RED(raw);
+ *dst++ = RGB_GREEN(raw);
+ *dst++ = RGB_BLUE(raw);
+ *dst++ = RGB_ALPHA(raw);
+ }
+ }
+
+ /* unsupported format */
+ else
+ return PNGERR_UNSUPPORTED_FORMAT;
+ }
+
+ return PNGERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ write_png_stream - stream a series of PNG
+ chunks to the given file
+-------------------------------------------------*/
+
+static png_error write_png_stream(core_file *fp, png_info *pnginfo, const bitmap_t *bitmap, int palette_length, const rgb_t *palette)
+{
+ UINT8 tempbuff[16];
+ png_text *text;
+ png_error error;
+
+ /* create an unfiltered image in either palette or RGB form */
+ if (bitmap->format == BITMAP_FORMAT_INDEXED16 && palette_length <= 256)
+ error = convert_bitmap_to_image_palette(pnginfo, bitmap, palette_length, palette);
+ else
+ error = convert_bitmap_to_image_rgb(pnginfo, bitmap, palette_length, palette);
+ if (error != PNGERR_NONE)
+ goto handle_error;
+
+ /* if we wanted to get clever and do filtering, we would do it here */
+
+ /* write the IHDR chunk */
+ put_32bit(tempbuff + 0, pnginfo->width);
+ put_32bit(tempbuff + 4, pnginfo->height);
+ put_8bit(tempbuff + 8, pnginfo->bit_depth);
+ put_8bit(tempbuff + 9, pnginfo->color_type);
+ put_8bit(tempbuff + 10, pnginfo->compression_method);
+ put_8bit(tempbuff + 11, pnginfo->filter_method);
+ put_8bit(tempbuff + 12, pnginfo->interlace_method);
+ error = write_chunk(fp, tempbuff, PNG_CN_IHDR, 13);
+ if (error != PNGERR_NONE)
+ goto handle_error;
+
+ /* write the PLTE chunk */
+ if (pnginfo->num_palette > 0)
+ error = write_chunk(fp, pnginfo->palette, PNG_CN_PLTE, pnginfo->num_palette * 3);
+ if (error != PNGERR_NONE)
+ goto handle_error;
+
+ /* write a single IDAT chunk */
+ error = write_deflated_chunk(fp, pnginfo->image, PNG_CN_IDAT, pnginfo->height * (compute_rowbytes(pnginfo) + 1));
+ if (error != PNGERR_NONE)
+ goto handle_error;
+
+ /* write TEXT chunks */
+ for (text = pnginfo->textlist; text != NULL; text = text->next)
+ {
+ error = write_chunk(fp, (UINT8 *)text->keyword, PNG_CN_tEXt, (UINT32)strlen(text->keyword) + 1 + (UINT32)strlen(text->text));
+ if (error != PNGERR_NONE)
+ goto handle_error;
+ }
+
+ /* write an IEND chunk */
+ error = write_chunk(fp, NULL, PNG_CN_IEND, 0);
+
+handle_error:
+ return error;
+}
+
+
+
+png_error png_write_bitmap(core_file *fp, png_info *info, bitmap_t *bitmap, int palette_length, const UINT32 *palette)
+{
+ png_info pnginfo;
+ png_error error;
+
+ /* use a dummy pnginfo if none passed to us */
+ if (info == NULL)
+ {
+ info = &pnginfo;
+ memset(&pnginfo, 0, sizeof(pnginfo));
+ }
+
+ /* write the PNG signature */
+ if (core_fwrite(fp, PNG_Signature, 8) != 8)
+ {
+ if (info == &pnginfo)
+ png_free(&pnginfo);
+ return PNGERR_FILE_ERROR;
+ }
+
+ /* write the rest of the PNG data */
+ error = write_png_stream(fp, info, bitmap, palette_length, palette);
+ if (info == &pnginfo)
+ png_free(&pnginfo);
+ return error;
+}
+
+
+
+/********************************************************************************
+
+ MNG write functions
+
+********************************************************************************/
+
+png_error mng_capture_start(core_file *fp, bitmap_t *bitmap, double rate)
+{
+ UINT8 mhdr[28];
+ png_error error;
+
+ if (core_fwrite(fp, MNG_Signature, 8) != 8)
+ return PNGERR_FILE_ERROR;
+
+ memset(mhdr, 0, 28);
+ put_32bit(mhdr + 0, bitmap->width);
+ put_32bit(mhdr + 4, bitmap->height);
+ put_32bit(mhdr + 8, rate);
+ put_32bit(mhdr + 24, 0x0041); /* Simplicity profile */
+ /* frame count and play time unspecified because
+ we don't know at this stage */
+ error = write_chunk(fp, mhdr, MNG_CN_MHDR, 28);
+ if (error != PNGERR_NONE)
+ return error;
+
+ return PNGERR_NONE;
+}
+
+png_error mng_capture_frame(core_file *fp, png_info *info, bitmap_t *bitmap, int palette_length, const UINT32 *palette)
+{
+ return write_png_stream(fp, info, bitmap, palette_length, palette);
+}
+
+png_error mng_capture_stop(core_file *fp)
+{
+ return write_chunk(fp, NULL, MNG_CN_MEND, 0);
+}
diff --git a/src/lib/util/png.h b/src/lib/util/png.h
new file mode 100644
index 00000000000..9d11d895d64
--- /dev/null
+++ b/src/lib/util/png.h
@@ -0,0 +1,137 @@
+/***************************************************************************
+
+ png.h
+
+ PNG file management.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __PNG_H__
+#define __PNG_H__
+
+#include "osdcore.h"
+#include "bitmap.h"
+#include "corefile.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define PNG_Signature "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A"
+#define MNG_Signature "\x8A\x4D\x4E\x47\x0D\x0A\x1A\x0A"
+
+/* Chunk names */
+#define PNG_CN_IHDR 0x49484452L
+#define PNG_CN_PLTE 0x504C5445L
+#define PNG_CN_IDAT 0x49444154L
+#define PNG_CN_IEND 0x49454E44L
+#define PNG_CN_gAMA 0x67414D41L
+#define PNG_CN_sBIT 0x73424954L
+#define PNG_CN_cHRM 0x6348524DL
+#define PNG_CN_tRNS 0x74524E53L
+#define PNG_CN_bKGD 0x624B4744L
+#define PNG_CN_hIST 0x68495354L
+#define PNG_CN_tEXt 0x74455874L
+#define PNG_CN_zTXt 0x7A545874L
+#define PNG_CN_pHYs 0x70485973L
+#define PNG_CN_oFFs 0x6F464673L
+#define PNG_CN_tIME 0x74494D45L
+#define PNG_CN_sCAL 0x7343414CL
+
+/* MNG Chunk names */
+#define MNG_CN_MHDR 0x4D484452L
+#define MNG_CN_MEND 0x4D454E44L
+#define MNG_CN_TERM 0x5445524DL
+#define MNG_CN_BACK 0x4241434BL
+
+/* Prediction filters */
+#define PNG_PF_None 0
+#define PNG_PF_Sub 1
+#define PNG_PF_Up 2
+#define PNG_PF_Average 3
+#define PNG_PF_Paeth 4
+
+/* Error types */
+enum _png_error
+{
+ PNGERR_NONE,
+ PNGERR_OUT_OF_MEMORY,
+ PNGERR_UNKNOWN_FILTER,
+ PNGERR_FILE_ERROR,
+ PNGERR_BAD_SIGNATURE,
+ PNGERR_DECOMPRESS_ERROR,
+ PNGERR_FILE_TRUNCATED,
+ PNGERR_FILE_CORRUPT,
+ PNGERR_UNKNOWN_CHUNK,
+ PNGERR_COMPRESS_ERROR,
+ PNGERR_UNSUPPORTED_FORMAT
+};
+typedef enum _png_error png_error;
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _png_text png_text;
+struct _png_text
+{
+ png_text * next;
+ const char * keyword; /* this is allocated */
+ const char * text; /* this points to a part of keyword */
+};
+
+
+typedef struct _png_info png_info;
+struct _png_info
+{
+ UINT8 * image;
+ UINT32 width, height;
+ UINT32 xres, yres;
+ rectangle screen;
+ double xscale, yscale;
+ double source_gamma;
+ UINT32 resolution_unit;
+ UINT8 bit_depth;
+ UINT8 color_type;
+ UINT8 compression_method;
+ UINT8 filter_method;
+ UINT8 interlace_method;
+
+ UINT8 * palette;
+ UINT32 num_palette;
+
+ UINT8 * trans;
+ UINT32 num_trans;
+
+ png_text * textlist;
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+void png_free(png_info *pnginfo);
+
+png_error png_read_file(core_file *fp, png_info *pnginfo);
+png_error png_read_bitmap(core_file *fp, bitmap_t **bitmap);
+png_error png_expand_buffer_8bit(png_info *p);
+
+png_error png_add_text(png_info *pnginfo, const char *keyword, const char *text);
+png_error png_write_bitmap(core_file *fp, png_info *info, bitmap_t *bitmap, int palette_length, const UINT32 *palette);
+
+png_error mng_capture_start(core_file *fp, bitmap_t *bitmap, double rate);
+png_error mng_capture_frame(core_file *fp, png_info *info, bitmap_t *bitmap, int palette_length, const UINT32 *palette);
+png_error mng_capture_stop(core_file *fp);
+
+#endif /* __PNG_H__ */
diff --git a/src/lib/util/pool.c b/src/lib/util/pool.c
new file mode 100644
index 00000000000..62b131416fb
--- /dev/null
+++ b/src/lib/util/pool.c
@@ -0,0 +1,614 @@
+/***************************************************************************
+
+ pool.c
+
+ Resource pool code
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "pool.h"
+#include "coreutil.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define OBJECT_ENTRY_BLOCK 256
+#define POOL_HASH_SIZE 3797
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* an object type entry */
+typedef struct _objtype_entry objtype_entry;
+struct _objtype_entry
+{
+ objtype_entry * next;
+ UINT32 type;
+ const char * friendly;
+ void (*destructor)(void *, size_t);
+};
+
+
+/* an entry in a pool */
+typedef struct _object_entry object_entry;
+struct _object_entry
+{
+ object_entry * next;
+ objtype_entry * type;
+ void * object;
+ size_t size;
+ const char * file;
+ int line;
+};
+
+
+/* a block of entry items */
+typedef struct _object_entry_block object_entry_block;
+struct _object_entry_block
+{
+ object_entry_block *next;
+ object_entry entry[OBJECT_ENTRY_BLOCK];
+};
+
+
+/* the object pool itself */
+struct _object_pool
+{
+ object_entry * hashtable[POOL_HASH_SIZE];
+ object_entry * freelist;
+ object_entry_block *blocklist;
+ objtype_entry * typelist;
+ void (*fail)(const char *message);
+};
+
+
+/* an iterator over objects in a pool */
+struct _object_pool_iterator
+{
+ object_pool * pool;
+ object_type type;
+ int hashnum;
+ object_entry * last;
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static void memory_destruct(void *object, size_t size);
+static void report_failure(object_pool *pool, const char *format, ...);
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ hash_object - compute the hash for a given
+ object
+-------------------------------------------------*/
+
+INLINE int hash_object(void *object)
+{
+ return ((size_t)object >> 4) % POOL_HASH_SIZE;
+}
+
+
+/*-------------------------------------------------
+ hash_object - compute the hash for a given
+ object
+-------------------------------------------------*/
+
+INLINE objtype_entry *get_object_type(object_pool *pool, object_type type)
+{
+ objtype_entry *entry;
+
+ for (entry = pool->typelist; entry != NULL; entry = entry->next)
+ if (entry->type == type)
+ return entry;
+
+ return NULL;
+}
+
+
+
+/***************************************************************************
+ RESOURCE POOL MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ pool_alloc - allocates a new memory pool
+-------------------------------------------------*/
+
+object_pool *pool_alloc(void (*fail)(const char *message))
+{
+ object_pool *pool;
+
+ /* allocate memory for the pool itself */
+ pool = malloc(sizeof(*pool));
+ if (pool == NULL)
+ return NULL;
+ memset(pool, 0, sizeof(*pool));
+
+ /* register the built-in types */
+ pool_type_register(pool, OBJTYPE_MEMORY, "Memory", memory_destruct);
+
+ return pool;
+}
+
+
+/*-------------------------------------------------
+ pool_type_register - register a new pool
+ type
+-------------------------------------------------*/
+
+void pool_type_register(object_pool *pool, object_type type, const char *friendly, void (*destructor)(void *, size_t))
+{
+ objtype_entry *newtype = get_object_type(pool, type);
+
+ /* if the type doesn't already exist... */
+ if (newtype == NULL)
+ {
+ /* allocate a new entry */
+ newtype = malloc(sizeof(*newtype));
+ if (newtype == NULL)
+ {
+ report_failure(pool, "Error adding new type %s\n", friendly);
+ return;
+ }
+ memset(newtype, 0, sizeof(*newtype));
+
+ /* link us in */
+ newtype->next = pool->typelist;
+ pool->typelist = newtype;
+ }
+
+ /* fill in the type information */
+ newtype->type = type;
+ newtype->friendly = friendly;
+ newtype->destructor = destructor;
+}
+
+
+/*-------------------------------------------------
+ pool_clear - frees all contained memory blocks
+ in a pool
+-------------------------------------------------*/
+
+void pool_clear(object_pool *pool)
+{
+ int hashnum;
+
+ /* iterate over hash buckets */
+ for (hashnum = 0; hashnum < ARRAY_LENGTH(pool->hashtable); hashnum++)
+ {
+ object_entry *entry, *next;
+
+ /* iterate over entries in this hash bucket and free them */
+ for (entry = pool->hashtable[hashnum]; entry != NULL; entry = next)
+ {
+ /* remember the next entry */
+ next = entry->next;
+
+ /* call the destructor */
+ (*entry->type->destructor)(entry->object, entry->size);
+
+ /* add ourself to the free list */
+ entry->next = pool->freelist;
+ pool->freelist = entry;
+ }
+
+ /* reset the list we just walked */
+ pool->hashtable[hashnum] = NULL;
+ }
+}
+
+
+/*-------------------------------------------------
+ pool_free - frees a memory pool and all
+ contained memory blocks
+-------------------------------------------------*/
+
+void pool_free(object_pool *pool)
+{
+ object_entry_block *block, *nextblock;
+ objtype_entry *type, *nexttype;
+
+ /* clear the pool */
+ pool_clear(pool);
+
+ /* free all entry blocks */
+ for (block = pool->blocklist; block != NULL; block = nextblock)
+ {
+ nextblock = block->next;
+ free(block);
+ }
+
+ /* free all types */
+ for (type = pool->typelist; type != NULL; type = nexttype)
+ {
+ nexttype = type->next;
+ free(type);
+ }
+
+ /* free the pool itself */
+ free(pool);
+}
+
+
+
+/***************************************************************************
+ OBJECT MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ pool_object_add_file_line - add an object to
+ the resource pool
+-------------------------------------------------*/
+
+void *pool_object_add_file_line(object_pool *pool, object_type _type, void *object, size_t size, const char *file, int line)
+{
+ objtype_entry *type = get_object_type(pool, _type);
+ int hashnum = hash_object(object);
+ object_entry *entry;
+
+ /* if we have an invalid type, fail */
+ if (type == NULL)
+ {
+ report_failure(pool, "pool_object_add (via %s:%d): Attempted to add object of unknown type", file, line, (int)size);
+ return object;
+ }
+
+ /* if we get a NULL object, fail */
+ if (object == NULL)
+ {
+ report_failure(pool, "pool_object_add (via %s:%d): Attempted to add a NULL object of size %d", file, line, (int)size);
+ return object;
+ }
+
+ /* allocate a new entry */
+ if (pool->freelist == NULL)
+ {
+ object_entry_block *block;
+ int entrynum;
+
+ /* if we need a new block, allocate that now */
+ block = malloc(sizeof(*block));
+ if (block == NULL)
+ return NULL;
+ memset(block, 0, sizeof(*block));
+
+ /* hook us into the blocklist */
+ block->next = pool->blocklist;
+ pool->blocklist = block;
+
+ /* add all entries to the free list */
+ for (entrynum = 0; entrynum < ARRAY_LENGTH(block->entry); entrynum++)
+ {
+ block->entry[entrynum].next = pool->freelist;
+ pool->freelist = &block->entry[entrynum];
+ }
+ }
+
+ /* remove the head of the freelist */
+ entry = pool->freelist;
+ pool->freelist = entry->next;
+
+ /* fill in the entry */
+ entry->type = type;
+ entry->object = object;
+ entry->size = size;
+ entry->file = file;
+ entry->line = line;
+
+ /* hook us into the list */
+ entry->next = pool->hashtable[hashnum];
+ pool->hashtable[hashnum] = entry;
+ return object;
+}
+
+
+/*-------------------------------------------------
+ pool_object_remove - remove an entry from a
+ pool, optionally calling its destructor
+-------------------------------------------------*/
+
+void *pool_object_remove(object_pool *pool, void *object, int destruct)
+{
+ int hashnum = hash_object(object);
+ object_entry **entryptr;
+
+ /* find the object in question and remove it */
+ for (entryptr = &pool->hashtable[hashnum]; *entryptr != NULL; entryptr = &(*entryptr)->next)
+ if ((*entryptr)->object == object)
+ {
+ object_entry *entry = *entryptr;
+
+ /* call the destructor */
+ if (destruct)
+ (*entry->type->destructor)(entry->object, entry->size);
+
+ /* remove us from the list */
+ *entryptr = entry->next;
+
+ /* add us to the free list */
+ entry->next = pool->freelist;
+ pool->freelist = entry;
+ break;
+ }
+
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ pool_object_exists - return TRUE if an
+ object exists in the pool
+-------------------------------------------------*/
+
+int pool_object_exists(object_pool *pool, object_type type, void *object)
+{
+ int hashnum = hash_object(object);
+ object_entry *entry;
+
+ /* find the object in question */
+ for (entry = pool->hashtable[hashnum]; entry != NULL; entry = entry->next)
+ if (entry->object == object && (type == OBJTYPE_WILDCARD || entry->type->type == type))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+
+/***************************************************************************
+ OBJECT ITERATORS
+***************************************************************************/
+
+/*-------------------------------------------------
+ pool_iterate_begin - begin iterating over
+ objects in an object pool
+-------------------------------------------------*/
+
+object_pool_iterator *pool_iterate_begin(object_pool *pool, object_type type)
+{
+ object_pool_iterator *iter;
+
+ /* allocate the iterator */
+ iter = malloc(sizeof(*iter));
+ if (iter == NULL)
+ return NULL;
+ memset(iter, 0, sizeof(*iter));
+
+ /* fill it in */
+ iter->pool = pool;
+ iter->type = type;
+ iter->hashnum = 0;
+ iter->last = NULL;
+ return iter;
+}
+
+
+/*-------------------------------------------------
+ pool_iterate_next - get the next object in the
+ object pool
+-------------------------------------------------*/
+
+int pool_iterate_next(object_pool_iterator *iter, void **objectptr, size_t *sizeptr, object_type *typeptr)
+{
+ /* advance from the last one */
+ while (iter->hashnum < ARRAY_LENGTH(iter->pool->hashtable))
+ {
+ /* if the last entry is non-NULL, advance */
+ if (iter->last == NULL)
+ iter->last = iter->pool->hashtable[iter->hashnum++];
+ else
+ iter->last = iter->last->next;
+
+ /* stop when we get one */
+ if (iter->last != NULL)
+ {
+ if (objectptr != NULL)
+ *objectptr = iter->last;
+ if (sizeptr != NULL)
+ *sizeptr = iter->last->size;
+ if (typeptr != NULL)
+ *typeptr = iter->last->type->type;
+ return TRUE;
+ }
+ }
+
+ /* nothing left */
+ return FALSE;
+}
+
+
+/*-------------------------------------------------
+ pool_iterate_end - finish iterating over
+ objects in an object pool
+-------------------------------------------------*/
+
+void pool_iterate_end(object_pool_iterator *iter)
+{
+ free(iter);
+}
+
+
+
+/***************************************************************************
+ MEMORY HELPERS
+***************************************************************************/
+
+/*-------------------------------------------------
+ pool_malloc_file_line - allocates memory in a
+ memory pool
+-------------------------------------------------*/
+
+void *pool_malloc_file_line(object_pool *pool, size_t size, const char *file, int line)
+{
+#ifdef MALLOC_DEBUG
+ void *ptr = malloc_file_line(size, file, line);
+#else
+ void *ptr = malloc(size);
+#endif
+ return pool_object_add_file_line(pool, OBJTYPE_MEMORY, ptr, size, file, line);
+}
+
+
+/*-------------------------------------------------
+ pool_realloc_file_line - reallocs memory in a
+ memory pool
+-------------------------------------------------*/
+
+void *pool_realloc_file_line(object_pool *pool, void *ptr, size_t size, const char *file, int line)
+{
+ if (ptr != NULL)
+ pool_object_remove(pool, ptr, FALSE);
+#ifdef MALLOC_DEBUG
+ ptr = realloc_file_line(ptr, size, file, line);
+#else
+ ptr = realloc(ptr, size);
+#endif
+ if (size != 0)
+ pool_object_add_file_line(pool, OBJTYPE_MEMORY, ptr, size, file, line);
+ return ptr;
+}
+
+
+/*-------------------------------------------------
+ pool_strdup_file_line - strdup in a memory
+ pool
+-------------------------------------------------*/
+
+char *pool_strdup_file_line(object_pool *pool, const char *str, const char *file, int line)
+{
+ char *ptr = pool_malloc_file_line(pool, strlen(str) + 1, file, line);
+ if (ptr != NULL)
+ strcpy(ptr, str);
+ return ptr;
+}
+
+
+
+/***************************************************************************
+ GENERIC DESTRUCTORS
+***************************************************************************/
+
+/*-------------------------------------------------
+ memory_destruct - generic destructor
+ that just does a free() on the object
+-------------------------------------------------*/
+
+static void memory_destruct(void *object, size_t size)
+{
+ free(object);
+}
+
+
+
+/***************************************************************************
+ INTERNAL FUNCTIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ report_failure - report a failure to the
+ failure callback
+-------------------------------------------------*/
+
+static void report_failure(object_pool *pool, const char *format, ...)
+{
+ /* only do the work if we have a callback */
+ if (pool->fail != NULL)
+ {
+ char message[1024];
+ va_list argptr;
+
+ /* generate the final message text */
+ va_start(argptr, format);
+ vsprintf(message, format, argptr);
+ va_end(argptr);
+
+ /* call the callback with the message */
+ (*pool->fail)(message);
+ }
+}
+
+
+
+/***************************************************************************
+ TESTING FUNCTIONS
+***************************************************************************/
+
+static int has_memory_error;
+
+
+/*-------------------------------------------------
+ memory_error - report a memory error
+-------------------------------------------------*/
+
+static void memory_error(const char *message)
+{
+ printf("memory test failure: %s\n", message);
+ has_memory_error = TRUE;
+}
+
+
+/*-------------------------------------------------
+ test_memory_pools - unit tests for memory
+ pool behavior
+-------------------------------------------------*/
+
+int test_memory_pools(void)
+{
+ object_pool *pool;
+ void *ptrs[16];
+ int i;
+
+ has_memory_error = FALSE;
+ pool = pool_alloc(memory_error);
+ memset(ptrs, 0, sizeof(ptrs));
+
+ ptrs[0] = pool_malloc(pool, 50);
+ ptrs[1] = pool_malloc(pool, 100);
+
+ ptrs[0] = pool_realloc(pool, ptrs[0], 150);
+ ptrs[1] = pool_realloc(pool, ptrs[1], 200);
+
+ ptrs[2] = pool_malloc(pool, 250);
+ ptrs[3] = pool_malloc(pool, 300);
+
+ ptrs[0] = pool_realloc(pool, ptrs[0], 350);
+ ptrs[1] = pool_realloc(pool, ptrs[1], 400);
+
+ ptrs[2] = pool_realloc(pool, ptrs[2], 450);
+ ptrs[3] = pool_realloc(pool, ptrs[3], 500);
+
+ ptrs[0] = pool_realloc(pool, ptrs[0], 0);
+ ptrs[1] = pool_realloc(pool, ptrs[1], 0);
+
+ ptrs[2] = pool_realloc(pool, ptrs[2], 550);
+ ptrs[3] = pool_realloc(pool, ptrs[3], 600);
+
+ /* some heavier stress tests */
+ for (i = 0; i < 512; i++)
+ {
+ ptrs[i % ARRAY_LENGTH(ptrs)] = pool_realloc(pool,
+ ptrs[i % ARRAY_LENGTH(ptrs)], rand() % 1000);
+ }
+
+ pool_free(pool);
+ return has_memory_error;
+}
diff --git a/src/lib/util/pool.h b/src/lib/util/pool.h
new file mode 100644
index 00000000000..6d746c36de5
--- /dev/null
+++ b/src/lib/util/pool.h
@@ -0,0 +1,117 @@
+/***************************************************************************
+
+ pool.h
+
+ Abstract object pool management
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#ifndef __POOL_H__
+#define __POOL_H__
+
+#include "osdcore.h"
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+/* helper macros for memory pools that pass file/line number */
+#define pool_malloc(pool, size) pool_malloc_file_line((pool), (size), __FILE__, __LINE__)
+#define pool_realloc(pool, ptr, size) pool_realloc_file_line((pool), (ptr), (size), __FILE__, __LINE__)
+#define pool_strdup(pool, size) pool_strdup_file_line((pool), (size), __FILE__, __LINE__)
+
+/* macro to define a 4-character type for a pool */
+#define OBJECT_TYPE(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
+
+/* built-in pool types */
+#define OBJTYPE_WILDCARD (0)
+#define OBJTYPE_MEMORY OBJECT_TYPE('m','e','m','o')
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* pool types are UINT32s */
+typedef UINT32 object_type;
+
+/* opaque type representing a pool of objects */
+typedef struct _object_pool object_pool;
+
+/* opaque type representing an iterator over pool objects */
+typedef struct _object_pool_iterator object_pool_iterator;
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+
+/* ----- object pool management ----- */
+
+/* allocate a new object pool */
+object_pool *pool_alloc(void (*fail)(const char *message));
+
+/* register a new object type; returns TRUE if the type already existed and was overridden */
+void pool_type_register(object_pool *pool, object_type type, const char *friendly, void (*destructor)(void *, size_t));
+
+/* free all allocated objects in a pool */
+void pool_clear(object_pool *pool);
+
+/* free an object pool, including all allocated objects */
+void pool_free(object_pool *pool);
+
+
+
+/* ----- object management ----- */
+
+/* add an object to the pool, along with its filename/line number */
+void *pool_object_add_file_line(object_pool *pool, object_type type, void *object, size_t size, const char *file, int line);
+
+/* remove an object from the pool (optionally calling destructor) */
+void *pool_object_remove(object_pool *pool, void *object, int destruct);
+
+/* does an object exist in the pool? */
+int pool_object_exists(object_pool *pool, object_type type, void *object);
+
+
+
+/* ----- object iterators ----- */
+
+/* begin iterating over objects in an object pool */
+object_pool_iterator *pool_iterate_begin(object_pool *pool, object_type type);
+
+/* get the next object in the object pool */
+int pool_iterate_next(object_pool_iterator *iter, void **objectptr, size_t *sizeptr, object_type *typeptr);
+
+/* finish iterating over objects in an object pool */
+void pool_iterate_end(object_pool_iterator *iter);
+
+
+
+/* ----- memory helpers ----- */
+
+/* malloc memory and register it with the given pool */
+void *pool_malloc_file_line(object_pool *pool, size_t size, const char *file, int line);
+
+/* realloc memory and register it with the given pool */
+void *pool_realloc_file_line(object_pool *pool, void *ptr, size_t size, const char *file, int line);
+
+/* strdup memory and register it with the given pool */
+char *pool_strdup_file_line(object_pool *pool, const char *str, const char *file, int line);
+
+
+
+/* ----- miscellaneous ----- */
+
+/* internal unit tests */
+int test_memory_pools(void);
+
+
+#endif /* __POOL_H__ */
diff --git a/src/lib/util/sha1.c b/src/lib/util/sha1.c
new file mode 100644
index 00000000000..bf376874816
--- /dev/null
+++ b/src/lib/util/sha1.c
@@ -0,0 +1,387 @@
+/* sha1.h
+ *
+ * The sha1 hash function.
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2001 Peter Gutmann, Andrew Kuchling, Niels Moeller
+ *
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The nettle library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#include "sha1.h"
+//#include "macros.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+static unsigned int READ_UINT32(const UINT8* data)
+{
+ return ((UINT32)data[0] << 24) |
+ ((UINT32)data[1] << 16) |
+ ((UINT32)data[2] << 8) |
+ ((UINT32)data[3]);
+}
+
+static void WRITE_UINT32(unsigned char* data, UINT32 val)
+{
+ data[0] = (val >> 24) & 0xFF;
+ data[1] = (val >> 16) & 0xFF;
+ data[2] = (val >> 8) & 0xFF;
+ data[3] = (val >> 0) & 0xFF;
+}
+
+
+/* A block, treated as a sequence of 32-bit words. */
+#define SHA1_DATA_LENGTH 16
+
+/* The SHA f()-functions. The f1 and f3 functions can be optimized to
+ save one boolean operation each - thanks to Rich Schroeppel,
+ rcs@cs.arizona.edu for discovering this */
+
+/* #define f1(x,y,z) ( ( x & y ) | ( ~x & z ) ) Rounds 0-19 */
+#define f1(x,y,z) ( z ^ ( x & ( y ^ z ) ) ) /* Rounds 0-19 */
+#define f2(x,y,z) ( x ^ y ^ z ) /* Rounds 20-39 */
+/* #define f3(x,y,z) ( ( x & y ) | ( x & z ) | ( y & z ) ) Rounds 40-59 */
+#define f3(x,y,z) ( ( x & y ) | ( z & ( x | y ) ) ) /* Rounds 40-59 */
+#define f4(x,y,z) ( x ^ y ^ z ) /* Rounds 60-79 */
+
+/* The SHA Mysterious Constants */
+
+#define K1 0x5A827999L /* Rounds 0-19 */
+#define K2 0x6ED9EBA1L /* Rounds 20-39 */
+#define K3 0x8F1BBCDCL /* Rounds 40-59 */
+#define K4 0xCA62C1D6L /* Rounds 60-79 */
+
+/* SHA initial values */
+
+#define h0init 0x67452301L
+#define h1init 0xEFCDAB89L
+#define h2init 0x98BADCFEL
+#define h3init 0x10325476L
+#define h4init 0xC3D2E1F0L
+
+/* 32-bit rotate left - kludged with shifts */
+#ifdef _MSC_VER
+#define ROTL(n,X) _lrotl(X, n)
+#else
+#define ROTL(n,X) ( ( (X) << (n) ) | ( (X) >> ( 32 - (n) ) ) )
+#endif
+
+/* The initial expanding function. The hash function is defined over an
+ 80-word expanded input array W, where the first 16 are copies of the input
+ data, and the remaining 64 are defined by
+
+ W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ]
+
+ This implementation generates these values on the fly in a circular
+ buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this
+ optimization.
+
+ The updated SHA changes the expanding function by adding a rotate of 1
+ bit. Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor
+ for this information */
+
+#define expand(W,i) ( W[ i & 15 ] = \
+ ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \
+ W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) ) )
+
+
+/* The prototype SHA sub-round. The fundamental sub-round is:
+
+ a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data;
+ b' = a;
+ c' = ROTL( 30, b );
+ d' = c;
+ e' = d;
+
+ but this is implemented by unrolling the loop 5 times and renaming the
+ variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration.
+ This code is then replicated 20 times for each of the 4 functions, using
+ the next 20 values from the W[] array each time */
+
+#define subRound(a, b, c, d, e, f, k, data) \
+ ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) )
+
+/* Initialize the SHA values */
+
+void
+sha1_init(struct sha1_ctx *ctx)
+{
+ /* Set the h-vars to their initial values */
+ ctx->digest[ 0 ] = h0init;
+ ctx->digest[ 1 ] = h1init;
+ ctx->digest[ 2 ] = h2init;
+ ctx->digest[ 3 ] = h3init;
+ ctx->digest[ 4 ] = h4init;
+
+ /* Initialize bit count */
+ ctx->count_low = ctx->count_high = 0;
+
+ /* Initialize buffer */
+ ctx->index = 0;
+}
+
+/* Perform the SHA transformation. Note that this code, like MD5, seems to
+ break some optimizing compilers due to the complexity of the expressions
+ and the size of the basic block. It may be necessary to split it into
+ sections, e.g. based on the four subrounds
+
+ Note that this function destroys the data area */
+
+static void
+sha1_transform(UINT32 *state, UINT32 *data)
+{
+ UINT32 A, B, C, D, E; /* Local vars */
+
+ /* Set up first buffer and local data buffer */
+ A = state[0];
+ B = state[1];
+ C = state[2];
+ D = state[3];
+ E = state[4];
+
+ /* Heavy mangling, in 4 sub-rounds of 20 interations each. */
+ subRound( A, B, C, D, E, f1, K1, data[ 0] );
+ subRound( E, A, B, C, D, f1, K1, data[ 1] );
+ subRound( D, E, A, B, C, f1, K1, data[ 2] );
+ subRound( C, D, E, A, B, f1, K1, data[ 3] );
+ subRound( B, C, D, E, A, f1, K1, data[ 4] );
+ subRound( A, B, C, D, E, f1, K1, data[ 5] );
+ subRound( E, A, B, C, D, f1, K1, data[ 6] );
+ subRound( D, E, A, B, C, f1, K1, data[ 7] );
+ subRound( C, D, E, A, B, f1, K1, data[ 8] );
+ subRound( B, C, D, E, A, f1, K1, data[ 9] );
+ subRound( A, B, C, D, E, f1, K1, data[10] );
+ subRound( E, A, B, C, D, f1, K1, data[11] );
+ subRound( D, E, A, B, C, f1, K1, data[12] );
+ subRound( C, D, E, A, B, f1, K1, data[13] );
+ subRound( B, C, D, E, A, f1, K1, data[14] );
+ subRound( A, B, C, D, E, f1, K1, data[15] );
+ subRound( E, A, B, C, D, f1, K1, expand( data, 16 ) );
+ subRound( D, E, A, B, C, f1, K1, expand( data, 17 ) );
+ subRound( C, D, E, A, B, f1, K1, expand( data, 18 ) );
+ subRound( B, C, D, E, A, f1, K1, expand( data, 19 ) );
+
+ subRound( A, B, C, D, E, f2, K2, expand( data, 20 ) );
+ subRound( E, A, B, C, D, f2, K2, expand( data, 21 ) );
+ subRound( D, E, A, B, C, f2, K2, expand( data, 22 ) );
+ subRound( C, D, E, A, B, f2, K2, expand( data, 23 ) );
+ subRound( B, C, D, E, A, f2, K2, expand( data, 24 ) );
+ subRound( A, B, C, D, E, f2, K2, expand( data, 25 ) );
+ subRound( E, A, B, C, D, f2, K2, expand( data, 26 ) );
+ subRound( D, E, A, B, C, f2, K2, expand( data, 27 ) );
+ subRound( C, D, E, A, B, f2, K2, expand( data, 28 ) );
+ subRound( B, C, D, E, A, f2, K2, expand( data, 29 ) );
+ subRound( A, B, C, D, E, f2, K2, expand( data, 30 ) );
+ subRound( E, A, B, C, D, f2, K2, expand( data, 31 ) );
+ subRound( D, E, A, B, C, f2, K2, expand( data, 32 ) );
+ subRound( C, D, E, A, B, f2, K2, expand( data, 33 ) );
+ subRound( B, C, D, E, A, f2, K2, expand( data, 34 ) );
+ subRound( A, B, C, D, E, f2, K2, expand( data, 35 ) );
+ subRound( E, A, B, C, D, f2, K2, expand( data, 36 ) );
+ subRound( D, E, A, B, C, f2, K2, expand( data, 37 ) );
+ subRound( C, D, E, A, B, f2, K2, expand( data, 38 ) );
+ subRound( B, C, D, E, A, f2, K2, expand( data, 39 ) );
+
+ subRound( A, B, C, D, E, f3, K3, expand( data, 40 ) );
+ subRound( E, A, B, C, D, f3, K3, expand( data, 41 ) );
+ subRound( D, E, A, B, C, f3, K3, expand( data, 42 ) );
+ subRound( C, D, E, A, B, f3, K3, expand( data, 43 ) );
+ subRound( B, C, D, E, A, f3, K3, expand( data, 44 ) );
+ subRound( A, B, C, D, E, f3, K3, expand( data, 45 ) );
+ subRound( E, A, B, C, D, f3, K3, expand( data, 46 ) );
+ subRound( D, E, A, B, C, f3, K3, expand( data, 47 ) );
+ subRound( C, D, E, A, B, f3, K3, expand( data, 48 ) );
+ subRound( B, C, D, E, A, f3, K3, expand( data, 49 ) );
+ subRound( A, B, C, D, E, f3, K3, expand( data, 50 ) );
+ subRound( E, A, B, C, D, f3, K3, expand( data, 51 ) );
+ subRound( D, E, A, B, C, f3, K3, expand( data, 52 ) );
+ subRound( C, D, E, A, B, f3, K3, expand( data, 53 ) );
+ subRound( B, C, D, E, A, f3, K3, expand( data, 54 ) );
+ subRound( A, B, C, D, E, f3, K3, expand( data, 55 ) );
+ subRound( E, A, B, C, D, f3, K3, expand( data, 56 ) );
+ subRound( D, E, A, B, C, f3, K3, expand( data, 57 ) );
+ subRound( C, D, E, A, B, f3, K3, expand( data, 58 ) );
+ subRound( B, C, D, E, A, f3, K3, expand( data, 59 ) );
+
+ subRound( A, B, C, D, E, f4, K4, expand( data, 60 ) );
+ subRound( E, A, B, C, D, f4, K4, expand( data, 61 ) );
+ subRound( D, E, A, B, C, f4, K4, expand( data, 62 ) );
+ subRound( C, D, E, A, B, f4, K4, expand( data, 63 ) );
+ subRound( B, C, D, E, A, f4, K4, expand( data, 64 ) );
+ subRound( A, B, C, D, E, f4, K4, expand( data, 65 ) );
+ subRound( E, A, B, C, D, f4, K4, expand( data, 66 ) );
+ subRound( D, E, A, B, C, f4, K4, expand( data, 67 ) );
+ subRound( C, D, E, A, B, f4, K4, expand( data, 68 ) );
+ subRound( B, C, D, E, A, f4, K4, expand( data, 69 ) );
+ subRound( A, B, C, D, E, f4, K4, expand( data, 70 ) );
+ subRound( E, A, B, C, D, f4, K4, expand( data, 71 ) );
+ subRound( D, E, A, B, C, f4, K4, expand( data, 72 ) );
+ subRound( C, D, E, A, B, f4, K4, expand( data, 73 ) );
+ subRound( B, C, D, E, A, f4, K4, expand( data, 74 ) );
+ subRound( A, B, C, D, E, f4, K4, expand( data, 75 ) );
+ subRound( E, A, B, C, D, f4, K4, expand( data, 76 ) );
+ subRound( D, E, A, B, C, f4, K4, expand( data, 77 ) );
+ subRound( C, D, E, A, B, f4, K4, expand( data, 78 ) );
+ subRound( B, C, D, E, A, f4, K4, expand( data, 79 ) );
+
+ /* Build message digest */
+ state[0] += A;
+ state[1] += B;
+ state[2] += C;
+ state[3] += D;
+ state[4] += E;
+}
+
+static void
+sha1_block(struct sha1_ctx *ctx, const UINT8 *block)
+{
+ UINT32 data[SHA1_DATA_LENGTH];
+ int i;
+
+ /* Update block count */
+ if (!++ctx->count_low)
+ ++ctx->count_high;
+
+ /* Endian independent conversion */
+ for (i = 0; i<SHA1_DATA_LENGTH; i++, block += 4)
+ data[i] = READ_UINT32(block);
+
+ sha1_transform(ctx->digest, data);
+}
+
+void
+sha1_update(struct sha1_ctx *ctx,
+ unsigned length, const UINT8 *buffer)
+{
+ if (ctx->index)
+ { /* Try to fill partial block */
+ unsigned left = SHA1_DATA_SIZE - ctx->index;
+ if (length < left)
+ {
+ memcpy(ctx->block + ctx->index, buffer, length);
+ ctx->index += length;
+ return; /* Finished */
+ }
+ else
+ {
+ memcpy(ctx->block + ctx->index, buffer, left);
+ sha1_block(ctx, ctx->block);
+ buffer += left;
+ length -= left;
+ }
+ }
+ while (length >= SHA1_DATA_SIZE)
+ {
+ sha1_block(ctx, buffer);
+ buffer += SHA1_DATA_SIZE;
+ length -= SHA1_DATA_SIZE;
+ }
+ if ((ctx->index = length)) /* This assignment is intended */
+ /* Buffer leftovers */
+ memcpy(ctx->block, buffer, length);
+}
+
+/* Final wrapup - pad to SHA1_DATA_SIZE-byte boundary with the bit pattern
+ 1 0* (64-bit count of bits processed, MSB-first) */
+
+void
+sha1_final(struct sha1_ctx *ctx)
+{
+ UINT32 data[SHA1_DATA_LENGTH];
+ int i;
+ int words;
+
+ i = ctx->index;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+
+ assert(i < SHA1_DATA_SIZE);
+ ctx->block[i++] = 0x80;
+
+ /* Fill rest of word */
+ for( ; i & 3; i++)
+ ctx->block[i] = 0;
+
+ /* i is now a multiple of the word size 4 */
+ words = i >> 2;
+ for (i = 0; i < words; i++)
+ data[i] = READ_UINT32(ctx->block + 4*i);
+
+ if (words > (SHA1_DATA_LENGTH-2))
+ { /* No room for length in this block. Process it and
+ * pad with another one */
+ for (i = words ; i < SHA1_DATA_LENGTH; i++)
+ data[i] = 0;
+ sha1_transform(ctx->digest, data);
+ for (i = 0; i < (SHA1_DATA_LENGTH-2); i++)
+ data[i] = 0;
+ }
+ else
+ for (i = words ; i < SHA1_DATA_LENGTH - 2; i++)
+ data[i] = 0;
+
+ /* There are 512 = 2^9 bits in one block */
+ data[SHA1_DATA_LENGTH-2] = (ctx->count_high << 9) | (ctx->count_low >> 23);
+ data[SHA1_DATA_LENGTH-1] = (ctx->count_low << 9) | (ctx->index << 3);
+ sha1_transform(ctx->digest, data);
+}
+
+void
+sha1_digest(const struct sha1_ctx *ctx,
+ unsigned length,
+ UINT8 *digest)
+{
+ unsigned i;
+ unsigned words;
+ unsigned leftover;
+
+ assert(length <= SHA1_DIGEST_SIZE);
+
+ words = length / 4;
+ leftover = length % 4;
+
+ for (i = 0; i < words; i++, digest += 4)
+ WRITE_UINT32(digest, ctx->digest[i]);
+
+ if (leftover)
+ {
+ UINT32 word;
+ unsigned j = leftover;
+
+ assert(i < _SHA1_DIGEST_LENGTH);
+
+ word = ctx->digest[i];
+
+ switch (leftover)
+ {
+ default:
+ /* this is just here to keep the compiler happy; it can never happen */
+ case 3:
+ digest[--j] = (word >> 8) & 0xff;
+ /* Fall through */
+ case 2:
+ digest[--j] = (word >> 16) & 0xff;
+ /* Fall through */
+ case 1:
+ digest[--j] = (word >> 24) & 0xff;
+ }
+ }
+}
diff --git a/src/lib/util/sha1.h b/src/lib/util/sha1.h
new file mode 100644
index 00000000000..8f9d9cdd835
--- /dev/null
+++ b/src/lib/util/sha1.h
@@ -0,0 +1,61 @@
+/* sha1.h
+ *
+ * The sha1 hash function.
+ */
+
+/* nettle, low-level cryptographics library
+ *
+ * Copyright (C) 2001 Niels Moeller
+ *
+ * The nettle library is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * The nettle library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the nettle library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+#ifndef NETTLE_SHA1_H_INCLUDED
+#define NETTLE_SHA1_H_INCLUDED
+
+#include "osdcore.h"
+
+#define SHA1_DIGEST_SIZE 20
+#define SHA1_DATA_SIZE 64
+
+/* Digest is kept internally as 4 32-bit words. */
+#define _SHA1_DIGEST_LENGTH 5
+
+struct sha1_ctx
+{
+ UINT32 digest[_SHA1_DIGEST_LENGTH]; /* Message digest */
+ UINT32 count_low, count_high; /* 64-bit block count */
+ UINT8 block[SHA1_DATA_SIZE]; /* SHA1 data buffer */
+ unsigned int index; /* index into buffer */
+};
+
+void
+sha1_init(struct sha1_ctx *ctx);
+
+void
+sha1_update(struct sha1_ctx *ctx,
+ unsigned length,
+ const UINT8 *data);
+
+void
+sha1_final(struct sha1_ctx *ctx);
+
+void
+sha1_digest(const struct sha1_ctx *ctx,
+ unsigned length,
+ UINT8 *digest);
+
+#endif /* NETTLE_SHA1_H_INCLUDED */
diff --git a/src/lib/util/unicode.c b/src/lib/util/unicode.c
new file mode 100644
index 00000000000..33dac112fa7
--- /dev/null
+++ b/src/lib/util/unicode.c
@@ -0,0 +1,346 @@
+/*********************************************************************
+
+ unicode.c
+
+ Unicode related functions
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#include "unicode.h"
+
+
+/*-------------------------------------------------
+ uchar_isvalid - return true if a given
+ character is a legitimate unicode character
+-------------------------------------------------*/
+
+int uchar_isvalid(unicode_char uchar)
+{
+ return (uchar < 0x110000) && !((uchar >= 0xd800) && (uchar <= 0xdfff));
+}
+
+
+/*-------------------------------------------------
+ uchar_from_utf8 - convert a UTF-8 sequence
+ into a unicode character
+-------------------------------------------------*/
+
+int uchar_from_utf8(unicode_char *uchar, const char *utf8char, size_t count)
+{
+ unicode_char c, minchar;
+ int auxlen, i;
+ char auxchar;
+
+ /* validate parameters */
+ if (utf8char == NULL || count == 0)
+ return 0;
+
+ /* start with the first byte */
+ c = (unsigned char) *utf8char;
+ count--;
+ utf8char++;
+
+ /* based on that, determine how many additional bytes we need */
+ if (c < 0x80)
+ {
+ /* unicode char 0x00000000 - 0x0000007F */
+ c &= 0x7f;
+ auxlen = 0;
+ minchar = 0x00000000;
+ }
+ else if (c >= 0xc0 && c < 0xe0)
+ {
+ /* unicode char 0x00000080 - 0x000007FF */
+ c &= 0x1f;
+ auxlen = 1;
+ minchar = 0x00000080;
+ }
+ else if (c >= 0xe0 && c < 0xf0)
+ {
+ /* unicode char 0x00000800 - 0x0000FFFF */
+ c &= 0x0f;
+ auxlen = 2;
+ minchar = 0x00000800;
+ }
+ else if (c >= 0xf0 && c < 0xf8)
+ {
+ /* unicode char 0x00010000 - 0x001FFFFF */
+ c &= 0x07;
+ auxlen = 3;
+ minchar = 0x00010000;
+ }
+ else if (c >= 0xf8 && c < 0xfc)
+ {
+ /* unicode char 0x00200000 - 0x03FFFFFF */
+ c &= 0x03;
+ auxlen = 4;
+ minchar = 0x00200000;
+ }
+ else if (c >= 0xfc && c < 0xfe)
+ {
+ /* unicode char 0x04000000 - 0x7FFFFFFF */
+ c &= 0x01;
+ auxlen = 5;
+ minchar = 0x04000000;
+ }
+ else
+ {
+ /* invalid */
+ return -1;
+ }
+
+ /* exceeds the count? */
+ if (auxlen > count)
+ return -1;
+
+ /* we now know how long the char is, now compute it */
+ for (i = 0; i < auxlen; i++)
+ {
+ auxchar = utf8char[i];
+
+ /* all auxillary chars must be between 0x80-0xbf */
+ if ((auxchar & 0xc0) != 0x80)
+ return -1;
+
+ c = c << 6;
+ c |= auxchar & 0x3f;
+ }
+
+ /* make sure that this char is above the minimum */
+ if (c < minchar)
+ return -1;
+
+ *uchar = c;
+ return auxlen + 1;
+}
+
+
+/*-------------------------------------------------
+ uchar_from_utf16 - convert a UTF-16 sequence
+ into a unicode character
+-------------------------------------------------*/
+
+int uchar_from_utf16(unicode_char *uchar, const utf16_char *utf16char, size_t count)
+{
+ int rc = -1;
+
+ /* validate parameters */
+ if (utf16char == NULL || count == 0)
+ return 0;
+
+ /* handle the two-byte case */
+ if (utf16char[0] >= 0xd800 && utf16char[0] <= 0xdbff)
+ {
+ if (count > 1 && utf16char[1] >= 0xdc00 && utf16char[1] <= 0xdfff)
+ {
+ *uchar = 0x10000 + ((utf16char[0] & 0x3ff) * 0x400) + (utf16char[1] & 0x3ff);
+ rc = 2;
+ }
+ }
+
+ /* handle the one-byte case */
+ else if (utf16char[0] < 0xdc00 || utf16char[0] > 0xdfff)
+ {
+ *uchar = utf16char[0];
+ rc = 1;
+ }
+
+ return rc;
+}
+
+
+/*-------------------------------------------------
+ uchar_from_utf16f - convert a UTF-16 sequence
+ into a unicode character from a flipped
+ byte order
+-------------------------------------------------*/
+
+int uchar_from_utf16f(unicode_char *uchar, const utf16_char *utf16char, size_t count)
+{
+ utf16_char buf[2] = {0};
+ if (count > 0)
+ buf[0] = FLIPENDIAN_INT16(utf16char[0]);
+ if (count > 1)
+ buf[1] = FLIPENDIAN_INT16(utf16char[1]);
+ return uchar_from_utf16(uchar, buf, count);
+}
+
+
+/*-------------------------------------------------
+ utf8_from_uchar - convert a unicode character
+ into a UTF-8 sequence
+-------------------------------------------------*/
+
+int utf8_from_uchar(char *utf8string, size_t count, unicode_char uchar)
+{
+ int rc = 0;
+
+ /* error on invalid characters */
+ if (!uchar_isvalid(uchar))
+ return -1;
+
+ /* based on the value, output the appropriate number of bytes */
+ if (uchar < 0x80)
+ {
+ /* unicode char 0x00000000 - 0x0000007F */
+ if (count < 1)
+ return -1;
+ utf8string[rc++] = (char) uchar;
+ }
+ else if (uchar < 0x800)
+ {
+ /* unicode char 0x00000080 - 0x000007FF */
+ if (count < 2)
+ return -1;
+ utf8string[rc++] = ((char) (uchar >> 6)) | 0xC0;
+ utf8string[rc++] = ((char) ((uchar >> 0) & 0x3F)) | 0x80;
+ }
+ else if (uchar < 0x10000)
+ {
+ /* unicode char 0x00000800 - 0x0000FFFF */
+ if (count < 3)
+ return -1;
+ utf8string[rc++] = ((char) (uchar >> 12)) | 0xE0;
+ utf8string[rc++] = ((char) ((uchar >> 6) & 0x3F)) | 0x80;
+ utf8string[rc++] = ((char) ((uchar >> 0) & 0x3F)) | 0x80;
+ }
+ else if (uchar < 0x00200000)
+ {
+ /* unicode char 0x00010000 - 0x001FFFFF */
+ if (count < 4)
+ return -1;
+ utf8string[rc++] = ((char) (uchar >> 18)) | 0xF0;
+ utf8string[rc++] = ((char) ((uchar >> 12) & 0x3F)) | 0x80;
+ utf8string[rc++] = ((char) ((uchar >> 6) & 0x3F)) | 0x80;
+ utf8string[rc++] = ((char) ((uchar >> 0) & 0x3F)) | 0x80;
+ }
+ else if (uchar < 0x04000000)
+ {
+ /* unicode char 0x00200000 - 0x03FFFFFF */
+ if (count < 5)
+ return -1;
+ utf8string[rc++] = ((char) (uchar >> 24)) | 0xF8;
+ utf8string[rc++] = ((char) ((uchar >> 18) & 0x3F)) | 0x80;
+ utf8string[rc++] = ((char) ((uchar >> 12) & 0x3F)) | 0x80;
+ utf8string[rc++] = ((char) ((uchar >> 6) & 0x3F)) | 0x80;
+ utf8string[rc++] = ((char) ((uchar >> 0) & 0x3F)) | 0x80;
+ }
+ else if (uchar < 0x80000000)
+ {
+ /* unicode char 0x04000000 - 0x7FFFFFFF */
+ if (count < 6)
+ return -1;
+ utf8string[rc++] = ((char) (uchar >> 30)) | 0xFC;
+ utf8string[rc++] = ((char) ((uchar >> 24) & 0x3F)) | 0x80;
+ utf8string[rc++] = ((char) ((uchar >> 18) & 0x3F)) | 0x80;
+ utf8string[rc++] = ((char) ((uchar >> 12) & 0x3F)) | 0x80;
+ utf8string[rc++] = ((char) ((uchar >> 6) & 0x3F)) | 0x80;
+ utf8string[rc++] = ((char) ((uchar >> 0) & 0x3F)) | 0x80;
+ }
+ else
+ rc = -1;
+
+ return rc;
+}
+
+
+/*-------------------------------------------------
+ utf16_from_uchar - convert a unicode character
+ into a UTF-16 sequence
+-------------------------------------------------*/
+
+int utf16_from_uchar(utf16_char *utf16string, size_t count, unicode_char uchar)
+{
+ int rc;
+
+ /* error on invalid characters */
+ if (!uchar_isvalid(uchar))
+ return -1;
+
+ /* single word case */
+ if (uchar < 0x10000)
+ {
+ if (count < 1)
+ return -1;
+ utf16string[0] = (utf16_char) uchar;
+ rc = 1;
+ }
+
+ /* double word case */
+ else if (uchar < 0x100000)
+ {
+ if (count < 2)
+ return -1;
+ utf16string[0] = ((uchar >> 10) & 0x03ff) | 0xd800;
+ utf16string[1] = ((uchar >> 0) & 0x03ff) | 0xdc00;
+ rc = 2;
+ }
+ else
+ return -1;
+ return rc;
+}
+
+
+/*-------------------------------------------------
+ utf16_from_uchar - convert a unicode character
+ into a UTF-16 sequence with flipped endianness
+-------------------------------------------------*/
+
+int utf16f_from_uchar(utf16_char *utf16string, size_t count, unicode_char uchar)
+{
+ int rc;
+ utf16_char buf[2] = { 0, 0 };
+
+ rc = utf16_from_uchar(buf, count, uchar);
+
+ if (rc >= 1)
+ utf16string[0] = FLIPENDIAN_INT16(buf[0]);
+ if (rc >= 2)
+ utf16string[1] = FLIPENDIAN_INT16(buf[1]);
+ return rc;
+}
+
+
+/*-------------------------------------------------
+ utf8_previous_char - return a pointer to the
+ previous character in a string
+-------------------------------------------------*/
+
+const char *utf8_previous_char(const char *utf8string)
+{
+ while ((*--utf8string & 0xc0) == 0x80)
+ ;
+ return utf8string;
+}
+
+
+/*-------------------------------------------------
+ utf8_is_valid_string - return true if the
+ given string is a properly formed sequence of
+ UTF-8 characters
+-------------------------------------------------*/
+
+int utf8_is_valid_string(const char *utf8string)
+{
+ int remaining_length = strlen(utf8string);
+
+ while (*utf8string != 0)
+ {
+ unicode_char uchar = 0;
+ int charlen;
+
+ /* extract the current character and verify it */
+ charlen = uchar_from_utf8(&uchar, utf8string, remaining_length);
+ if (charlen <= 0 || uchar == 0 || !uchar_isvalid(uchar))
+ return FALSE;
+
+ /* advance */
+ utf8string += charlen;
+ remaining_length -= charlen;
+ }
+
+ return TRUE;
+}
diff --git a/src/lib/util/unicode.h b/src/lib/util/unicode.h
new file mode 100644
index 00000000000..19eb3eab9e0
--- /dev/null
+++ b/src/lib/util/unicode.h
@@ -0,0 +1,92 @@
+/*********************************************************************
+
+ unicode.h
+
+ Unicode related functions
+
+ This code is for converting between UTF-8, UTF-16, and 32-bit
+ Unicode strings. These functions roughly parallel C runtime
+ library functions like mbtowc() and similar functions, but are
+ specific for these Unicode encodings. Specifically, there are
+ functions that convert UTF-8 and UTF-16 char clusters to and from
+ singular 32-bit Unicode chars.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+*********************************************************************/
+
+#pragma once
+
+#ifndef UNICODE_H
+#define UNICODE_H
+
+#include <stdlib.h>
+#include "osdcore.h"
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* these defines specify the maximum size of different types of Unicode
+ * character encodings */
+#define UTF8_CHAR_MAX 6
+#define UTF16_CHAR_MAX 2
+
+/* these are UTF-8 encoded strings for common characters */
+#define UTF8_NBSP "\xc2\xa0" /* non-breaking space */
+#define UTF8_MULTIPLY "\xc3\x97" /* multiplication symbol */
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef UINT16 utf16_char;
+typedef UINT32 unicode_char;
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* tests to see if a unicode char is a valid code point */
+int uchar_isvalid(unicode_char uchar);
+
+/* converting strings to 32-bit Unicode chars */
+int uchar_from_utf8(unicode_char *uchar, const char *utf8char, size_t count);
+int uchar_from_utf16(unicode_char *uchar, const utf16_char *utf16char, size_t count);
+int uchar_from_utf16f(unicode_char *uchar, const utf16_char *utf16char, size_t count);
+
+/* converting 32-bit Unicode chars to strings */
+int utf8_from_uchar(char *utf8string, size_t count, unicode_char uchar);
+int utf16_from_uchar(utf16_char *utf16string, size_t count, unicode_char uchar);
+int utf16f_from_uchar(utf16_char *utf16string, size_t count, unicode_char uchar);
+
+/* misc UTF-8 helpers */
+const char *utf8_previous_char(const char *utf8string);
+int utf8_is_valid_string(const char *utf8string);
+
+
+
+/***************************************************************************
+ MACROS
+***************************************************************************/
+
+#ifdef LSB_FIRST
+#define uchar_from_utf16be uchar_from_utf16f
+#define uchar_from_utf16le uchar_from_utf16
+#define utf16be_from_uchar utf16f_from_uchar
+#define utf16le_from_uchar utf16_from_uchar
+#else
+#define uchar_from_utf16be uchar_from_utf16
+#define uchar_from_utf16le uchar_from_utf16f
+#define utf16be_from_uchar utf16_from_uchar
+#define utf16le_from_uchar utf16f_from_uchar
+#endif
+
+#endif /* UNICODE_H */
diff --git a/src/lib/util/unzip.c b/src/lib/util/unzip.c
new file mode 100644
index 00000000000..9b95321ded7
--- /dev/null
+++ b/src/lib/util/unzip.c
@@ -0,0 +1,616 @@
+/***************************************************************************
+
+ unzip.c
+
+ Functions to manipulate data within ZIP files.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "osdcore.h"
+#include "unzip.h"
+
+#include <ctype.h>
+#include <zlib.h>
+
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+/* number of open files to cache */
+#define ZIP_CACHE_SIZE 8
+
+/* offsets in end of central directory structure */
+#define ZIPESIG 0x00
+#define ZIPEDSK 0x04
+#define ZIPECEN 0x06
+#define ZIPENUM 0x08
+#define ZIPECENN 0x0a
+#define ZIPECSZ 0x0c
+#define ZIPEOFST 0x10
+#define ZIPECOML 0x14
+#define ZIPECOM 0x16
+
+/* offsets in central directory entry structure */
+#define ZIPCENSIG 0x00
+#define ZIPCVER 0x04
+#define ZIPCOS 0x05
+#define ZIPCVXT 0x06
+#define ZIPCEXOS 0x07
+#define ZIPCFLG 0x08
+#define ZIPCMTHD 0x0a
+#define ZIPCTIM 0x0c
+#define ZIPCDAT 0x0e
+#define ZIPCCRC 0x10
+#define ZIPCSIZ 0x14
+#define ZIPCUNC 0x18
+#define ZIPCFNL 0x1c
+#define ZIPCXTL 0x1e
+#define ZIPCCML 0x20
+#define ZIPDSK 0x22
+#define ZIPINT 0x24
+#define ZIPEXT 0x26
+#define ZIPOFST 0x2a
+#define ZIPCFN 0x2e
+
+/* offsets in local file header structure */
+#define ZIPLOCSIG 0x00
+#define ZIPVER 0x04
+#define ZIPGENFLG 0x06
+#define ZIPMTHD 0x08
+#define ZIPTIME 0x0a
+#define ZIPDATE 0x0c
+#define ZIPCRC 0x0e
+#define ZIPSIZE 0x12
+#define ZIPUNCMP 0x16
+#define ZIPFNLN 0x1a
+#define ZIPXTRALN 0x1c
+#define ZIPNAME 0x1e
+
+
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE UINT16 read_word(UINT8 *buf)
+{
+ return (buf[1] << 8) | buf[0];
+}
+
+INLINE UINT32 read_dword(UINT8 *buf)
+{
+ return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+}
+
+
+
+/***************************************************************************
+ GLOBAL VARIABLES
+***************************************************************************/
+
+static zip_file *zip_cache[ZIP_CACHE_SIZE];
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+/* cache management */
+static void free_zip_file(zip_file *zip);
+
+/* ZIP file parsing */
+static zip_error read_ecd(zip_file *zip);
+static zip_error get_compressed_data_offset(zip_file *zip, UINT64 *offset);
+
+/* decompression interfaces */
+static zip_error decompress_data_type_0(zip_file *zip, UINT64 offset, void *buffer, UINT32 length);
+static zip_error decompress_data_type_8(zip_file *zip, UINT64 offset, void *buffer, UINT32 length);
+
+
+
+/***************************************************************************
+ ZIP FILE ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+ zip_file_open - opens a ZIP file for reading
+-------------------------------------------------*/
+
+zip_error zip_file_open(const char *filename, zip_file **zip)
+{
+ zip_error ziperr = ZIPERR_NONE;
+ file_error filerr;
+ UINT32 read_length;
+ zip_file *newzip;
+ char *string;
+ int cachenum;
+
+ /* ensure we start with a NULL result */
+ *zip = NULL;
+
+ /* see if we are in the cache, and reopen if so */
+ for (cachenum = 0; cachenum < ARRAY_LENGTH(zip_cache); cachenum++)
+ {
+ zip_file *cached = zip_cache[cachenum];
+
+ /* if we have a valid entry and it matches our filename, use it and remove from the cache */
+ if (cached != NULL && cached->filename != NULL && strcmp(filename, cached->filename) == 0)
+ {
+ *zip = cached;
+ zip_cache[cachenum] = NULL;
+ return ZIPERR_NONE;
+ }
+ }
+
+ /* allocate memory for the zip_file structure */
+ newzip = malloc(sizeof(*newzip));
+ if (newzip == NULL)
+ return ZIPERR_OUT_OF_MEMORY;
+ memset(newzip, 0, sizeof(*newzip));
+
+ /* open the file */
+ filerr = osd_open(filename, OPEN_FLAG_READ, &newzip->file, &newzip->length);
+ if (filerr != FILERR_NONE)
+ {
+ ziperr = ZIPERR_FILE_ERROR;
+ goto error;
+ }
+
+ /* read ecd data */
+ ziperr = read_ecd(newzip);
+ if (ziperr != ZIPERR_NONE)
+ goto error;
+
+ /* verify that we can work with this zipfile (no disk spanning allowed) */
+ if (newzip->ecd.disk_number != newzip->ecd.cd_start_disk_number || newzip->ecd.cd_disk_entries != newzip->ecd.cd_total_entries)
+ {
+ ziperr = ZIPERR_UNSUPPORTED;
+ goto error;
+ }
+
+ /* allocate memory for the central directory */
+ newzip->cd = malloc(newzip->ecd.cd_size + 1);
+ if (newzip->cd == NULL)
+ {
+ ziperr = ZIPERR_OUT_OF_MEMORY;
+ goto error;
+ }
+
+ /* read the central directory */
+ filerr = osd_read(newzip->file, newzip->cd, newzip->ecd.cd_start_disk_offset, newzip->ecd.cd_size, &read_length);
+ if (filerr != FILERR_NONE || read_length != newzip->ecd.cd_size)
+ {
+ ziperr = (filerr == FILERR_NONE) ? ZIPERR_FILE_TRUNCATED : ZIPERR_FILE_ERROR;
+ goto error;
+ }
+
+ /* make a copy of the filename for caching purposes */
+ string = malloc(strlen(filename) + 1);
+ if (string == NULL)
+ {
+ ziperr = ZIPERR_OUT_OF_MEMORY;
+ goto error;
+ }
+ strcpy(string, filename);
+ newzip->filename = string;
+ *zip = newzip;
+ return ZIPERR_NONE;
+
+error:
+ free_zip_file(newzip);
+ return ziperr;
+}
+
+
+/*-------------------------------------------------
+ zip_file_close - close a ZIP file and add it
+ to the cache
+-------------------------------------------------*/
+
+void zip_file_close(zip_file *zip)
+{
+ int cachenum;
+
+ /* close the open files */
+ if (zip->file != NULL)
+ osd_close(zip->file);
+ zip->file = NULL;
+
+ /* find the first NULL entry in the cache */
+ for (cachenum = 0; cachenum < ARRAY_LENGTH(zip_cache); cachenum++)
+ if (zip_cache[cachenum] == NULL)
+ break;
+
+ /* if no room left in the cache, free the bottommost entry */
+ if (cachenum == ARRAY_LENGTH(zip_cache))
+ free_zip_file(zip_cache[--cachenum]);
+
+ /* move everyone else down and place us at the top */
+ if (cachenum != 0)
+ memmove(&zip_cache[1], &zip_cache[0], cachenum * sizeof(zip_cache[0]));
+ zip_cache[0] = zip;
+}
+
+
+/*-------------------------------------------------
+ zip_file_cache_clear - clear the ZIP file
+ cache and free all memory
+-------------------------------------------------*/
+
+void zip_file_cache_clear(void)
+{
+ int cachenum;
+
+ /* clear call cache entries */
+ for (cachenum = 0; cachenum < ARRAY_LENGTH(zip_cache); cachenum++)
+ if (zip_cache[cachenum] != NULL)
+ {
+ free_zip_file(zip_cache[cachenum]);
+ zip_cache[cachenum] = NULL;
+ }
+}
+
+
+
+/***************************************************************************
+ CONTAINED FILE ACCESS
+***************************************************************************/
+
+/*-------------------------------------------------
+ zip_file_first_entry - return the first entry
+ in the ZIP
+-------------------------------------------------*/
+
+const zip_file_header *zip_file_first_file(zip_file *zip)
+{
+ /* reset the position and go from there */
+ zip->cd_pos = 0;
+ return zip_file_next_file(zip);
+}
+
+
+/*-------------------------------------------------
+ zip_file_next_entry - return the next entry
+ in the ZIP
+-------------------------------------------------*/
+
+const zip_file_header *zip_file_next_file(zip_file *zip)
+{
+ /* fix up any modified data */
+ if (zip->header.raw != NULL)
+ {
+ zip->header.raw[ZIPCFN + zip->header.filename_length] = zip->header.saved;
+ zip->header.raw = NULL;
+ }
+
+ /* if we're at or past the end, we're done */
+ if (zip->cd_pos >= zip->ecd.cd_size)
+ return NULL;
+
+ /* extract file header info */
+ zip->header.raw = zip->cd + zip->cd_pos;
+ zip->header.rawlength = ZIPCFN;
+ zip->header.signature = read_dword(zip->header.raw + ZIPCENSIG);
+ zip->header.version_created = read_word (zip->header.raw + ZIPCVER);
+ zip->header.version_needed = read_word (zip->header.raw + ZIPCVXT);
+ zip->header.bit_flag = read_word (zip->header.raw + ZIPCFLG);
+ zip->header.compression = read_word (zip->header.raw + ZIPCMTHD);
+ zip->header.file_time = read_word (zip->header.raw + ZIPCTIM);
+ zip->header.file_date = read_word (zip->header.raw + ZIPCDAT);
+ zip->header.crc = read_dword(zip->header.raw + ZIPCCRC);
+ zip->header.compressed_length = read_dword(zip->header.raw + ZIPCSIZ);
+ zip->header.uncompressed_length = read_dword(zip->header.raw + ZIPCUNC);
+ zip->header.filename_length = read_word (zip->header.raw + ZIPCFNL);
+ zip->header.extra_field_length = read_word (zip->header.raw + ZIPCXTL);
+ zip->header.file_comment_length = read_word (zip->header.raw + ZIPCCML);
+ zip->header.start_disk_number = read_word (zip->header.raw + ZIPDSK);
+ zip->header.internal_attributes = read_word (zip->header.raw + ZIPINT);
+ zip->header.external_attributes = read_dword(zip->header.raw + ZIPEXT);
+ zip->header.local_header_offset = read_dword(zip->header.raw + ZIPOFST);
+ zip->header.filename = (char *)zip->header.raw + ZIPCFN;
+
+ /* make sure we have enough data */
+ zip->header.rawlength += zip->header.filename_length;
+ zip->header.rawlength += zip->header.extra_field_length;
+ zip->header.rawlength += zip->header.file_comment_length;
+ if (zip->cd_pos + zip->header.rawlength > zip->ecd.cd_size)
+ return NULL;
+
+ /* NULL terminate the filename */
+ zip->header.saved = zip->header.raw[ZIPCFN + zip->header.filename_length];
+ zip->header.raw[ZIPCFN + zip->header.filename_length] = 0;
+
+ /* advance the position */
+ zip->cd_pos += zip->header.rawlength;
+ return &zip->header;
+}
+
+
+/*-------------------------------------------------
+ zip_file_decompress - decompress a file
+ from a ZIP into the target buffer
+-------------------------------------------------*/
+
+zip_error zip_file_decompress(zip_file *zip, void *buffer, UINT32 length)
+{
+ zip_error ziperr;
+ UINT64 offset;
+
+ /* if we don't have enough buffer, error */
+ if (length < zip->header.uncompressed_length)
+ return ZIPERR_BUFFER_TOO_SMALL;
+
+ /* make sure the info in the header aligns with what we know */
+ if (zip->header.start_disk_number != zip->ecd.disk_number)
+ return ZIPERR_UNSUPPORTED;
+
+ /* get the compressed data offset */
+ ziperr = get_compressed_data_offset(zip, &offset);
+ if (ziperr != ZIPERR_NONE)
+ return ziperr;
+
+ /* handle compression types */
+ switch (zip->header.compression)
+ {
+ case 0:
+ ziperr = decompress_data_type_0(zip, offset, buffer, length);
+ break;
+
+ case 8:
+ ziperr = decompress_data_type_8(zip, offset, buffer, length);
+ break;
+
+ default:
+ ziperr = ZIPERR_UNSUPPORTED;
+ break;
+ }
+ return ziperr;
+}
+
+
+
+/***************************************************************************
+ CACHE MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ free_zip_file - free all the data for a
+ zip_file
+-------------------------------------------------*/
+
+static void free_zip_file(zip_file *zip)
+{
+ if (zip != NULL)
+ {
+ if (zip->file != NULL)
+ osd_close(zip->file);
+ if (zip->filename != NULL)
+ free((void *)zip->filename);
+ if (zip->ecd.raw != NULL)
+ free(zip->ecd.raw);
+ if (zip->cd != NULL)
+ free(zip->cd);
+ free(zip);
+ }
+}
+
+
+
+/***************************************************************************
+ ZIP FILE PARSING
+***************************************************************************/
+
+/*-------------------------------------------------
+ read_ecd - read the ECD data
+-------------------------------------------------*/
+
+static zip_error read_ecd(zip_file *zip)
+{
+ UINT32 buflen = 1024;
+ UINT8 *buffer;
+
+ /* we may need multiple tries */
+ while (buflen < 65536)
+ {
+ file_error error;
+ UINT32 read_length;
+ INT32 offset;
+
+ /* max out the buffer length at the size of the file */
+ if (buflen > zip->length)
+ buflen = zip->length;
+
+ /* allocate buffer */
+ buffer = malloc(buflen + 1);
+ if (buffer == NULL)
+ return ZIPERR_OUT_OF_MEMORY;
+
+ /* read in one buffers' worth of data */
+ error = osd_read(zip->file, buffer, zip->length - buflen, buflen, &read_length);
+ if (error != FILERR_NONE || read_length != buflen)
+ {
+ free(buffer);
+ return ZIPERR_FILE_ERROR;
+ }
+
+ /* find the ECD signature */
+ for (offset = buflen - 22; offset >= 0; offset--)
+ if (buffer[offset + 0] == 'P' && buffer[offset + 1] == 'K' && buffer[offset + 2] == 0x05 && buffer[offset + 3] == 0x06)
+ break;
+
+ /* if we found it, fill out the data */
+ if (offset >= 0)
+ {
+ /* reuse the buffer as our ECD buffer */
+ zip->ecd.raw = buffer;
+ zip->ecd.rawlength = buflen - offset;
+
+ /* append a NULL terminator to the comment */
+ memmove(&buffer[0], &buffer[offset], zip->ecd.rawlength);
+ zip->ecd.raw[zip->ecd.rawlength] = 0;
+
+ /* extract ecd info */
+ zip->ecd.signature = read_dword(zip->ecd.raw + ZIPESIG);
+ zip->ecd.disk_number = read_word (zip->ecd.raw + ZIPEDSK);
+ zip->ecd.cd_start_disk_number = read_word (zip->ecd.raw + ZIPECEN);
+ zip->ecd.cd_disk_entries = read_word (zip->ecd.raw + ZIPENUM);
+ zip->ecd.cd_total_entries = read_word (zip->ecd.raw + ZIPECENN);
+ zip->ecd.cd_size = read_dword(zip->ecd.raw + ZIPECSZ);
+ zip->ecd.cd_start_disk_offset = read_dword(zip->ecd.raw + ZIPEOFST);
+ zip->ecd.comment_length = read_word (zip->ecd.raw + ZIPECOML);
+ zip->ecd.comment = (const char *)(zip->ecd.raw + ZIPECOM);
+ return ZIPERR_NONE;
+ }
+
+ /* didn't find it; free this buffer and expand our search */
+ free(buffer);
+ if (buflen < zip->length)
+ buflen *= 2;
+ else
+ return ZIPERR_BAD_SIGNATURE;
+ }
+ return ZIPERR_OUT_OF_MEMORY;
+}
+
+
+/*-------------------------------------------------
+ get_compressed_data_offset - return the
+ offset of the compressed data
+-------------------------------------------------*/
+
+static zip_error get_compressed_data_offset(zip_file *zip, UINT64 *offset)
+{
+ file_error error;
+ UINT32 read_length;
+
+ /* make sure the file handle is open */
+ if (zip->file == NULL)
+ {
+ int filerr = osd_open(zip->filename, OPEN_FLAG_READ, &zip->file, &zip->length);
+ if (filerr != FILERR_NONE)
+ return ZIPERR_FILE_ERROR;
+ }
+
+ /* now go read the fixed-sized part of the local file header */
+ error = osd_read(zip->file, zip->buffer, zip->header.local_header_offset, ZIPNAME, &read_length);
+ if (error != FILERR_NONE || read_length != ZIPNAME)
+ return (error == FILERR_NONE) ? ZIPERR_FILE_TRUNCATED : ZIPERR_FILE_ERROR;
+
+ /* compute the final offset */
+ *offset = zip->header.local_header_offset + ZIPNAME;
+ *offset += read_word(zip->buffer + ZIPFNLN);
+ *offset += read_word(zip->buffer + ZIPXTRALN);
+
+ return ZIPERR_NONE;
+}
+
+
+
+/***************************************************************************
+ DECOMPRESSION INTERFACES
+***************************************************************************/
+
+/*-------------------------------------------------
+ decompress_data_type_0 - "decompress"
+ type 0 data (which is uncompressed)
+-------------------------------------------------*/
+
+static zip_error decompress_data_type_0(zip_file *zip, UINT64 offset, void *buffer, UINT32 length)
+{
+ file_error filerr;
+ UINT32 read_length;
+
+ /* the data is uncompressed; just read it */
+ filerr = osd_read(zip->file, buffer, offset, zip->header.compressed_length, &read_length);
+ if (filerr != FILERR_NONE)
+ return ZIPERR_FILE_ERROR;
+ else if (read_length != zip->header.compressed_length)
+ return ZIPERR_FILE_TRUNCATED;
+ else
+ return ZIPERR_NONE;
+}
+
+
+/*-------------------------------------------------
+ decompress_data_type_8 - decompress
+ type 8 data (which is deflated)
+-------------------------------------------------*/
+
+static zip_error decompress_data_type_8(zip_file *zip, UINT64 offset, void *buffer, UINT32 length)
+{
+ UINT32 input_remaining = zip->header.compressed_length;
+ UINT32 read_length;
+ z_stream stream;
+ int filerr;
+ int zerr;
+
+ /* make sure we don't need a newer mechanism */
+ if (zip->header.version_needed > 0x14)
+ return ZIPERR_UNSUPPORTED;
+
+ /* reset the stream */
+ memset(&stream, 0, sizeof(stream));
+ stream.next_out = buffer;
+ stream.avail_out = length;
+
+ /* initialize the decompressor */
+ zerr = inflateInit2(&stream, -MAX_WBITS);
+ if (zerr != Z_OK)
+ return ZIPERR_DECOMPRESS_ERROR;
+
+ /* loop until we're done */
+ while (1)
+ {
+ /* read in the next chunk of data */
+ filerr = osd_read(zip->file, zip->buffer, offset, MIN(input_remaining, sizeof(zip->buffer)), &read_length);
+ if (filerr != FILERR_NONE)
+ {
+ inflateEnd(&stream);
+ return ZIPERR_FILE_ERROR;
+ }
+ offset += read_length;
+
+ /* if we read nothing, but still have data left, the file is truncated */
+ if (read_length == 0 && input_remaining > 0)
+ {
+ inflateEnd(&stream);
+ return ZIPERR_FILE_TRUNCATED;
+ }
+
+ /* fill out the input data */
+ stream.next_in = zip->buffer;
+ stream.avail_in = read_length;
+ input_remaining -= read_length;
+
+ /* add a dummy byte at end of compressed data */
+ if (input_remaining == 0)
+ stream.avail_in++;
+
+ /* now inflate */
+ zerr = inflate(&stream, Z_NO_FLUSH);
+ if (zerr == Z_STREAM_END)
+ break;
+ if (zerr != Z_OK)
+ {
+ inflateEnd(&stream);
+ return ZIPERR_DECOMPRESS_ERROR;
+ }
+ }
+
+ /* finish decompression */
+ zerr = inflateEnd(&stream);
+ if (zerr != Z_OK)
+ return ZIPERR_DECOMPRESS_ERROR;
+
+ /* if anything looks funny, report an error */
+ if (stream.avail_out > 0 || input_remaining > 0)
+ return ZIPERR_DECOMPRESS_ERROR;
+
+ return ZIPERR_NONE;
+}
diff --git a/src/lib/util/unzip.h b/src/lib/util/unzip.h
new file mode 100644
index 00000000000..0cc9842994d
--- /dev/null
+++ b/src/lib/util/unzip.h
@@ -0,0 +1,143 @@
+/***************************************************************************
+
+ unzip.h
+
+ ZIP file management.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __UNZIP_H__
+#define __UNZIP_H__
+
+#include "osdcore.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define ZIP_DECOMPRESS_BUFSIZE 16384
+
+/* Error types */
+enum _zip_error
+{
+ ZIPERR_NONE = 0,
+ ZIPERR_OUT_OF_MEMORY,
+ ZIPERR_FILE_ERROR,
+ ZIPERR_BAD_SIGNATURE,
+ ZIPERR_DECOMPRESS_ERROR,
+ ZIPERR_FILE_TRUNCATED,
+ ZIPERR_FILE_CORRUPT,
+ ZIPERR_UNSUPPORTED,
+ ZIPERR_BUFFER_TOO_SMALL
+};
+typedef enum _zip_error zip_error;
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* contains extracted file header information */
+typedef struct _zip_file_header zip_file_header;
+struct _zip_file_header
+{
+ UINT32 signature; /* central file header signature */
+ UINT16 version_created; /* version made by */
+ UINT16 version_needed; /* version needed to extract */
+ UINT16 bit_flag; /* general purpose bit flag */
+ UINT16 compression; /* compression method */
+ UINT16 file_time; /* last mod file time */
+ UINT16 file_date; /* last mod file date */
+ UINT32 crc; /* crc-32 */
+ UINT32 compressed_length; /* compressed size */
+ UINT32 uncompressed_length; /* uncompressed size */
+ UINT16 filename_length; /* filename length */
+ UINT16 extra_field_length; /* extra field length */
+ UINT16 file_comment_length; /* file comment length */
+ UINT16 start_disk_number; /* disk number start */
+ UINT16 internal_attributes; /* internal file attributes */
+ UINT32 external_attributes; /* external file attributes */
+ UINT32 local_header_offset; /* relative offset of local header */
+ const char * filename; /* filename */
+
+ UINT8 * raw; /* pointer to the raw data */
+ UINT32 rawlength; /* length of the raw data */
+ UINT8 saved; /* saved byte from after filename */
+};
+
+
+/* contains extracted end of central directory information */
+typedef struct _zip_ecd zip_ecd;
+struct _zip_ecd
+{
+ UINT32 signature; /* end of central dir signature */
+ UINT16 disk_number; /* number of this disk */
+ UINT16 cd_start_disk_number; /* number of the disk with the start of the central directory */
+ UINT16 cd_disk_entries; /* total number of entries in the central directory on this disk */
+ UINT16 cd_total_entries; /* total number of entries in the central directory */
+ UINT32 cd_size; /* size of the central directory */
+ UINT32 cd_start_disk_offset; /* offset of start of central directory with respect to the starting disk number */
+ UINT16 comment_length; /* .ZIP file comment length */
+ const char * comment; /* .ZIP file comment */
+
+ UINT8 * raw; /* pointer to the raw data */
+ UINT32 rawlength; /* length of the raw data */
+};
+
+
+/* describes an open ZIP file */
+typedef struct _zip_file zip_file;
+struct _zip_file
+{
+ const char * filename; /* copy of ZIP filename (for caching) */
+ osd_file * file; /* OSD file handle */
+ UINT64 length; /* length of zip file */
+
+ zip_ecd ecd; /* end of central directory */
+
+ UINT8 * cd; /* central directory raw data */
+ UINT32 cd_pos; /* position in central directory */
+ zip_file_header header; /* current file header */
+
+ UINT8 buffer[ZIP_DECOMPRESS_BUFSIZE]; /* buffer for decompression */
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- ZIP file access ----- */
+
+/* open a ZIP file and parse its central directory */
+zip_error zip_file_open(const char *filename, zip_file **zip);
+
+/* close a ZIP file (may actually be left open due to caching) */
+void zip_file_close(zip_file *zip);
+
+/* clear out all open ZIP files from the cache */
+void zip_file_cache_clear(void);
+
+
+/* ----- contained file access ----- */
+
+/* find the first file in the ZIP */
+const zip_file_header *zip_file_first_file(zip_file *zip);
+
+/* find the next file in the ZIP */
+const zip_file_header *zip_file_next_file(zip_file *zip);
+
+/* decompress the most recently found file in the ZIP */
+zip_error zip_file_decompress(zip_file *zip, void *buffer, UINT32 length);
+
+
+#endif /* __UNZIP_H__ */
diff --git a/src/lib/util/xmlfile.c b/src/lib/util/xmlfile.c
new file mode 100644
index 00000000000..a220cc05e4a
--- /dev/null
+++ b/src/lib/util/xmlfile.c
@@ -0,0 +1,857 @@
+/***************************************************************************
+
+ xmlfile.c
+
+ XML file parsing code.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#include "xmlfile.h"
+#include <ctype.h>
+#include <expat.h>
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+#define TEMP_BUFFER_SIZE 4096
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _xml_parse_info xml_parse_info;
+struct _xml_parse_info
+{
+ XML_Parser parser;
+ xml_data_node * rootnode;
+ xml_data_node * curnode;
+ UINT32 flags;
+};
+
+
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+/* expat interfaces */
+static int expat_setup_parser(xml_parse_info *parse_info, xml_parse_options *opts);
+static void expat_element_start(void *data, const XML_Char *name, const XML_Char **attributes);
+static void expat_data(void *data, const XML_Char *s, int len);
+static void expat_element_end(void *data, const XML_Char *name);
+
+/* node/attributes additions */
+static xml_data_node *add_child(xml_data_node *parent, const char *name, const char *value);
+static xml_attribute_node *add_attribute(xml_data_node *node, const char *name, const char *value);
+
+/* recursive tree operations */
+static void write_node_recursive(xml_data_node *node, int indent, core_file *file);
+static void free_node_recursive(xml_data_node *node);
+
+
+
+/***************************************************************************
+ CORE IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ copystring - make an allocated copy of a
+ string
+-------------------------------------------------*/
+
+static const char *copystring(const char *input)
+{
+ char *newstr;
+
+ /* NULL just passes through */
+ if (input == NULL)
+ return NULL;
+
+ /* make a lower-case copy if the allocation worked */
+ newstr = malloc(strlen(input) + 1);
+ if (newstr != NULL)
+ strcpy(newstr, input);
+
+ return newstr;
+}
+
+
+/*-------------------------------------------------
+ copystring_lower - make an allocated copy of
+ a string and convert it to lowercase along
+ the way
+-------------------------------------------------*/
+
+static const char *copystring_lower(const char *input)
+{
+ char *newstr;
+ int i;
+
+ /* NULL just passes through */
+ if (input == NULL)
+ return NULL;
+
+ /* make a lower-case copy if the allocation worked */
+ newstr = malloc(strlen(input) + 1);
+ if (newstr != NULL)
+ {
+ for (i = 0; input[i] != 0; i++)
+ newstr[i] = tolower(input[i]);
+ newstr[i] = 0;
+ }
+
+ return newstr;
+}
+
+
+
+/***************************************************************************
+ XML FILE OBJECTS
+***************************************************************************/
+
+/*-------------------------------------------------
+ xml_file_create - create a new xml file
+ object
+-------------------------------------------------*/
+
+xml_data_node *xml_file_create(void)
+{
+ xml_data_node *rootnode;
+
+ /* create a root node */
+ rootnode = malloc(sizeof(*rootnode));
+ if (rootnode == NULL)
+ return NULL;
+ memset(rootnode, 0, sizeof(*rootnode));
+ return rootnode;
+}
+
+
+/*-------------------------------------------------
+ xml_file_read - parse an XML file into its
+ nodes
+-------------------------------------------------*/
+
+xml_data_node *xml_file_read(core_file *file, xml_parse_options *opts)
+{
+ xml_parse_info parse_info;
+ int done;
+
+ /* set up the parser */
+ if (!expat_setup_parser(&parse_info, opts))
+ return NULL;
+
+ /* loop through the file and parse it */
+ do
+ {
+ char tempbuf[TEMP_BUFFER_SIZE];
+
+ /* read as much as we can */
+ int bytes = core_fread(file, tempbuf, sizeof(tempbuf));
+ done = core_feof(file);
+
+ /* parse the data */
+ if (XML_Parse(parse_info.parser, tempbuf, bytes, done) == XML_STATUS_ERROR)
+ {
+ if (opts != NULL && opts->error != NULL)
+ {
+ opts->error->error_message = XML_ErrorString(XML_GetErrorCode(parse_info.parser));
+ opts->error->error_line = XML_GetCurrentLineNumber(parse_info.parser);
+ opts->error->error_column = XML_GetCurrentColumnNumber(parse_info.parser);
+ }
+
+ xml_file_free(parse_info.rootnode);
+ XML_ParserFree(parse_info.parser);
+ return NULL;
+ }
+
+ } while (!done);
+
+ /* free the parser */
+ XML_ParserFree(parse_info.parser);
+
+ /* return the root node */
+ return parse_info.rootnode;
+}
+
+
+/*-------------------------------------------------
+ xml_string_read - parse an XML string into its
+ nodes
+-------------------------------------------------*/
+
+xml_data_node *xml_string_read(const char *string, xml_parse_options *opts)
+{
+ xml_parse_info parse_info;
+ int length = (int)strlen(string);
+
+ /* set up the parser */
+ if (!expat_setup_parser(&parse_info, opts))
+ return NULL;
+
+ /* parse the data */
+ if (XML_Parse(parse_info.parser, string, length, TRUE) == XML_STATUS_ERROR)
+ {
+ if (opts != NULL && opts->error != NULL)
+ {
+ opts->error->error_message = XML_ErrorString(XML_GetErrorCode(parse_info.parser));
+ opts->error->error_line = XML_GetCurrentLineNumber(parse_info.parser);
+ opts->error->error_column = XML_GetCurrentColumnNumber(parse_info.parser);
+ }
+
+ xml_file_free(parse_info.rootnode);
+ XML_ParserFree(parse_info.parser);
+ return NULL;
+ }
+
+ /* free the parser */
+ XML_ParserFree(parse_info.parser);
+
+ /* return the root node */
+ return parse_info.rootnode;
+}
+
+
+/*-------------------------------------------------
+ xml_file_write - write an XML tree to a file
+-------------------------------------------------*/
+
+void xml_file_write(xml_data_node *node, core_file *file)
+{
+ /* ensure this is a root node */
+ if (node->name != NULL)
+ return;
+
+ /* output a simple header */
+ core_fprintf(file, "<?xml version=\"1.0\"?>\n");
+ core_fprintf(file, "<!-- This file is autogenerated; comments and unknown tags will be stripped -->\n");
+
+ /* loop over children of the root and output */
+ for (node = node->child; node; node = node->next)
+ write_node_recursive(node, 0, file);
+}
+
+
+/*-------------------------------------------------
+ xml_file_free - free an XML file object
+-------------------------------------------------*/
+
+void xml_file_free(xml_data_node *node)
+{
+ /* ensure this is a root node */
+ if (node->name != NULL)
+ return;
+
+ free_node_recursive(node);
+}
+
+
+
+/***************************************************************************
+ XML NODE MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ xml_count_children - count the number of
+ child nodes
+-------------------------------------------------*/
+
+int xml_count_children(xml_data_node *node)
+{
+ int count = 0;
+
+ /* loop over children and count */
+ for (node = node->child; node; node = node->next)
+ count++;
+ return count;
+}
+
+
+/*-------------------------------------------------
+ xml_get_sibling - find the next sibling of
+ the specified node with the specified tag
+-------------------------------------------------*/
+
+xml_data_node *xml_get_sibling(xml_data_node *node, const char *name)
+{
+ /* loop over siblings and find a matching name */
+ for ( ; node; node = node->next)
+ if (strcmp(node->name, name) == 0)
+ return node;
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ xml_find_matching_sibling - find the next
+ sibling of the specified node with the
+ specified tag or attribute/value pair
+-------------------------------------------------*/
+
+xml_data_node *xml_find_matching_sibling(xml_data_node *node, const char *name, const char *attribute, const char *matchval)
+{
+ /* loop over siblings and find a matching attribute */
+ for ( ; node; node = node->next)
+ {
+ /* can pass NULL as a wildcard for the node name */
+ if (name == NULL || strcmp(name, node->name) == 0)
+ {
+ /* find a matching attribute */
+ xml_attribute_node *attr = xml_get_attribute(node, attribute);
+ if (attr != NULL && strcmp(attr->value, matchval) == 0)
+ return node;
+ }
+ }
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ xml_add_child - add a new child node to the
+ given node
+-------------------------------------------------*/
+
+xml_data_node *xml_add_child(xml_data_node *node, const char *name, const char *value)
+{
+ /* just a standard add child */
+ return add_child(node, name, value);
+}
+
+
+/*-------------------------------------------------
+ xml_get_or_add_child - find a child node of
+ the specified type; if not found, add one
+-------------------------------------------------*/
+
+xml_data_node *xml_get_or_add_child(xml_data_node *node, const char *name, const char *value)
+{
+ xml_data_node *child;
+
+ /* find the child first */
+ child = xml_get_sibling(node->child, name);
+ if (child != NULL)
+ return child;
+
+ /* if not found, do a standard add child */
+ return add_child(node, name, value);
+}
+
+
+/*-------------------------------------------------
+ xml_delete_node - delete a node and its
+ children
+-------------------------------------------------*/
+
+void xml_delete_node(xml_data_node *node)
+{
+ xml_data_node **pnode;
+
+ /* first unhook us from the list of children of our parent */
+ for (pnode = &node->parent->child; *pnode; pnode = &(*pnode)->next)
+ if (*pnode == node)
+ {
+ *pnode = node->next;
+ break;
+ }
+
+ /* now free ourselves and our children */
+ free_node_recursive(node);
+}
+
+
+
+/***************************************************************************
+ XML ATTRIBUTE MANAGEMENT
+***************************************************************************/
+
+/*-------------------------------------------------
+ xml_get_attribute - get the value of the
+ specified attribute, or NULL if not found
+-------------------------------------------------*/
+
+xml_attribute_node *xml_get_attribute(xml_data_node *node, const char *attribute)
+{
+ xml_attribute_node *anode;
+
+ /* loop over attributes and find a match */
+ for (anode = node->attribute; anode; anode = anode->next)
+ if (strcmp(anode->name, attribute) == 0)
+ return anode;
+ return NULL;
+}
+
+
+/*-------------------------------------------------
+ xml_get_attribute_string - get the string
+ value of the specified attribute; if not
+ found, return = the provided default
+-------------------------------------------------*/
+
+const char *xml_get_attribute_string(xml_data_node *node, const char *attribute, const char *defvalue)
+{
+ xml_attribute_node *attr = xml_get_attribute(node, attribute);
+ return attr ? attr->value : defvalue;
+}
+
+
+/*-------------------------------------------------
+ xml_get_attribute_int - get the integer
+ value of the specified attribute; if not
+ found, return = the provided default
+-------------------------------------------------*/
+
+int xml_get_attribute_int(xml_data_node *node, const char *attribute, int defvalue)
+{
+ const char *string = xml_get_attribute_string(node, attribute, NULL);
+ int value;
+
+ if (string == NULL || sscanf(string, "%d", &value) != 1)
+ return defvalue;
+ return value;
+}
+
+
+/*-------------------------------------------------
+ xml_get_attribute_float - get the float
+ value of the specified attribute; if not
+ found, return = the provided default
+-------------------------------------------------*/
+
+float xml_get_attribute_float(xml_data_node *node, const char *attribute, float defvalue)
+{
+ const char *string = xml_get_attribute_string(node, attribute, NULL);
+ float value;
+
+ if (string == NULL || sscanf(string, "%f", &value) != 1)
+ return defvalue;
+ return value;
+}
+
+
+/*-------------------------------------------------
+ xml_set_attribute - set a new attribute and
+ string value on the node
+-------------------------------------------------*/
+
+xml_attribute_node *xml_set_attribute(xml_data_node *node, const char *name, const char *value)
+{
+ xml_attribute_node *anode;
+
+ /* first find an existing one to replace */
+ anode = xml_get_attribute(node, name);
+
+ /* if we found it, free the old value and replace it */
+ if (anode != NULL)
+ {
+ if (anode->value != NULL)
+ free((void *)anode->value);
+ anode->value = copystring(value);
+ }
+
+ /* otherwise, create a new node */
+ else
+ anode = add_attribute(node, name, value);
+
+ return anode;
+}
+
+
+/*-------------------------------------------------
+ xml_set_attribute_int - set a new attribute and
+ integer value on the node
+-------------------------------------------------*/
+
+xml_attribute_node *xml_set_attribute_int(xml_data_node *node, const char *name, int value)
+{
+ char buffer[100];
+ sprintf(buffer, "%d", value);
+ return xml_set_attribute(node, name, buffer);
+}
+
+
+/*-------------------------------------------------
+ xml_set_attribute_int - set a new attribute and
+ float value on the node
+-------------------------------------------------*/
+
+xml_attribute_node *xml_set_attribute_float(xml_data_node *node, const char *name, float value)
+{
+ char buffer[100];
+ sprintf(buffer, "%f", value);
+ return xml_set_attribute(node, name, buffer);
+}
+
+
+
+/***************************************************************************
+ MISCELLANEOUS INTERFACES
+***************************************************************************/
+
+/*-------------------------------------------------
+ xml_normalize_string - normalize a string
+ to ensure it doesn't contain embedded tags
+-------------------------------------------------*/
+
+const char *xml_normalize_string(const char *string)
+{
+ static char buffer[1024];
+ char *d = &buffer[0];
+
+ if (string != NULL)
+ {
+ while (*string)
+ {
+ switch (*string)
+ {
+ case '\"' : d += sprintf(d, "&quot;"); break;
+ case '&' : d += sprintf(d, "&amp;"); break;
+ case '<' : d += sprintf(d, "&lt;"); break;
+ case '>' : d += sprintf(d, "&gt;"); break;
+ default:
+ if (*string >= ' ' && *string <= '~')
+ *d++ = *string;
+ else
+ d += sprintf(d, "&#%d;", (unsigned)(unsigned char)*string);
+ }
+ ++string;
+ }
+ }
+ *d++ = 0;
+ return buffer;
+}
+
+
+
+/***************************************************************************
+ EXPAT INTERFACES
+***************************************************************************/
+
+/*-------------------------------------------------
+ expat_setup_parser - set up expat for parsing
+-------------------------------------------------*/
+
+static int expat_setup_parser(xml_parse_info *parse_info, xml_parse_options *opts)
+{
+ /* setup parse_info structure */
+ memset(parse_info, 0, sizeof(*parse_info));
+ if (opts != NULL)
+ {
+ parse_info->flags = opts->flags;
+ if (opts->error != NULL)
+ {
+ opts->error->error_message = NULL;
+ opts->error->error_line = 0;
+ opts->error->error_column = 0;
+ }
+ }
+
+ /* create a root node */
+ parse_info->rootnode = xml_file_create();
+ if (parse_info->rootnode == NULL)
+ return FALSE;
+ parse_info->curnode = parse_info->rootnode;
+
+ /* create the XML parser */
+ parse_info->parser = XML_ParserCreate(NULL);
+ if (parse_info->parser == NULL)
+ {
+ free(parse_info->rootnode);
+ return FALSE;
+ }
+
+ /* configure the parser */
+ XML_SetElementHandler(parse_info->parser, expat_element_start, expat_element_end);
+ XML_SetCharacterDataHandler(parse_info->parser, expat_data);
+ XML_SetUserData(parse_info->parser, parse_info);
+
+ /* optional parser initialization step */
+ if (opts != NULL && opts->init_parser != NULL)
+ (*opts->init_parser)(parse_info->parser);
+ return TRUE;
+}
+
+
+/*-------------------------------------------------
+ expat_element_start - expat callback for a new
+ element
+-------------------------------------------------*/
+
+static void expat_element_start(void *data, const XML_Char *name, const XML_Char **attributes)
+{
+ xml_parse_info *parse_info = (xml_parse_info *) data;
+ xml_data_node **curnode = &parse_info->curnode;
+ xml_data_node *newnode;
+ int attr;
+
+ /* add a new child node to the current node */
+ newnode = add_child(*curnode, name, NULL);
+ if (newnode == NULL)
+ return;
+
+ /* add all the attributes as well */
+ for (attr = 0; attributes[attr]; attr += 2)
+ add_attribute(newnode, attributes[attr+0], attributes[attr+1]);
+
+ /* set us up as the current node */
+ *curnode = newnode;
+}
+
+
+/*-------------------------------------------------
+ expat_data - expat callback for a additional
+ element data
+-------------------------------------------------*/
+
+static void expat_data(void *data, const XML_Char *s, int len)
+{
+ xml_parse_info *parse_info = (xml_parse_info *) data;
+ xml_data_node **curnode = &parse_info->curnode;
+ int oldlen = 0;
+ char *newdata;
+
+ /* if no data, skip */
+ if (len == 0)
+ return;
+
+ /* determine how much data we currently have */
+ if ((*curnode)->value != NULL)
+ oldlen = (int)strlen((*curnode)->value);
+
+ /* realloc */
+ newdata = realloc((void *)(*curnode)->value, oldlen + len + 1);
+ if (newdata == NULL)
+ return;
+
+ /* copy in the new data a NULL-terminate */
+ memcpy(&newdata[oldlen], s, len);
+ newdata[oldlen + len] = 0;
+ (*curnode)->value = newdata;
+}
+
+
+/*-------------------------------------------------
+ expat_element_end - expat callback for the end
+ of an element
+-------------------------------------------------*/
+
+static void expat_element_end(void *data, const XML_Char *name)
+{
+ xml_parse_info *parse_info = (xml_parse_info *) data;
+ xml_data_node **curnode = &parse_info->curnode;
+ char *orig;
+
+ /* strip leading/trailing spaces from the value data */
+ orig = (char *)(*curnode)->value;
+ if (orig != NULL && !(parse_info->flags & XML_PARSE_FLAG_WHITESPACE_SIGNIFICANT))
+ {
+ char *start = orig;
+ char *end = start + strlen(start);
+
+ /* first strip leading spaces */
+ while (*start && isspace(*start))
+ start++;
+
+ /* then strip trailing spaces */
+ while (end > start && isspace(end[-1]))
+ end--;
+
+ /* if nothing left, just free it */
+ if (start == end)
+ {
+ free(orig);
+ (*curnode)->value = NULL;
+ }
+
+ /* otherwise, memmove the data */
+ else
+ {
+ memmove(orig, start, end - start);
+ orig[end - start] = 0;
+ }
+ }
+
+ /* back us up a node */
+ *curnode = (*curnode)->parent;
+}
+
+
+
+/***************************************************************************
+ NODE/ATTRIBUTE ADDITIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ add_child - add a new node to the parent
+-------------------------------------------------*/
+
+static xml_data_node *add_child(xml_data_node *parent, const char *name, const char *value)
+{
+ xml_data_node **pnode;
+ xml_data_node *node;
+
+ /* new element: create a new node */
+ node = malloc(sizeof(*node));
+ if (node == NULL)
+ return NULL;
+
+ /* initialize the members */
+ node->next = NULL;
+ node->parent = parent;
+ node->child = NULL;
+ node->name = copystring_lower(name);
+ if (node->name == NULL)
+ {
+ free(node);
+ return NULL;
+ }
+ node->value = copystring(value);
+ if (node->value == NULL && value != NULL)
+ {
+ free((void *)node->name);
+ free(node);
+ return NULL;
+ }
+ node->attribute = NULL;
+
+ /* add us to the end of the list of siblings */
+ for (pnode = &parent->child; *pnode; pnode = &(*pnode)->next) ;
+ *pnode = node;
+
+ return node;
+}
+
+
+/*-------------------------------------------------
+ add_attribute - add a new attribute to the
+ given node
+-------------------------------------------------*/
+
+static xml_attribute_node *add_attribute(xml_data_node *node, const char *name, const char *value)
+{
+ xml_attribute_node *anode, **panode;
+
+ /* allocate a new attribute node */
+ anode = malloc(sizeof(*anode));
+ if (anode == NULL)
+ return NULL;
+
+ /* fill it in */
+ anode->next = NULL;
+ anode->name = copystring_lower(name);
+ if (anode->name == NULL)
+ {
+ free(anode);
+ return NULL;
+ }
+ anode->value = copystring(value);
+ if (anode->value == NULL)
+ {
+ free((void *)anode->name);
+ free(anode);
+ return NULL;
+ }
+
+ /* add us to the end of the list of attributes */
+ for (panode = &node->attribute; *panode; panode = &(*panode)->next) ;
+ *panode = anode;
+
+ return anode;
+}
+
+
+
+/***************************************************************************
+ RECURSIVE TREE OPERATIONS
+***************************************************************************/
+
+/*-------------------------------------------------
+ write_node_recursive - recursively write
+ an XML node and its children to a file
+-------------------------------------------------*/
+
+static void write_node_recursive(xml_data_node *node, int indent, core_file *file)
+{
+ xml_attribute_node *anode;
+ xml_data_node *child;
+
+ /* output this tag */
+ core_fprintf(file, "%*s<%s", indent, "", node->name);
+
+ /* output any attributes */
+ for (anode = node->attribute; anode; anode = anode->next)
+ core_fprintf(file, " %s=\"%s\"", anode->name, anode->value);
+
+ /* if there are no children and no value, end the tag here */
+ if (node->child == NULL && node->value == NULL)
+ core_fprintf(file, " />\n");
+
+ /* otherwise, close this tag and output more stuff */
+ else
+ {
+ core_fprintf(file, ">\n");
+
+ /* if there is a value, output that here */
+ if (node->value != NULL)
+ core_fprintf(file, "%*s%s\n", indent + 4, "", node->value);
+
+ /* loop over children and output them as well */
+ if (node->child != NULL)
+ {
+ for (child = node->child; child; child = child->next)
+ write_node_recursive(child, indent + 4, file);
+ }
+
+ /* write a closing tag */
+ core_fprintf(file, "%*s</%s>\n", indent, "", node->name);
+ }
+}
+
+
+/*-------------------------------------------------
+ free_node_recursive - recursively free
+ the data allocated to an XML node
+-------------------------------------------------*/
+
+static void free_node_recursive(xml_data_node *node)
+{
+ xml_attribute_node *anode, *nanode;
+ xml_data_node *child, *nchild;
+
+ /* free name/value */
+ if (node->name != NULL)
+ free((void *)node->name);
+ if (node->value != NULL)
+ free((void *)node->value);
+
+ /* free attributes */
+ for (anode = node->attribute; anode; anode = nanode)
+ {
+ /* free name/value */
+ if (anode->name != NULL)
+ free((void *)anode->name);
+ if (anode->value != NULL)
+ free((void *)anode->value);
+
+ /* note the next node and free this node */
+ nanode = anode->next;
+ free(anode);
+ }
+
+ /* free the children */
+ for (child = node->child; child; child = nchild)
+ {
+ /* note the next node and free this node */
+ nchild = child->next;
+ free_node_recursive(child);
+ }
+
+ /* finally free ourself */
+ free(node);
+}
diff --git a/src/lib/util/xmlfile.h b/src/lib/util/xmlfile.h
new file mode 100644
index 00000000000..f68c81fddb2
--- /dev/null
+++ b/src/lib/util/xmlfile.h
@@ -0,0 +1,160 @@
+/***************************************************************************
+
+ xmlfile.h
+
+ XML file parsing code.
+
+ Copyright (c) 1996-2007, Nicola Salmoria and the MAME Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __XMLFILE_H__
+#define __XMLFILE_H__
+
+#include "osdcore.h"
+#include "corefile.h"
+
+
+/***************************************************************************
+ CONSTANTS
+***************************************************************************/
+
+enum
+{
+ XML_PARSE_FLAG_WHITESPACE_SIGNIFICANT = 1
+};
+
+
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+/* forward type declarations */
+struct XML_ParserStruct;
+
+
+/* a node representing an attribute */
+typedef struct _xml_attribute_node xml_attribute_node;
+struct _xml_attribute_node
+{
+ xml_attribute_node * next; /* pointer to next attribute node */
+ const char * name; /* pointer to copy of tag name */
+ const char * value; /* pointer to copy of value string */
+};
+
+
+/* a node representing a data item and its relationships */
+typedef struct _xml_data_node xml_data_node;
+struct _xml_data_node
+{
+ xml_data_node * next; /* pointer to next sibling node */
+ xml_data_node * parent; /* pointer to parent node */
+ xml_data_node * child; /* pointer to first child node */
+ const char * name; /* pointer to copy of tag name */
+ const char * value; /* pointer to copy of value string */
+ xml_attribute_node * attribute; /* pointer to array of attribute nodes */
+};
+
+
+/* extended error information from parsing */
+typedef struct _xml_parse_error xml_parse_error;
+struct _xml_parse_error
+{
+ const char * error_message;
+ int error_line;
+ int error_column;
+};
+
+
+/* parsing options */
+typedef struct _xml_parse_options xml_parse_options;
+struct _xml_parse_options
+{
+ xml_parse_error * error;
+ void (*init_parser)(struct XML_ParserStruct *parser);
+ UINT32 flags;
+};
+
+
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+
+/* ----- XML file objects ----- */
+
+/* create a new empty xml file object */
+xml_data_node *xml_file_create(void);
+
+/* parse an XML file into its nodes */
+xml_data_node *xml_file_read(core_file *file, xml_parse_options *opts);
+
+/* parse an XML string into its nodes */
+xml_data_node *xml_string_read(const char *string, xml_parse_options *opts);
+
+/* write an XML tree to a file */
+void xml_file_write(xml_data_node *node, core_file *file);
+
+/* free an XML file object */
+void xml_file_free(xml_data_node *node);
+
+
+
+/* ----- XML node management ----- */
+
+/* count the number of child nodes */
+int xml_count_children(xml_data_node *node);
+
+/* find the next sibling with the given tag */
+xml_data_node *xml_get_sibling(xml_data_node *node, const char *name);
+
+/* find the next sibling with the given tag and/or attribute/value pair */
+xml_data_node *xml_find_matching_sibling(xml_data_node *node, const char *name, const char *attribute, const char *matchval);
+
+/* add a new child node */
+xml_data_node *xml_add_child(xml_data_node *node, const char *name, const char *value);
+
+/* either return an existing child node or create one if it doesn't exist */
+xml_data_node *xml_get_or_add_child(xml_data_node *node, const char *name, const char *value);
+
+/* delete a node and its children */
+void xml_delete_node(xml_data_node *node);
+
+
+
+/* ----- XML attribute management ----- */
+
+/* find an attribute node with the specified tag */
+xml_attribute_node *xml_get_attribute(xml_data_node *node, const char *attribute);
+
+/* return the string value of an attribute, or the specified default if not present */
+const char *xml_get_attribute_string(xml_data_node *node, const char *attribute, const char *defvalue);
+
+/* return the integer value of an attribute, or the specified default if not present */
+int xml_get_attribute_int(xml_data_node *node, const char *attribute, int defvalue);
+
+/* return the float value of an attribute, or the specified default if not present */
+float xml_get_attribute_float(xml_data_node *node, const char *attribute, float defvalue);
+
+/* set the string value of an attribute */
+xml_attribute_node *xml_set_attribute(xml_data_node *node, const char *name, const char *value);
+
+/* set the integer value of an attribute */
+xml_attribute_node *xml_set_attribute_int(xml_data_node *node, const char *name, int value);
+
+/* set the float value of an attribute */
+xml_attribute_node *xml_set_attribute_float(xml_data_node *node, const char *name, float value);
+
+
+
+/* ----- miscellaneous interfaces ----- */
+
+/* normalize a string into something that can be written to an XML file */
+const char *xml_normalize_string(const char *string);
+
+#endif /* __XMLFILE_H__ */
diff --git a/src/lib/zlib/Makefile b/src/lib/zlib/Makefile
new file mode 100644
index 00000000000..2fd6e45c48d
--- /dev/null
+++ b/src/lib/zlib/Makefile
@@ -0,0 +1,154 @@
+# Makefile for zlib
+# Copyright (C) 1995-2005 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile and test, type:
+# ./configure; make test
+# The call of configure is optional if you don't have special requirements
+# If you wish to build zlib as a shared library, use: ./configure -s
+
+# To use the asm code, type:
+# cp contrib/asm?86/match.S ./match.S
+# make LOC=-DASMV OBJA=match.o
+
+# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
+# make install
+# To install in $HOME instead of /usr/local, use:
+# make install prefix=$HOME
+
+CC=cc
+
+CFLAGS=-O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+LDFLAGS=libz.a
+LDSHARED=$(CC)
+CPP=$(CC) -E
+
+LIBS=libz.a
+SHAREDLIB=libz.so
+SHAREDLIBV=libz.so.1.2.3
+SHAREDLIBM=libz.so.1
+
+AR=ar rc
+RANLIB=ranlib
+TAR=tar
+SHELL=/bin/sh
+EXE=
+
+prefix = /usr/local
+exec_prefix = ${prefix}
+libdir = ${exec_prefix}/lib
+includedir = ${prefix}/include
+mandir = ${prefix}/share/man
+man3dir = ${mandir}/man3
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infback.o inftrees.o inffast.o
+
+OBJA =
+# to use the asm code: make OBJA=match.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example$(EXE) minigzip$(EXE)
+
+check: test
+test: all
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+ echo hello world | ./minigzip | ./minigzip -d || \
+ echo ' *** minigzip test FAILED ***' ; \
+ if ./example; then \
+ echo ' *** zlib test OK ***'; \
+ else \
+ echo ' *** zlib test FAILED ***'; \
+ fi
+
+libz.a: $(OBJS) $(OBJA)
+ $(AR) $@ $(OBJS) $(OBJA)
+ -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+match.o: match.S
+ $(CPP) match.S > _match.s
+ $(CC) -c _match.s
+ mv _match.o match.o
+ rm -f _match.s
+
+$(SHAREDLIBV): $(OBJS)
+ $(LDSHARED) -o $@ $(OBJS)
+ rm -f $(SHAREDLIB) $(SHAREDLIBM)
+ ln -s $@ $(SHAREDLIB)
+ ln -s $@ $(SHAREDLIBM)
+
+example$(EXE): example.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip$(EXE): minigzip.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+install: $(LIBS)
+ -@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi
+ -@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi
+ -@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi
+ -@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi
+ cp zlib.h zconf.h $(includedir)
+ chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h
+ cp $(LIBS) $(libdir)
+ cd $(libdir); chmod 755 $(LIBS)
+ -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1
+ cd $(libdir); if test -f $(SHAREDLIBV); then \
+ rm -f $(SHAREDLIB) $(SHAREDLIBM); \
+ ln -s $(SHAREDLIBV) $(SHAREDLIB); \
+ ln -s $(SHAREDLIBV) $(SHAREDLIBM); \
+ (ldconfig || true) >/dev/null 2>&1; \
+ fi
+ cp zlib.3 $(man3dir)
+ chmod 644 $(man3dir)/zlib.3
+# The ranlib in install is needed on NeXTSTEP which checks file times
+# ldconfig is for Linux
+
+uninstall:
+ cd $(includedir); \
+ cd $(libdir); rm -f libz.a; \
+ if test -f $(SHAREDLIBV); then \
+ rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \
+ fi
+ cd $(man3dir); rm -f zlib.3
+
+mostlyclean: clean
+clean:
+ rm -f *.o *~ example$(EXE) minigzip$(EXE) \
+ libz.* foo.gz so_locations \
+ _match.s maketree contrib/infback9/*.o
+
+maintainer-clean: distclean
+distclean: clean
+ cp -p Makefile.in Makefile
+ cp -p zconf.in.h zconf.h
+ rm -f .DS_Store
+
+tags:
+ etags *.[ch]
+
+depend:
+ makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: crc32.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/src/lib/zlib/Makefile.in b/src/lib/zlib/Makefile.in
new file mode 100644
index 00000000000..2fd6e45c48d
--- /dev/null
+++ b/src/lib/zlib/Makefile.in
@@ -0,0 +1,154 @@
+# Makefile for zlib
+# Copyright (C) 1995-2005 Jean-loup Gailly.
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile and test, type:
+# ./configure; make test
+# The call of configure is optional if you don't have special requirements
+# If you wish to build zlib as a shared library, use: ./configure -s
+
+# To use the asm code, type:
+# cp contrib/asm?86/match.S ./match.S
+# make LOC=-DASMV OBJA=match.o
+
+# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
+# make install
+# To install in $HOME instead of /usr/local, use:
+# make install prefix=$HOME
+
+CC=cc
+
+CFLAGS=-O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+LDFLAGS=libz.a
+LDSHARED=$(CC)
+CPP=$(CC) -E
+
+LIBS=libz.a
+SHAREDLIB=libz.so
+SHAREDLIBV=libz.so.1.2.3
+SHAREDLIBM=libz.so.1
+
+AR=ar rc
+RANLIB=ranlib
+TAR=tar
+SHELL=/bin/sh
+EXE=
+
+prefix = /usr/local
+exec_prefix = ${prefix}
+libdir = ${exec_prefix}/lib
+includedir = ${prefix}/include
+mandir = ${prefix}/share/man
+man3dir = ${mandir}/man3
+
+OBJS = adler32.o compress.o crc32.o gzio.o uncompr.o deflate.o trees.o \
+ zutil.o inflate.o infback.o inftrees.o inffast.o
+
+OBJA =
+# to use the asm code: make OBJA=match.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example$(EXE) minigzip$(EXE)
+
+check: test
+test: all
+ @LD_LIBRARY_PATH=.:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+ echo hello world | ./minigzip | ./minigzip -d || \
+ echo ' *** minigzip test FAILED ***' ; \
+ if ./example; then \
+ echo ' *** zlib test OK ***'; \
+ else \
+ echo ' *** zlib test FAILED ***'; \
+ fi
+
+libz.a: $(OBJS) $(OBJA)
+ $(AR) $@ $(OBJS) $(OBJA)
+ -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+match.o: match.S
+ $(CPP) match.S > _match.s
+ $(CC) -c _match.s
+ mv _match.o match.o
+ rm -f _match.s
+
+$(SHAREDLIBV): $(OBJS)
+ $(LDSHARED) -o $@ $(OBJS)
+ rm -f $(SHAREDLIB) $(SHAREDLIBM)
+ ln -s $@ $(SHAREDLIB)
+ ln -s $@ $(SHAREDLIBM)
+
+example$(EXE): example.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ example.o $(LDFLAGS)
+
+minigzip$(EXE): minigzip.o $(LIBS)
+ $(CC) $(CFLAGS) -o $@ minigzip.o $(LDFLAGS)
+
+install: $(LIBS)
+ -@if [ ! -d $(exec_prefix) ]; then mkdir -p $(exec_prefix); fi
+ -@if [ ! -d $(includedir) ]; then mkdir -p $(includedir); fi
+ -@if [ ! -d $(libdir) ]; then mkdir -p $(libdir); fi
+ -@if [ ! -d $(man3dir) ]; then mkdir -p $(man3dir); fi
+ cp zlib.h zconf.h $(includedir)
+ chmod 644 $(includedir)/zlib.h $(includedir)/zconf.h
+ cp $(LIBS) $(libdir)
+ cd $(libdir); chmod 755 $(LIBS)
+ -@(cd $(libdir); $(RANLIB) libz.a || true) >/dev/null 2>&1
+ cd $(libdir); if test -f $(SHAREDLIBV); then \
+ rm -f $(SHAREDLIB) $(SHAREDLIBM); \
+ ln -s $(SHAREDLIBV) $(SHAREDLIB); \
+ ln -s $(SHAREDLIBV) $(SHAREDLIBM); \
+ (ldconfig || true) >/dev/null 2>&1; \
+ fi
+ cp zlib.3 $(man3dir)
+ chmod 644 $(man3dir)/zlib.3
+# The ranlib in install is needed on NeXTSTEP which checks file times
+# ldconfig is for Linux
+
+uninstall:
+ cd $(includedir); \
+ cd $(libdir); rm -f libz.a; \
+ if test -f $(SHAREDLIBV); then \
+ rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \
+ fi
+ cd $(man3dir); rm -f zlib.3
+
+mostlyclean: clean
+clean:
+ rm -f *.o *~ example$(EXE) minigzip$(EXE) \
+ libz.* foo.gz so_locations \
+ _match.s maketree contrib/infback9/*.o
+
+maintainer-clean: distclean
+distclean: clean
+ cp -p Makefile.in Makefile
+ cp -p zconf.in.h zconf.h
+ rm -f .DS_Store
+
+tags:
+ etags *.[ch]
+
+depend:
+ makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: crc32.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzio.o: zutil.h zlib.h zconf.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
diff --git a/src/lib/zlib/adler32.c b/src/lib/zlib/adler32.c
new file mode 100644
index 00000000000..007ba26277c
--- /dev/null
+++ b/src/lib/zlib/adler32.c
@@ -0,0 +1,149 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#define BASE 65521UL /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware */
+#ifdef NO_DIVIDE
+# define MOD(a) \
+ do { \
+ if (a >= (BASE << 16)) a -= (BASE << 16); \
+ if (a >= (BASE << 15)) a -= (BASE << 15); \
+ if (a >= (BASE << 14)) a -= (BASE << 14); \
+ if (a >= (BASE << 13)) a -= (BASE << 13); \
+ if (a >= (BASE << 12)) a -= (BASE << 12); \
+ if (a >= (BASE << 11)) a -= (BASE << 11); \
+ if (a >= (BASE << 10)) a -= (BASE << 10); \
+ if (a >= (BASE << 9)) a -= (BASE << 9); \
+ if (a >= (BASE << 8)) a -= (BASE << 8); \
+ if (a >= (BASE << 7)) a -= (BASE << 7); \
+ if (a >= (BASE << 6)) a -= (BASE << 6); \
+ if (a >= (BASE << 5)) a -= (BASE << 5); \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD4(a) \
+ do { \
+ if (a >= (BASE << 4)) a -= (BASE << 4); \
+ if (a >= (BASE << 3)) a -= (BASE << 3); \
+ if (a >= (BASE << 2)) a -= (BASE << 2); \
+ if (a >= (BASE << 1)) a -= (BASE << 1); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD4(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD4(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ rem = (unsigned)(len2 % BASE);
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum1 > BASE) sum1 -= BASE;
+ if (sum2 > (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 > BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
diff --git a/src/lib/zlib/compress.c b/src/lib/zlib/compress.c
new file mode 100644
index 00000000000..df04f0148e6
--- /dev/null
+++ b/src/lib/zlib/compress.c
@@ -0,0 +1,79 @@
+/* compress.c -- compress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least 0.1% larger than sourceLen plus
+ 12 bytes. Upon exit, destLen is the actual size of the compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+int ZEXPORT compress2 (dest, destLen, source, sourceLen, level)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+ int level;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+#ifdef MAXSEG_64K
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, level);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+ If the default memLevel or windowBits for deflateInit() is changed, then
+ this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+ uLong sourceLen;
+{
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + 11;
+}
diff --git a/src/lib/zlib/crc32.c b/src/lib/zlib/crc32.c
new file mode 100644
index 00000000000..f658a9ef55e
--- /dev/null
+++ b/src/lib/zlib/crc32.c
@@ -0,0 +1,423 @@
+/* crc32.c -- compute the CRC-32 of a data stream
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Thanks to Rodney Brown <rbrown64@csc.com.au> for his contribution of faster
+ * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing
+ * tables for updating the shift register in one step with three exclusive-ors
+ * instead of four steps with four exclusive-ors. This results in about a
+ * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3.
+ */
+
+/* @(#) $Id$ */
+
+/*
+ Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore
+ protection on the static variables used to control the first-use generation
+ of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should
+ first call get_crc_table() to initialize the tables before allowing more than
+ one thread to use crc32().
+ */
+
+#ifdef MAKECRCH
+# include <stdio.h>
+# ifndef DYNAMIC_CRC_TABLE
+# define DYNAMIC_CRC_TABLE
+# endif /* !DYNAMIC_CRC_TABLE */
+#endif /* MAKECRCH */
+
+#include "zutil.h" /* for STDC and FAR definitions */
+
+#define local static
+
+/* Find a four-byte integer type for crc32_little() and crc32_big(). */
+#ifndef NOBYFOUR
+# ifdef STDC /* need ANSI C limits.h to determine sizes */
+# include <limits.h>
+# define BYFOUR
+# if (UINT_MAX == 0xffffffffUL)
+ typedef unsigned int u4;
+# else
+# if (ULONG_MAX == 0xffffffffUL)
+ typedef unsigned long u4;
+# else
+# if (USHRT_MAX == 0xffffffffUL)
+ typedef unsigned short u4;
+# else
+# undef BYFOUR /* can't find a four-byte integer type! */
+# endif
+# endif
+# endif
+# endif /* STDC */
+#endif /* !NOBYFOUR */
+
+/* Definitions for doing the crc four data bytes at a time. */
+#ifdef BYFOUR
+# define REV(w) (((w)>>24)+(((w)>>8)&0xff00)+ \
+ (((w)&0xff00)<<8)+(((w)&0xff)<<24))
+ local unsigned long crc32_little OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+ local unsigned long crc32_big OF((unsigned long,
+ const unsigned char FAR *, unsigned));
+# define TBLS 8
+#else
+# define TBLS 1
+#endif /* BYFOUR */
+
+/* Local functions for crc concatenation */
+local unsigned long gf2_matrix_times OF((unsigned long *mat,
+ unsigned long vec));
+local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat));
+
+#ifdef DYNAMIC_CRC_TABLE
+
+local volatile int crc_table_empty = 1;
+local unsigned long FAR crc_table[TBLS][256];
+local void make_crc_table OF((void));
+#ifdef MAKECRCH
+ local void write_table OF((FILE *, const unsigned long FAR *));
+#endif /* MAKECRCH */
+/*
+ Generate tables for a byte-wise 32-bit CRC calculation on the polynomial:
+ x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
+
+ Polynomials over GF(2) are represented in binary, one bit per coefficient,
+ with the lowest powers in the most significant bit. Then adding polynomials
+ is just exclusive-or, and multiplying a polynomial by x is a right shift by
+ one. If we call the above polynomial p, and represent a byte as the
+ polynomial q, also with the lowest power in the most significant bit (so the
+ byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
+ where a mod b means the remainder after dividing a by b.
+
+ This calculation is done using the shift-register method of multiplying and
+ taking the remainder. The register is initialized to zero, and for each
+ incoming bit, x^32 is added mod p to the register if the bit is a one (where
+ x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
+ x (which is shifting right by one and adding x^32 mod p if the bit shifted
+ out is a one). We start with the highest power (least significant bit) of
+ q and repeat for all eight bits of q.
+
+ The first table is simply the CRC of all possible eight bit values. This is
+ all the information needed to generate CRCs on data a byte at a time for all
+ combinations of CRC register values and incoming bytes. The remaining tables
+ allow for word-at-a-time CRC calculation for both big-endian and little-
+ endian machines, where a word is four bytes.
+*/
+local void make_crc_table()
+{
+ unsigned long c;
+ int n, k;
+ unsigned long poly; /* polynomial exclusive-or pattern */
+ /* terms of polynomial defining this crc (except x^32): */
+ static volatile int first = 1; /* flag to limit concurrent making */
+ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+
+ /* See if another task is already doing this (not thread-safe, but better
+ than nothing -- significantly reduces duration of vulnerability in
+ case the advice about DYNAMIC_CRC_TABLE is ignored) */
+ if (first) {
+ first = 0;
+
+ /* make exclusive-or pattern from polynomial (0xedb88320UL) */
+ poly = 0UL;
+ for (n = 0; n < sizeof(p)/sizeof(unsigned char); n++)
+ poly |= 1UL << (31 - p[n]);
+
+ /* generate a crc for every 8-bit value */
+ for (n = 0; n < 256; n++) {
+ c = (unsigned long)n;
+ for (k = 0; k < 8; k++)
+ c = c & 1 ? poly ^ (c >> 1) : c >> 1;
+ crc_table[0][n] = c;
+ }
+
+#ifdef BYFOUR
+ /* generate crc for each value followed by one, two, and three zeros,
+ and then the byte reversal of those as well as the first table */
+ for (n = 0; n < 256; n++) {
+ c = crc_table[0][n];
+ crc_table[4][n] = REV(c);
+ for (k = 1; k < 4; k++) {
+ c = crc_table[0][c & 0xff] ^ (c >> 8);
+ crc_table[k][n] = c;
+ crc_table[k + 4][n] = REV(c);
+ }
+ }
+#endif /* BYFOUR */
+
+ crc_table_empty = 0;
+ }
+ else { /* not first */
+ /* wait for the other guy to finish (not efficient, but rare) */
+ while (crc_table_empty)
+ ;
+ }
+
+#ifdef MAKECRCH
+ /* write out CRC tables to crc32.h */
+ {
+ FILE *out;
+
+ out = fopen("crc32.h", "w");
+ if (out == NULL) return;
+ fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n");
+ fprintf(out, " * Generated automatically by crc32.c\n */\n\n");
+ fprintf(out, "local const unsigned long FAR ");
+ fprintf(out, "crc_table[TBLS][256] =\n{\n {\n");
+ write_table(out, crc_table[0]);
+# ifdef BYFOUR
+ fprintf(out, "#ifdef BYFOUR\n");
+ for (k = 1; k < 8; k++) {
+ fprintf(out, " },\n {\n");
+ write_table(out, crc_table[k]);
+ }
+ fprintf(out, "#endif\n");
+# endif /* BYFOUR */
+ fprintf(out, " }\n};\n");
+ fclose(out);
+ }
+#endif /* MAKECRCH */
+}
+
+#ifdef MAKECRCH
+local void write_table(out, table)
+ FILE *out;
+ const unsigned long FAR *table;
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", table[n],
+ n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", "));
+}
+#endif /* MAKECRCH */
+
+#else /* !DYNAMIC_CRC_TABLE */
+/* ========================================================================
+ * Tables of CRC-32s of all single-byte values, made by make_crc_table().
+ */
+#include "crc32.h"
+#endif /* DYNAMIC_CRC_TABLE */
+
+/* =========================================================================
+ * This function can be used by asm versions of crc32()
+ */
+const unsigned long FAR * ZEXPORT get_crc_table()
+{
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+ return (const unsigned long FAR *)crc_table;
+}
+
+/* ========================================================================= */
+#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8)
+#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1
+
+/* ========================================================================= */
+unsigned long ZEXPORT crc32(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ if (buf == Z_NULL) return 0UL;
+
+#ifdef DYNAMIC_CRC_TABLE
+ if (crc_table_empty)
+ make_crc_table();
+#endif /* DYNAMIC_CRC_TABLE */
+
+#ifdef BYFOUR
+ if (sizeof(void *) == sizeof(ptrdiff_t)) {
+ u4 endian;
+
+ endian = 1;
+ if (*((unsigned char *)(&endian)))
+ return crc32_little(crc, buf, len);
+ else
+ return crc32_big(crc, buf, len);
+ }
+#endif /* BYFOUR */
+ crc = crc ^ 0xffffffffUL;
+ while (len >= 8) {
+ DO8;
+ len -= 8;
+ }
+ if (len) do {
+ DO1;
+ } while (--len);
+ return crc ^ 0xffffffffUL;
+}
+
+#ifdef BYFOUR
+
+/* ========================================================================= */
+#define DOLIT4 c ^= *buf4++; \
+ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \
+ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24]
+#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4
+
+/* ========================================================================= */
+local unsigned long crc32_little(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = (u4)crc;
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ while (len >= 32) {
+ DOLIT32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOLIT4;
+ len -= 4;
+ }
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)c;
+}
+
+/* ========================================================================= */
+#define DOBIG4 c ^= *++buf4; \
+ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \
+ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24]
+#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4
+
+/* ========================================================================= */
+local unsigned long crc32_big(crc, buf, len)
+ unsigned long crc;
+ const unsigned char FAR *buf;
+ unsigned len;
+{
+ register u4 c;
+ register const u4 FAR *buf4;
+
+ c = REV((u4)crc);
+ c = ~c;
+ while (len && ((ptrdiff_t)buf & 3)) {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ len--;
+ }
+
+ buf4 = (const u4 FAR *)(const void FAR *)buf;
+ buf4--;
+ while (len >= 32) {
+ DOBIG32;
+ len -= 32;
+ }
+ while (len >= 4) {
+ DOBIG4;
+ len -= 4;
+ }
+ buf4++;
+ buf = (const unsigned char FAR *)buf4;
+
+ if (len) do {
+ c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8);
+ } while (--len);
+ c = ~c;
+ return (unsigned long)(REV(c));
+}
+
+#endif /* BYFOUR */
+
+#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */
+
+/* ========================================================================= */
+local unsigned long gf2_matrix_times(mat, vec)
+ unsigned long *mat;
+ unsigned long vec;
+{
+ unsigned long sum;
+
+ sum = 0;
+ while (vec) {
+ if (vec & 1)
+ sum ^= *mat;
+ vec >>= 1;
+ mat++;
+ }
+ return sum;
+}
+
+/* ========================================================================= */
+local void gf2_matrix_square(square, mat)
+ unsigned long *square;
+ unsigned long *mat;
+{
+ int n;
+
+ for (n = 0; n < GF2_DIM; n++)
+ square[n] = gf2_matrix_times(mat, mat[n]);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT crc32_combine(crc1, crc2, len2)
+ uLong crc1;
+ uLong crc2;
+ z_off_t len2;
+{
+ int n;
+ unsigned long row;
+ unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */
+ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */
+
+ /* degenerate case */
+ if (len2 == 0)
+ return crc1;
+
+ /* put operator for one zero bit in odd */
+ odd[0] = 0xedb88320L; /* CRC-32 polynomial */
+ row = 1;
+ for (n = 1; n < GF2_DIM; n++) {
+ odd[n] = row;
+ row <<= 1;
+ }
+
+ /* put operator for two zero bits in even */
+ gf2_matrix_square(even, odd);
+
+ /* put operator for four zero bits in odd */
+ gf2_matrix_square(odd, even);
+
+ /* apply len2 zeros to crc1 (first square will put the operator for one
+ zero byte, eight zero bits, in even) */
+ do {
+ /* apply zeros operator for this bit of len2 */
+ gf2_matrix_square(even, odd);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(even, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ if (len2 == 0)
+ break;
+
+ /* another iteration of the loop with odd and even swapped */
+ gf2_matrix_square(odd, even);
+ if (len2 & 1)
+ crc1 = gf2_matrix_times(odd, crc1);
+ len2 >>= 1;
+
+ /* if no more bits set, then done */
+ } while (len2 != 0);
+
+ /* return combined crc */
+ crc1 ^= crc2;
+ return crc1;
+}
diff --git a/src/lib/zlib/crc32.h b/src/lib/zlib/crc32.h
new file mode 100644
index 00000000000..8053b6117c0
--- /dev/null
+++ b/src/lib/zlib/crc32.h
@@ -0,0 +1,441 @@
+/* crc32.h -- tables for rapid CRC calculation
+ * Generated automatically by crc32.c
+ */
+
+local const unsigned long FAR crc_table[TBLS][256] =
+{
+ {
+ 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
+ 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
+ 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
+ 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
+ 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
+ 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
+ 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
+ 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
+ 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
+ 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
+ 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
+ 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
+ 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
+ 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
+ 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
+ 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
+ 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
+ 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
+ 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
+ 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
+ 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
+ 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
+ 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
+ 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
+ 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
+ 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
+ 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
+ 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
+ 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
+ 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
+ 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
+ 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
+ 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
+ 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
+ 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
+ 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
+ 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
+ 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
+ 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
+ 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
+ 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
+ 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
+ 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
+ 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
+ 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
+ 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
+ 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
+ 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
+ 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
+ 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
+ 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
+ 0x2d02ef8dUL
+#ifdef BYFOUR
+ },
+ {
+ 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL,
+ 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL,
+ 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL,
+ 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL,
+ 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL,
+ 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL,
+ 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL,
+ 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL,
+ 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL,
+ 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL,
+ 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL,
+ 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL,
+ 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL,
+ 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL,
+ 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL,
+ 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL,
+ 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL,
+ 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL,
+ 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL,
+ 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL,
+ 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL,
+ 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL,
+ 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL,
+ 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL,
+ 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL,
+ 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL,
+ 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL,
+ 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL,
+ 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL,
+ 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL,
+ 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL,
+ 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL,
+ 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL,
+ 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL,
+ 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL,
+ 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL,
+ 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL,
+ 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL,
+ 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL,
+ 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL,
+ 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL,
+ 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL,
+ 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL,
+ 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL,
+ 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL,
+ 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL,
+ 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL,
+ 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL,
+ 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL,
+ 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL,
+ 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL,
+ 0x9324fd72UL
+ },
+ {
+ 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL,
+ 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL,
+ 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL,
+ 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL,
+ 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL,
+ 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL,
+ 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL,
+ 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL,
+ 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL,
+ 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL,
+ 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL,
+ 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL,
+ 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL,
+ 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL,
+ 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL,
+ 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL,
+ 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL,
+ 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL,
+ 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL,
+ 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL,
+ 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL,
+ 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL,
+ 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL,
+ 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL,
+ 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL,
+ 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL,
+ 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL,
+ 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL,
+ 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL,
+ 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL,
+ 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL,
+ 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL,
+ 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL,
+ 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL,
+ 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL,
+ 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL,
+ 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL,
+ 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL,
+ 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL,
+ 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL,
+ 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL,
+ 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL,
+ 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL,
+ 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL,
+ 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL,
+ 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL,
+ 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL,
+ 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL,
+ 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL,
+ 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL,
+ 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL,
+ 0xbe9834edUL
+ },
+ {
+ 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL,
+ 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL,
+ 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL,
+ 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL,
+ 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL,
+ 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL,
+ 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL,
+ 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL,
+ 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL,
+ 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL,
+ 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL,
+ 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL,
+ 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL,
+ 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL,
+ 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL,
+ 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL,
+ 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL,
+ 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL,
+ 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL,
+ 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL,
+ 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL,
+ 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL,
+ 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL,
+ 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL,
+ 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL,
+ 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL,
+ 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL,
+ 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL,
+ 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL,
+ 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL,
+ 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL,
+ 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL,
+ 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL,
+ 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL,
+ 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL,
+ 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL,
+ 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL,
+ 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL,
+ 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL,
+ 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL,
+ 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL,
+ 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL,
+ 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL,
+ 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL,
+ 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL,
+ 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL,
+ 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL,
+ 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL,
+ 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL,
+ 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL,
+ 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL,
+ 0xde0506f1UL
+ },
+ {
+ 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL,
+ 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL,
+ 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL,
+ 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL,
+ 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL,
+ 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL,
+ 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL,
+ 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL,
+ 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL,
+ 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL,
+ 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL,
+ 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL,
+ 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL,
+ 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL,
+ 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL,
+ 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL,
+ 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL,
+ 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL,
+ 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL,
+ 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL,
+ 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL,
+ 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL,
+ 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL,
+ 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL,
+ 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL,
+ 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL,
+ 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL,
+ 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL,
+ 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL,
+ 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL,
+ 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL,
+ 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL,
+ 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL,
+ 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL,
+ 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL,
+ 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL,
+ 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL,
+ 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL,
+ 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL,
+ 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL,
+ 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL,
+ 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL,
+ 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL,
+ 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL,
+ 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL,
+ 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL,
+ 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL,
+ 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL,
+ 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL,
+ 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL,
+ 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL,
+ 0x8def022dUL
+ },
+ {
+ 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL,
+ 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL,
+ 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL,
+ 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL,
+ 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL,
+ 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL,
+ 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL,
+ 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL,
+ 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL,
+ 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL,
+ 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL,
+ 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL,
+ 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL,
+ 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL,
+ 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL,
+ 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL,
+ 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL,
+ 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL,
+ 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL,
+ 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL,
+ 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL,
+ 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL,
+ 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL,
+ 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL,
+ 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL,
+ 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL,
+ 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL,
+ 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL,
+ 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL,
+ 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL,
+ 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL,
+ 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL,
+ 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL,
+ 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL,
+ 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL,
+ 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL,
+ 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL,
+ 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL,
+ 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL,
+ 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL,
+ 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL,
+ 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL,
+ 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL,
+ 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL,
+ 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL,
+ 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL,
+ 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL,
+ 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL,
+ 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL,
+ 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL,
+ 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL,
+ 0x72fd2493UL
+ },
+ {
+ 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL,
+ 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL,
+ 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL,
+ 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL,
+ 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL,
+ 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL,
+ 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL,
+ 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL,
+ 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL,
+ 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL,
+ 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL,
+ 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL,
+ 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL,
+ 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL,
+ 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL,
+ 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL,
+ 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL,
+ 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL,
+ 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL,
+ 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL,
+ 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL,
+ 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL,
+ 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL,
+ 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL,
+ 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL,
+ 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL,
+ 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL,
+ 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL,
+ 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL,
+ 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL,
+ 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL,
+ 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL,
+ 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL,
+ 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL,
+ 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL,
+ 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL,
+ 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL,
+ 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL,
+ 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL,
+ 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL,
+ 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL,
+ 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL,
+ 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL,
+ 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL,
+ 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL,
+ 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL,
+ 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL,
+ 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL,
+ 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL,
+ 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL,
+ 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL,
+ 0xed3498beUL
+ },
+ {
+ 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL,
+ 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL,
+ 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL,
+ 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL,
+ 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL,
+ 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL,
+ 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL,
+ 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL,
+ 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL,
+ 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL,
+ 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL,
+ 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL,
+ 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL,
+ 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL,
+ 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL,
+ 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL,
+ 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL,
+ 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL,
+ 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL,
+ 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL,
+ 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL,
+ 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL,
+ 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL,
+ 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL,
+ 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL,
+ 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL,
+ 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL,
+ 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL,
+ 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL,
+ 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL,
+ 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL,
+ 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL,
+ 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL,
+ 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL,
+ 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL,
+ 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL,
+ 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL,
+ 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL,
+ 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL,
+ 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL,
+ 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL,
+ 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL,
+ 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL,
+ 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL,
+ 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL,
+ 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL,
+ 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL,
+ 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL,
+ 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL,
+ 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL,
+ 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL,
+ 0xf10605deUL
+#endif
+ }
+};
diff --git a/src/lib/zlib/deflate.c b/src/lib/zlib/deflate.c
new file mode 100644
index 00000000000..29ce1f64a57
--- /dev/null
+++ b/src/lib/zlib/deflate.c
@@ -0,0 +1,1736 @@
+/* deflate.c -- compress data using the deflation algorithm
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process depends on being able to identify portions
+ * of the input text which are identical to earlier input (within a
+ * sliding window trailing behind the input currently being processed).
+ *
+ * The most straightforward technique turns out to be the fastest for
+ * most input files: try all possible matches and select the longest.
+ * The key feature of this algorithm is that insertions into the string
+ * dictionary are very simple and thus fast, and deletions are avoided
+ * completely. Insertions are performed at each input character, whereas
+ * string matches are performed only when the previous match ends. So it
+ * is preferable to spend more time in matches to allow very fast string
+ * insertions and avoid deletions. The matching algorithm for small
+ * strings is inspired from that of Rabin & Karp. A brute force approach
+ * is used to find longer strings when a small match has been found.
+ * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze
+ * (by Leonid Broukhis).
+ * A previous version of this file used a more sophisticated algorithm
+ * (by Fiala and Greene) which is guaranteed to run in linear amortized
+ * time, but has a larger average cost, uses more memory and is patented.
+ * However the F&G algorithm may be faster for some highly redundant
+ * files if the parameter max_chain_length (described below) is too large.
+ *
+ * ACKNOWLEDGEMENTS
+ *
+ * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and
+ * I found it in 'freeze' written by Leonid Broukhis.
+ * Thanks to many people for bug reports and testing.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification".
+ * Available in http://www.ietf.org/rfc/rfc1951.txt
+ *
+ * A description of the Rabin and Karp algorithm is given in the book
+ * "Algorithms" by R. Sedgewick, Addison-Wesley, p252.
+ *
+ * Fiala,E.R., and Greene,D.H.
+ * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595
+ *
+ */
+
+/* @(#) $Id$ */
+
+#include "deflate.h"
+
+const char deflate_copyright[] =
+ " deflate 1.2.3 Copyright 1995-2005 Jean-loup Gailly ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/* ===========================================================================
+ * Function prototypes.
+ */
+typedef enum {
+ need_more, /* block not completed, need more input or more output */
+ block_done, /* block flush performed */
+ finish_started, /* finish started, need only more output at next deflate */
+ finish_done /* finish done, accept no more input or output */
+} block_state;
+
+typedef block_state (*compress_func) OF((deflate_state *s, int flush));
+/* Compression function. Returns the block state after the call. */
+
+local void fill_window OF((deflate_state *s));
+local block_state deflate_stored OF((deflate_state *s, int flush));
+local block_state deflate_fast OF((deflate_state *s, int flush));
+#ifndef FASTEST
+local block_state deflate_slow OF((deflate_state *s, int flush));
+#endif
+local void lm_init OF((deflate_state *s));
+local void putShortMSB OF((deflate_state *s, uInt b));
+local void flush_pending OF((z_streamp strm));
+local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size));
+#ifndef FASTEST
+#ifdef ASMV
+ void match_init OF((void)); /* asm code initialization */
+ uInt longest_match OF((deflate_state *s, IPos cur_match));
+#else
+local uInt longest_match OF((deflate_state *s, IPos cur_match));
+#endif
+#endif
+local uInt longest_match_fast OF((deflate_state *s, IPos cur_match));
+
+#ifdef DEBUG
+local void check_match OF((deflate_state *s, IPos start, IPos match,
+ int length));
+#endif
+
+/* ===========================================================================
+ * Local data
+ */
+
+#define NIL 0
+/* Tail of hash chains */
+
+#ifndef TOO_FAR
+# define TOO_FAR 4096
+#endif
+/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+/* Values for max_lazy_match, good_match and max_chain_length, depending on
+ * the desired pack level (0..9). The values given below have been tuned to
+ * exclude worst case performance for pathological files. Better values may be
+ * found for specific files.
+ */
+typedef struct config_s {
+ ush good_length; /* reduce lazy search above this match length */
+ ush max_lazy; /* do not perform lazy search above this match length */
+ ush nice_length; /* quit search above this match length */
+ ush max_chain;
+ compress_func func;
+} config;
+
+#ifdef FASTEST
+local const config configuration_table[2] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */
+#else
+local const config configuration_table[10] = {
+/* good lazy nice chain */
+/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */
+/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */
+/* 2 */ {4, 5, 16, 8, deflate_fast},
+/* 3 */ {4, 6, 32, 32, deflate_fast},
+
+/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */
+/* 5 */ {8, 16, 32, 32, deflate_slow},
+/* 6 */ {8, 16, 128, 128, deflate_slow},
+/* 7 */ {8, 32, 128, 256, deflate_slow},
+/* 8 */ {32, 128, 258, 1024, deflate_slow},
+/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */
+#endif
+
+/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4
+ * For deflate_fast() (levels <= 3) good is ignored and lazy has a different
+ * meaning.
+ */
+
+#define EQUAL 0
+/* result of memcmp for equal strings */
+
+#ifndef NO_DUMMY_DECL
+struct static_tree_desc_s {int dummy;}; /* for buggy compilers */
+#endif
+
+/* ===========================================================================
+ * Update a hash value with the given input byte
+ * IN assertion: all calls to to UPDATE_HASH are made with consecutive
+ * input characters, so that a running hash key can be computed from the
+ * previous key instead of complete recalculation each time.
+ */
+#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask)
+
+
+/* ===========================================================================
+ * Insert string str in the dictionary and set match_head to the previous head
+ * of the hash chain (the most recent string with same hash key). Return
+ * the previous length of the hash chain.
+ * If this file is compiled with -DFASTEST, the compression level is forced
+ * to 1, and no hash chains are maintained.
+ * IN assertion: all calls to to INSERT_STRING are made with consecutive
+ * input characters and the first MIN_MATCH bytes of str are valid
+ * (except for the last MIN_MATCH-1 bytes of the input file).
+ */
+#ifdef FASTEST
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#else
+#define INSERT_STRING(s, str, match_head) \
+ (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \
+ match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \
+ s->head[s->ins_h] = (Pos)(str))
+#endif
+
+/* ===========================================================================
+ * Initialize the hash table (avoiding 64K overflow for 16 bit systems).
+ * prev[] will be initialized on the fly.
+ */
+#define CLEAR_HASH(s) \
+ s->head[s->hash_size-1] = NIL; \
+ zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head));
+
+/* ========================================================================= */
+int ZEXPORT deflateInit_(strm, level, version, stream_size)
+ z_streamp strm;
+ int level;
+ const char *version;
+ int stream_size;
+{
+ return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL,
+ Z_DEFAULT_STRATEGY, version, stream_size);
+ /* To do: ignore strm->next_in if we use it as window */
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy,
+ version, stream_size)
+ z_streamp strm;
+ int level;
+ int method;
+ int windowBits;
+ int memLevel;
+ int strategy;
+ const char *version;
+ int stream_size;
+{
+ deflate_state *s;
+ int wrap = 1;
+ static const char my_version[] = ZLIB_VERSION;
+
+ ushf *overlay;
+ /* We overlay pending_buf and d_buf+l_buf. This works since the average
+ * output size for (length,distance) codes is <= 24 bits.
+ */
+
+ if (version == Z_NULL || version[0] != my_version[0] ||
+ stream_size != sizeof(z_stream)) {
+ return Z_VERSION_ERROR;
+ }
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+
+ strm->msg = Z_NULL;
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+
+ if (windowBits < 0) { /* suppress zlib wrapper */
+ wrap = 0;
+ windowBits = -windowBits;
+ }
+#ifdef GZIP
+ else if (windowBits > 15) {
+ wrap = 2; /* write gzip wrapper instead */
+ windowBits -= 16;
+ }
+#endif
+ if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED ||
+ windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
+ strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */
+ s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state));
+ if (s == Z_NULL) return Z_MEM_ERROR;
+ strm->state = (struct internal_state FAR *)s;
+ s->strm = strm;
+
+ s->wrap = wrap;
+ s->gzhead = Z_NULL;
+ s->w_bits = windowBits;
+ s->w_size = 1 << s->w_bits;
+ s->w_mask = s->w_size - 1;
+
+ s->hash_bits = memLevel + 7;
+ s->hash_size = 1 << s->hash_bits;
+ s->hash_mask = s->hash_size - 1;
+ s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH);
+
+ s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte));
+ s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos));
+ s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos));
+
+ s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
+
+ overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2);
+ s->pending_buf = (uchf *) overlay;
+ s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L);
+
+ if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL ||
+ s->pending_buf == Z_NULL) {
+ s->status = FINISH_STATE;
+ strm->msg = (char*)ERR_MSG(Z_MEM_ERROR);
+ deflateEnd (strm);
+ return Z_MEM_ERROR;
+ }
+ s->d_buf = overlay + s->lit_bufsize/sizeof(ush);
+ s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize;
+
+ s->level = level;
+ s->strategy = strategy;
+ s->method = (Byte)method;
+
+ return deflateReset(strm);
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength)
+ z_streamp strm;
+ const Bytef *dictionary;
+ uInt dictLength;
+{
+ deflate_state *s;
+ uInt length = dictLength;
+ uInt n;
+ IPos hash_head = 0;
+
+ if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL ||
+ strm->state->wrap == 2 ||
+ (strm->state->wrap == 1 && strm->state->status != INIT_STATE))
+ return Z_STREAM_ERROR;
+
+ s = strm->state;
+ if (s->wrap)
+ strm->adler = adler32(strm->adler, dictionary, dictLength);
+
+ if (length < MIN_MATCH) return Z_OK;
+ if (length > MAX_DIST(s)) {
+ length = MAX_DIST(s);
+ dictionary += dictLength - length; /* use the tail of the dictionary */
+ }
+ zmemcpy(s->window, dictionary, length);
+ s->strstart = length;
+ s->block_start = (long)length;
+
+ /* Insert all strings in the hash table (except for the last two bytes).
+ * s->lookahead stays null, so s->ins_h will be recomputed at the next
+ * call of fill_window.
+ */
+ s->ins_h = s->window[0];
+ UPDATE_HASH(s, s->ins_h, s->window[1]);
+ for (n = 0; n <= length - MIN_MATCH; n++) {
+ INSERT_STRING(s, n, hash_head);
+ }
+ if (hash_head) hash_head = 0; /* to make compiler happy */
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateReset (strm)
+ z_streamp strm;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) {
+ return Z_STREAM_ERROR;
+ }
+
+ strm->total_in = strm->total_out = 0;
+ strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */
+ strm->data_type = Z_UNKNOWN;
+
+ s = (deflate_state *)strm->state;
+ s->pending = 0;
+ s->pending_out = s->pending_buf;
+
+ if (s->wrap < 0) {
+ s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
+ }
+ s->status = s->wrap ? INIT_STATE : BUSY_STATE;
+ strm->adler =
+#ifdef GZIP
+ s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
+#endif
+ adler32(0L, Z_NULL, 0);
+ s->last_flush = Z_NO_FLUSH;
+
+ _tr_init(s);
+ lm_init(s);
+
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateSetHeader (strm, head)
+ z_streamp strm;
+ gz_headerp head;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ if (strm->state->wrap != 2) return Z_STREAM_ERROR;
+ strm->state->gzhead = head;
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflatePrime (strm, bits, value)
+ z_streamp strm;
+ int bits;
+ int value;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ strm->state->bi_valid = bits;
+ strm->state->bi_buf = (ush)(value & ((1 << bits) - 1));
+ return Z_OK;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateParams(strm, level, strategy)
+ z_streamp strm;
+ int level;
+ int strategy;
+{
+ deflate_state *s;
+ compress_func func;
+ int err = Z_OK;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+
+#ifdef FASTEST
+ if (level != 0) level = 1;
+#else
+ if (level == Z_DEFAULT_COMPRESSION) level = 6;
+#endif
+ if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) {
+ return Z_STREAM_ERROR;
+ }
+ func = configuration_table[s->level].func;
+
+ if (func != configuration_table[level].func && strm->total_in != 0) {
+ /* Flush the last buffer: */
+ err = deflate(strm, Z_PARTIAL_FLUSH);
+ }
+ if (s->level != level) {
+ s->level = level;
+ s->max_lazy_match = configuration_table[level].max_lazy;
+ s->good_match = configuration_table[level].good_length;
+ s->nice_match = configuration_table[level].nice_length;
+ s->max_chain_length = configuration_table[level].max_chain;
+ }
+ s->strategy = strategy;
+ return err;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain)
+ z_streamp strm;
+ int good_length;
+ int max_lazy;
+ int nice_length;
+ int max_chain;
+{
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ s = strm->state;
+ s->good_match = good_length;
+ s->max_lazy_match = max_lazy;
+ s->nice_match = nice_length;
+ s->max_chain_length = max_chain;
+ return Z_OK;
+}
+
+/* =========================================================================
+ * For the default windowBits of 15 and memLevel of 8, this function returns
+ * a close to exact, as well as small, upper bound on the compressed size.
+ * They are coded as constants here for a reason--if the #define's are
+ * changed, then this function needs to be changed as well. The return
+ * value for 15 and 8 only works for those exact settings.
+ *
+ * For any setting other than those defaults for windowBits and memLevel,
+ * the value returned is a conservative worst case for the maximum expansion
+ * resulting from using fixed blocks instead of stored blocks, which deflate
+ * can emit on compressed data for some combinations of the parameters.
+ *
+ * This function could be more sophisticated to provide closer upper bounds
+ * for every combination of windowBits and memLevel, as well as wrap.
+ * But even the conservative upper bound of about 14% expansion does not
+ * seem onerous for output buffer allocation.
+ */
+uLong ZEXPORT deflateBound(strm, sourceLen)
+ z_streamp strm;
+ uLong sourceLen;
+{
+ deflate_state *s;
+ uLong destLen;
+
+ /* conservative upper bound */
+ destLen = sourceLen +
+ ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 11;
+
+ /* if can't get parameters, return conservative bound */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return destLen;
+
+ /* if not default parameters, return conservative bound */
+ s = strm->state;
+ if (s->w_bits != 15 || s->hash_bits != 8 + 7)
+ return destLen;
+
+ /* default settings: return tight bound for that case */
+ return compressBound(sourceLen);
+}
+
+/* =========================================================================
+ * Put a short in the pending buffer. The 16-bit value is put in MSB order.
+ * IN assertion: the stream state is correct and there is enough room in
+ * pending_buf.
+ */
+local void putShortMSB (s, b)
+ deflate_state *s;
+ uInt b;
+{
+ put_byte(s, (Byte)(b >> 8));
+ put_byte(s, (Byte)(b & 0xff));
+}
+
+/* =========================================================================
+ * Flush as much pending output as possible. All deflate() output goes
+ * through this function so some applications may wish to modify it
+ * to avoid allocating a large strm->next_out buffer and copying into it.
+ * (See also read_buf()).
+ */
+local void flush_pending(strm)
+ z_streamp strm;
+{
+ unsigned len = strm->state->pending;
+
+ if (len > strm->avail_out) len = strm->avail_out;
+ if (len == 0) return;
+
+ zmemcpy(strm->next_out, strm->state->pending_out, len);
+ strm->next_out += len;
+ strm->state->pending_out += len;
+ strm->total_out += len;
+ strm->avail_out -= len;
+ strm->state->pending -= len;
+ if (strm->state->pending == 0) {
+ strm->state->pending_out = strm->state->pending_buf;
+ }
+}
+
+/* ========================================================================= */
+int ZEXPORT deflate (strm, flush)
+ z_streamp strm;
+ int flush;
+{
+ int old_flush; /* value of flush param for previous deflate call */
+ deflate_state *s;
+
+ if (strm == Z_NULL || strm->state == Z_NULL ||
+ flush > Z_FINISH || flush < 0) {
+ return Z_STREAM_ERROR;
+ }
+ s = strm->state;
+
+ if (strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0) ||
+ (s->status == FINISH_STATE && flush != Z_FINISH)) {
+ ERR_RETURN(strm, Z_STREAM_ERROR);
+ }
+ if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
+
+ s->strm = strm; /* just in case */
+ old_flush = s->last_flush;
+ s->last_flush = flush;
+
+ /* Write the header */
+ if (s->status == INIT_STATE) {
+#ifdef GZIP
+ if (s->wrap == 2) {
+ strm->adler = crc32(0L, Z_NULL, 0);
+ put_byte(s, 31);
+ put_byte(s, 139);
+ put_byte(s, 8);
+ if (s->gzhead == NULL) {
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, 0);
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, OS_CODE);
+ s->status = BUSY_STATE;
+ }
+ else {
+ put_byte(s, (s->gzhead->text ? 1 : 0) +
+ (s->gzhead->hcrc ? 2 : 0) +
+ (s->gzhead->extra == Z_NULL ? 0 : 4) +
+ (s->gzhead->name == Z_NULL ? 0 : 8) +
+ (s->gzhead->comment == Z_NULL ? 0 : 16)
+ );
+ put_byte(s, (Byte)(s->gzhead->time & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff));
+ put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff));
+ put_byte(s, s->level == 9 ? 2 :
+ (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
+ 4 : 0));
+ put_byte(s, s->gzhead->os & 0xff);
+ if (s->gzhead->extra != NULL) {
+ put_byte(s, s->gzhead->extra_len & 0xff);
+ put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
+ }
+ if (s->gzhead->hcrc)
+ strm->adler = crc32(strm->adler, s->pending_buf,
+ s->pending);
+ s->gzindex = 0;
+ s->status = EXTRA_STATE;
+ }
+ }
+ else
+#endif
+ {
+ uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
+ uInt level_flags;
+
+ if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
+ level_flags = 0;
+ else if (s->level < 6)
+ level_flags = 1;
+ else if (s->level == 6)
+ level_flags = 2;
+ else
+ level_flags = 3;
+ header |= (level_flags << 6);
+ if (s->strstart != 0) header |= PRESET_DICT;
+ header += 31 - (header % 31);
+
+ s->status = BUSY_STATE;
+ putShortMSB(s, header);
+
+ /* Save the adler32 of the preset dictionary: */
+ if (s->strstart != 0) {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ strm->adler = adler32(0L, Z_NULL, 0);
+ }
+ }
+#ifdef GZIP
+ if (s->status == EXTRA_STATE) {
+ if (s->gzhead->extra != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+
+ while (s->gzindex < (s->gzhead->extra_len & 0xffff)) {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size)
+ break;
+ }
+ put_byte(s, s->gzhead->extra[s->gzindex]);
+ s->gzindex++;
+ }
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (s->gzindex == s->gzhead->extra_len) {
+ s->gzindex = 0;
+ s->status = NAME_STATE;
+ }
+ }
+ else
+ s->status = NAME_STATE;
+ }
+ if (s->status == NAME_STATE) {
+ if (s->gzhead->name != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->name[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0) {
+ s->gzindex = 0;
+ s->status = COMMENT_STATE;
+ }
+ }
+ else
+ s->status = COMMENT_STATE;
+ }
+ if (s->status == COMMENT_STATE) {
+ if (s->gzhead->comment != NULL) {
+ uInt beg = s->pending; /* start of bytes to update crc */
+ int val;
+
+ do {
+ if (s->pending == s->pending_buf_size) {
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ flush_pending(strm);
+ beg = s->pending;
+ if (s->pending == s->pending_buf_size) {
+ val = 1;
+ break;
+ }
+ }
+ val = s->gzhead->comment[s->gzindex++];
+ put_byte(s, val);
+ } while (val != 0);
+ if (s->gzhead->hcrc && s->pending > beg)
+ strm->adler = crc32(strm->adler, s->pending_buf + beg,
+ s->pending - beg);
+ if (val == 0)
+ s->status = HCRC_STATE;
+ }
+ else
+ s->status = HCRC_STATE;
+ }
+ if (s->status == HCRC_STATE) {
+ if (s->gzhead->hcrc) {
+ if (s->pending + 2 > s->pending_buf_size)
+ flush_pending(strm);
+ if (s->pending + 2 <= s->pending_buf_size) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ strm->adler = crc32(0L, Z_NULL, 0);
+ s->status = BUSY_STATE;
+ }
+ }
+ else
+ s->status = BUSY_STATE;
+ }
+#endif
+
+ /* Flush as much pending output as possible */
+ if (s->pending != 0) {
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ /* Since avail_out is 0, deflate will be called again with
+ * more output space, but possibly with both pending and
+ * avail_in equal to zero. There won't be anything to do,
+ * but this is not an error situation so make sure we
+ * return OK instead of BUF_ERROR at next call of deflate:
+ */
+ s->last_flush = -1;
+ return Z_OK;
+ }
+
+ /* Make sure there is something to do and avoid duplicate consecutive
+ * flushes. For repeated and useless calls with Z_FINISH, we keep
+ * returning Z_STREAM_END instead of Z_BUF_ERROR.
+ */
+ } else if (strm->avail_in == 0 && flush <= old_flush &&
+ flush != Z_FINISH) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* User must not provide more input after the first FINISH: */
+ if (s->status == FINISH_STATE && strm->avail_in != 0) {
+ ERR_RETURN(strm, Z_BUF_ERROR);
+ }
+
+ /* Start a new block or continue the current one.
+ */
+ if (strm->avail_in != 0 || s->lookahead != 0 ||
+ (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
+ block_state bstate;
+
+ bstate = (*(configuration_table[s->level].func))(s, flush);
+
+ if (bstate == finish_started || bstate == finish_done) {
+ s->status = FINISH_STATE;
+ }
+ if (bstate == need_more || bstate == finish_started) {
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
+ }
+ return Z_OK;
+ /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
+ * of deflate should use the same flush parameter to make sure
+ * that the flush is complete. So we don't have to output an
+ * empty block here, this will be done at next call. This also
+ * ensures that for a very small output buffer, we emit at most
+ * one empty block.
+ */
+ }
+ if (bstate == block_done) {
+ if (flush == Z_PARTIAL_FLUSH) {
+ _tr_align(s);
+ } else { /* FULL_FLUSH or SYNC_FLUSH */
+ _tr_stored_block(s, (char*)0, 0L, 0);
+ /* For a full flush, this empty block will be recognized
+ * as a special marker by inflate_sync().
+ */
+ if (flush == Z_FULL_FLUSH) {
+ CLEAR_HASH(s); /* forget history */
+ }
+ }
+ flush_pending(strm);
+ if (strm->avail_out == 0) {
+ s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
+ return Z_OK;
+ }
+ }
+ }
+ Assert(strm->avail_out > 0, "bug2");
+
+ if (flush != Z_FINISH) return Z_OK;
+ if (s->wrap <= 0) return Z_STREAM_END;
+
+ /* Write the trailer */
+#ifdef GZIP
+ if (s->wrap == 2) {
+ put_byte(s, (Byte)(strm->adler & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->adler >> 24) & 0xff));
+ put_byte(s, (Byte)(strm->total_in & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 8) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 16) & 0xff));
+ put_byte(s, (Byte)((strm->total_in >> 24) & 0xff));
+ }
+ else
+#endif
+ {
+ putShortMSB(s, (uInt)(strm->adler >> 16));
+ putShortMSB(s, (uInt)(strm->adler & 0xffff));
+ }
+ flush_pending(strm);
+ /* If avail_out is zero, the application will call deflate again
+ * to flush the rest.
+ */
+ if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
+ return s->pending != 0 ? Z_OK : Z_STREAM_END;
+}
+
+/* ========================================================================= */
+int ZEXPORT deflateEnd (strm)
+ z_streamp strm;
+{
+ int status;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+
+ status = strm->state->status;
+ if (status != INIT_STATE &&
+ status != EXTRA_STATE &&
+ status != NAME_STATE &&
+ status != COMMENT_STATE &&
+ status != HCRC_STATE &&
+ status != BUSY_STATE &&
+ status != FINISH_STATE) {
+ return Z_STREAM_ERROR;
+ }
+
+ /* Deallocate in reverse order of allocations: */
+ TRY_FREE(strm, strm->state->pending_buf);
+ TRY_FREE(strm, strm->state->head);
+ TRY_FREE(strm, strm->state->prev);
+ TRY_FREE(strm, strm->state->window);
+
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+
+ return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK;
+}
+
+/* =========================================================================
+ * Copy the source state to the destination state.
+ * To simplify the source, this is not supported for 16-bit MSDOS (which
+ * doesn't have enough memory anyway to duplicate compression states).
+ */
+int ZEXPORT deflateCopy (dest, source)
+ z_streamp dest;
+ z_streamp source;
+{
+#ifdef MAXSEG_64K
+ return Z_STREAM_ERROR;
+#else
+ deflate_state *ds;
+ deflate_state *ss;
+ ushf *overlay;
+
+
+ if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) {
+ return Z_STREAM_ERROR;
+ }
+
+ ss = source->state;
+
+ zmemcpy(dest, source, sizeof(z_stream));
+
+ ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state));
+ if (ds == Z_NULL) return Z_MEM_ERROR;
+ dest->state = (struct internal_state FAR *) ds;
+ zmemcpy(ds, ss, sizeof(deflate_state));
+ ds->strm = dest;
+
+ ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte));
+ ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos));
+ ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos));
+ overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2);
+ ds->pending_buf = (uchf *) overlay;
+
+ if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL ||
+ ds->pending_buf == Z_NULL) {
+ deflateEnd (dest);
+ return Z_MEM_ERROR;
+ }
+ /* following zmemcpy do not work for 16-bit MSDOS */
+ zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte));
+ zmemcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos));
+ zmemcpy(ds->head, ss->head, ds->hash_size * sizeof(Pos));
+ zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size);
+
+ ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf);
+ ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush);
+ ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize;
+
+ ds->l_desc.dyn_tree = ds->dyn_ltree;
+ ds->d_desc.dyn_tree = ds->dyn_dtree;
+ ds->bl_desc.dyn_tree = ds->bl_tree;
+
+ return Z_OK;
+#endif /* MAXSEG_64K */
+}
+
+/* ===========================================================================
+ * Read a new buffer from the current input stream, update the adler32
+ * and total number of bytes read. All deflate() input goes through
+ * this function so some applications may wish to modify it to avoid
+ * allocating a large strm->next_in buffer and copying from it.
+ * (See also flush_pending()).
+ */
+local int read_buf(strm, buf, size)
+ z_streamp strm;
+ Bytef *buf;
+ unsigned size;
+{
+ unsigned len = strm->avail_in;
+
+ if (len > size) len = size;
+ if (len == 0) return 0;
+
+ strm->avail_in -= len;
+
+ if (strm->state->wrap == 1) {
+ strm->adler = adler32(strm->adler, strm->next_in, len);
+ }
+#ifdef GZIP
+ else if (strm->state->wrap == 2) {
+ strm->adler = crc32(strm->adler, strm->next_in, len);
+ }
+#endif
+ zmemcpy(buf, strm->next_in, len);
+ strm->next_in += len;
+ strm->total_in += len;
+
+ return (int)len;
+}
+
+/* ===========================================================================
+ * Initialize the "longest match" routines for a new zlib stream
+ */
+local void lm_init (s)
+ deflate_state *s;
+{
+ s->window_size = (ulg)2L*s->w_size;
+
+ CLEAR_HASH(s);
+
+ /* Set the default configuration parameters:
+ */
+ s->max_lazy_match = configuration_table[s->level].max_lazy;
+ s->good_match = configuration_table[s->level].good_length;
+ s->nice_match = configuration_table[s->level].nice_length;
+ s->max_chain_length = configuration_table[s->level].max_chain;
+
+ s->strstart = 0;
+ s->block_start = 0L;
+ s->lookahead = 0;
+ s->match_length = s->prev_length = MIN_MATCH-1;
+ s->match_available = 0;
+ s->ins_h = 0;
+#ifndef FASTEST
+#ifdef ASMV
+ match_init(); /* initialize the asm code */
+#endif
+#endif
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Set match_start to the longest match starting at the given string and
+ * return its length. Matches shorter or equal to prev_length are discarded,
+ * in which case the result is equal to prev_length and match_start is
+ * garbage.
+ * IN assertions: cur_match is the head of the hash chain for the current
+ * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
+ * OUT assertion: the match length is not greater than s->lookahead.
+ */
+#ifndef ASMV
+/* For 80x86 and 680x0, an optimized version will be provided in match.asm or
+ * match.S. The code will be functionally equivalent.
+ */
+local uInt longest_match(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ unsigned chain_length = s->max_chain_length;/* max hash chain length */
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ int best_len = s->prev_length; /* best match length so far */
+ int nice_match = s->nice_match; /* stop if match long enough */
+ IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+ s->strstart - (IPos)MAX_DIST(s) : NIL;
+ /* Stop when cur_match becomes <= limit. To simplify the code,
+ * we prevent matches with the string of window index 0.
+ */
+ Posf *prev = s->prev;
+ uInt wmask = s->w_mask;
+
+#ifdef UNALIGNED_OK
+ /* Compare two bytes at a time. Note: this is not always beneficial.
+ * Try with and without -DUNALIGNED_OK to check.
+ */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1;
+ register ush scan_start = *(ushf*)scan;
+ register ush scan_end = *(ushf*)(scan+best_len-1);
+#else
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+ register Byte scan_end1 = scan[best_len-1];
+ register Byte scan_end = scan[best_len];
+#endif
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ /* Do not waste too much time if we already have a good match: */
+ if (s->prev_length >= s->good_match) {
+ chain_length >>= 2;
+ }
+ /* Do not look for matches beyond the end of the input. This is necessary
+ * to make deflate deterministic.
+ */
+ if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ do {
+ Assert(cur_match < s->strstart, "no future");
+ match = s->window + cur_match;
+
+ /* Skip to next match if the match length cannot increase
+ * or if the match length is less than 2. Note that the checks below
+ * for insufficient lookahead only occur occasionally for performance
+ * reasons. Therefore uninitialized memory will be accessed, and
+ * conditional jumps will be made that depend on those values.
+ * However the length of the match is limited to the lookahead, so
+ * the output of deflate is not affected by the uninitialized values.
+ */
+#if (defined(UNALIGNED_OK) && MAX_MATCH == 258)
+ /* This code assumes sizeof(unsigned short) == 2. Do not use
+ * UNALIGNED_OK if your compiler uses a different size.
+ */
+ if (*(ushf*)(match+best_len-1) != scan_end ||
+ *(ushf*)match != scan_start) continue;
+
+ /* It is not necessary to compare scan[2] and match[2] since they are
+ * always equal when the other bytes match, given that the hash keys
+ * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at
+ * strstart+3, +5, ... up to strstart+257. We check for insufficient
+ * lookahead only every 4th comparison; the 128th check will be made
+ * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is
+ * necessary to put more guard bytes at the end of the window, or
+ * to check more often for insufficient lookahead.
+ */
+ Assert(scan[2] == match[2], "scan[2]?");
+ scan++, match++;
+ do {
+ } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ *(ushf*)(scan+=2) == *(ushf*)(match+=2) &&
+ scan < strend);
+ /* The funny "do {}" generates better code on most compilers */
+
+ /* Here, scan <= window+strstart+257 */
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+ if (*scan == *match) scan++;
+
+ len = (MAX_MATCH - 1) - (int)(strend-scan);
+ scan = strend - (MAX_MATCH-1);
+
+#else /* UNALIGNED_OK */
+
+ if (match[best_len] != scan_end ||
+ match[best_len-1] != scan_end1 ||
+ *match != *scan ||
+ *++match != scan[1]) continue;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match++;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+ scan = strend - MAX_MATCH;
+
+#endif /* UNALIGNED_OK */
+
+ if (len > best_len) {
+ s->match_start = cur_match;
+ best_len = len;
+ if (len >= nice_match) break;
+#ifdef UNALIGNED_OK
+ scan_end = *(ushf*)(scan+best_len-1);
+#else
+ scan_end1 = scan[best_len-1];
+ scan_end = scan[best_len];
+#endif
+ }
+ } while ((cur_match = prev[cur_match & wmask]) > limit
+ && --chain_length != 0);
+
+ if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+ return s->lookahead;
+}
+#endif /* ASMV */
+#endif /* FASTEST */
+
+/* ---------------------------------------------------------------------------
+ * Optimized version for level == 1 or strategy == Z_RLE only
+ */
+local uInt longest_match_fast(s, cur_match)
+ deflate_state *s;
+ IPos cur_match; /* current match */
+{
+ register Bytef *scan = s->window + s->strstart; /* current string */
+ register Bytef *match; /* matched string */
+ register int len; /* length of current match */
+ register Bytef *strend = s->window + s->strstart + MAX_MATCH;
+
+ /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
+ * It is easy to get rid of this optimization if necessary.
+ */
+ Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
+
+ Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
+
+ Assert(cur_match < s->strstart, "no future");
+
+ match = s->window + cur_match;
+
+ /* Return failure if the match length is less than 2:
+ */
+ if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1;
+
+ /* The check at best_len-1 can be removed because it will be made
+ * again later. (This heuristic is not always a win.)
+ * It is not necessary to compare scan[2] and match[2] since they
+ * are always equal when the other bytes match, given that
+ * the hash keys are equal and that HASH_BITS >= 8.
+ */
+ scan += 2, match += 2;
+ Assert(*scan == *match, "match[2]?");
+
+ /* We check for insufficient lookahead only every 8th comparison;
+ * the 256th check will be made at strstart+258.
+ */
+ do {
+ } while (*++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ *++scan == *++match && *++scan == *++match &&
+ scan < strend);
+
+ Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
+
+ len = MAX_MATCH - (int)(strend - scan);
+
+ if (len < MIN_MATCH) return MIN_MATCH - 1;
+
+ s->match_start = cur_match;
+ return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead;
+}
+
+#ifdef DEBUG
+/* ===========================================================================
+ * Check that the match at match_start is indeed a match.
+ */
+local void check_match(s, start, match, length)
+ deflate_state *s;
+ IPos start, match;
+ int length;
+{
+ /* check that the match is indeed a match */
+ if (zmemcmp(s->window + match,
+ s->window + start, length) != EQUAL) {
+ fprintf(stderr, " start %u, match %u, length %d\n",
+ start, match, length);
+ do {
+ fprintf(stderr, "%c%c", s->window[match++], s->window[start++]);
+ } while (--length != 0);
+ z_error("invalid match");
+ }
+ if (z_verbose > 1) {
+ fprintf(stderr,"\\[%d,%d]", start-match, length);
+ do { putc(s->window[start++], stderr); } while (--length != 0);
+ }
+}
+#else
+# define check_match(s, start, match, length)
+#endif /* DEBUG */
+
+/* ===========================================================================
+ * Fill the window when the lookahead becomes insufficient.
+ * Updates strstart and lookahead.
+ *
+ * IN assertion: lookahead < MIN_LOOKAHEAD
+ * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
+ * At least one byte has been read, or avail_in == 0; reads are
+ * performed for at least two bytes (required for the zip translate_eol
+ * option -- not supported here).
+ */
+local void fill_window(s)
+ deflate_state *s;
+{
+ register unsigned n, m;
+ register Posf *p;
+ unsigned more; /* Amount of free space at the end of the window. */
+ uInt wsize = s->w_size;
+
+ do {
+ more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart);
+
+ /* Deal with !@#$% 64K limit: */
+ if (sizeof(int) <= 2) {
+ if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
+ more = wsize;
+
+ } else if (more == (unsigned)(-1)) {
+ /* Very unlikely, but possible on 16 bit machine if
+ * strstart == 0 && lookahead == 1 (input done a byte at time)
+ */
+ more--;
+ }
+ }
+
+ /* If the window is almost full and there is insufficient lookahead,
+ * move the upper half to the lower one to make room in the upper half.
+ */
+ if (s->strstart >= wsize+MAX_DIST(s)) {
+
+ zmemcpy(s->window, s->window+wsize, (unsigned)wsize);
+ s->match_start -= wsize;
+ s->strstart -= wsize; /* we now have strstart >= MAX_DIST */
+ s->block_start -= (long) wsize;
+
+ /* Slide the hash table (could be avoided with 32 bit values
+ at the expense of memory usage). We slide even when level == 0
+ to keep the hash table consistent if we switch back to level > 0
+ later. (Using level 0 permanently is not an optimal usage of
+ zlib, so we don't care about this pathological case.)
+ */
+ /* %%% avoid this when Z_RLE */
+ n = s->hash_size;
+ p = &s->head[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ } while (--n);
+
+ n = wsize;
+#ifndef FASTEST
+ p = &s->prev[n];
+ do {
+ m = *--p;
+ *p = (Pos)(m >= wsize ? m-wsize : NIL);
+ /* If n is not on any hash chain, prev[n] is garbage but
+ * its value will never be used.
+ */
+ } while (--n);
+#endif
+ more += wsize;
+ }
+ if (s->strm->avail_in == 0) return;
+
+ /* If there was no sliding:
+ * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
+ * more == window_size - lookahead - strstart
+ * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
+ * => more >= window_size - 2*WSIZE + 2
+ * In the BIG_MEM or MMAP case (not yet supported),
+ * window_size == input_size + MIN_LOOKAHEAD &&
+ * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
+ * Otherwise, window_size == 2*WSIZE so more >= 2.
+ * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
+ */
+ Assert(more >= 2, "more < 2");
+
+ n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more);
+ s->lookahead += n;
+
+ /* Initialize the hash value now that we have some input: */
+ if (s->lookahead >= MIN_MATCH) {
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ }
+ /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
+ * but this is not important since only literal bytes will be emitted.
+ */
+
+ } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0);
+}
+
+/* ===========================================================================
+ * Flush the current block, with given end-of-file flag.
+ * IN assertion: strstart is set to the end of the current match.
+ */
+#define FLUSH_BLOCK_ONLY(s, eof) { \
+ _tr_flush_block(s, (s->block_start >= 0L ? \
+ (charf *)&s->window[(unsigned)s->block_start] : \
+ (charf *)Z_NULL), \
+ (ulg)((long)s->strstart - s->block_start), \
+ (eof)); \
+ s->block_start = s->strstart; \
+ flush_pending(s->strm); \
+ Tracev((stderr,"[FLUSH]")); \
+}
+
+/* Same but force premature exit if necessary. */
+#define FLUSH_BLOCK(s, eof) { \
+ FLUSH_BLOCK_ONLY(s, eof); \
+ if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \
+}
+
+/* ===========================================================================
+ * Copy without compression as much as possible from the input stream, return
+ * the current block state.
+ * This function does not insert new strings in the dictionary since
+ * uncompressible data is probably not useful. This function is used
+ * only for the level=0 compression option.
+ * NOTE: this function should be optimized to avoid extra copying from
+ * window to pending_buf.
+ */
+local block_state deflate_stored(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
+ * to pending_buf_size, and each stored block has a 5 byte header:
+ */
+ ulg max_block_size = 0xffff;
+ ulg max_start;
+
+ if (max_block_size > s->pending_buf_size - 5) {
+ max_block_size = s->pending_buf_size - 5;
+ }
+
+ /* Copy as much as possible from input to output: */
+ for (;;) {
+ /* Fill the window as much as possible: */
+ if (s->lookahead <= 1) {
+
+ Assert(s->strstart < s->w_size+MAX_DIST(s) ||
+ s->block_start >= (long)s->w_size, "slide too late");
+
+ fill_window(s);
+ if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more;
+
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+ Assert(s->block_start >= 0L, "block gone");
+
+ s->strstart += s->lookahead;
+ s->lookahead = 0;
+
+ /* Emit a stored block if pending_buf will be full: */
+ max_start = s->block_start + max_block_size;
+ if (s->strstart == 0 || (ulg)s->strstart >= max_start) {
+ /* strstart == 0 is possible when wraparound on 16-bit machine */
+ s->lookahead = (uInt)(s->strstart - max_start);
+ s->strstart = (uInt)max_start;
+ FLUSH_BLOCK(s, 0);
+ }
+ /* Flush if we may have to slide, otherwise block_start may become
+ * negative and the data will be gone:
+ */
+ if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) {
+ FLUSH_BLOCK(s, 0);
+ }
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+/* ===========================================================================
+ * Compress as much as possible from the input stream, return the current
+ * block state.
+ * This function does not perform lazy evaluation of matches and inserts
+ * new strings in the dictionary only for unmatched strings or for short
+ * matches. It is used only for the fast compression options.
+ */
+local block_state deflate_fast(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of the hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ * At this point we have always match_length < MIN_MATCH
+ */
+ if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+#ifdef FASTEST
+ if ((s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) ||
+ (s->strategy == Z_RLE && s->strstart - hash_head == 1)) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#else
+ if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+#endif
+ /* longest_match() or longest_match_fast() sets match_start */
+ }
+ if (s->match_length >= MIN_MATCH) {
+ check_match(s, s->strstart, s->match_start, s->match_length);
+
+ _tr_tally_dist(s, s->strstart - s->match_start,
+ s->match_length - MIN_MATCH, bflush);
+
+ s->lookahead -= s->match_length;
+
+ /* Insert new strings in the hash table only if the match length
+ * is not too large. This saves time but degrades compression.
+ */
+#ifndef FASTEST
+ if (s->match_length <= s->max_insert_length &&
+ s->lookahead >= MIN_MATCH) {
+ s->match_length--; /* string at strstart already in table */
+ do {
+ s->strstart++;
+ INSERT_STRING(s, s->strstart, hash_head);
+ /* strstart never exceeds WSIZE-MAX_MATCH, so there are
+ * always MIN_MATCH bytes ahead.
+ */
+ } while (--s->match_length != 0);
+ s->strstart++;
+ } else
+#endif
+ {
+ s->strstart += s->match_length;
+ s->match_length = 0;
+ s->ins_h = s->window[s->strstart];
+ UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]);
+#if MIN_MATCH != 3
+ Call UPDATE_HASH() MIN_MATCH-3 more times
+#endif
+ /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
+ * matter since it will be recomputed at next deflate call.
+ */
+ }
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+
+#ifndef FASTEST
+/* ===========================================================================
+ * Same as above, but achieves better compression. We use a lazy
+ * evaluation for matches: a match is finally adopted only if there is
+ * no better match at the next window position.
+ */
+local block_state deflate_slow(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ IPos hash_head = NIL; /* head of hash chain */
+ int bflush; /* set if current block must be flushed */
+
+ /* Process the input block. */
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the next match, plus MIN_MATCH bytes to insert the
+ * string following the next match.
+ */
+ if (s->lookahead < MIN_LOOKAHEAD) {
+ fill_window(s);
+ if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* Insert the string window[strstart .. strstart+2] in the
+ * dictionary, and set hash_head to the head of the hash chain:
+ */
+ if (s->lookahead >= MIN_MATCH) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+
+ /* Find the longest match, discarding those <= prev_length.
+ */
+ s->prev_length = s->match_length, s->prev_match = s->match_start;
+ s->match_length = MIN_MATCH-1;
+
+ if (hash_head != NIL && s->prev_length < s->max_lazy_match &&
+ s->strstart - hash_head <= MAX_DIST(s)) {
+ /* To simplify the code, we prevent matches with the string
+ * of window index 0 (in particular we have to avoid a match
+ * of the string with itself at the start of the input file).
+ */
+ if (s->strategy != Z_HUFFMAN_ONLY && s->strategy != Z_RLE) {
+ s->match_length = longest_match (s, hash_head);
+ } else if (s->strategy == Z_RLE && s->strstart - hash_head == 1) {
+ s->match_length = longest_match_fast (s, hash_head);
+ }
+ /* longest_match() or longest_match_fast() sets match_start */
+
+ if (s->match_length <= 5 && (s->strategy == Z_FILTERED
+#if TOO_FAR <= 32767
+ || (s->match_length == MIN_MATCH &&
+ s->strstart - s->match_start > TOO_FAR)
+#endif
+ )) {
+
+ /* If prev_match is also MIN_MATCH, match_start is garbage
+ * but we will ignore the current match anyway.
+ */
+ s->match_length = MIN_MATCH-1;
+ }
+ }
+ /* If there was a match at the previous step and the current
+ * match is not better, output the previous match:
+ */
+ if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) {
+ uInt max_insert = s->strstart + s->lookahead - MIN_MATCH;
+ /* Do not insert strings in hash table beyond this. */
+
+ check_match(s, s->strstart-1, s->prev_match, s->prev_length);
+
+ _tr_tally_dist(s, s->strstart -1 - s->prev_match,
+ s->prev_length - MIN_MATCH, bflush);
+
+ /* Insert in hash table all strings up to the end of the match.
+ * strstart-1 and strstart are already inserted. If there is not
+ * enough lookahead, the last two strings are not inserted in
+ * the hash table.
+ */
+ s->lookahead -= s->prev_length-1;
+ s->prev_length -= 2;
+ do {
+ if (++s->strstart <= max_insert) {
+ INSERT_STRING(s, s->strstart, hash_head);
+ }
+ } while (--s->prev_length != 0);
+ s->match_available = 0;
+ s->match_length = MIN_MATCH-1;
+ s->strstart++;
+
+ if (bflush) FLUSH_BLOCK(s, 0);
+
+ } else if (s->match_available) {
+ /* If there was no match at the previous position, output a
+ * single literal. If there was a match but the current match
+ * is longer, truncate the previous match to a single literal.
+ */
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ if (bflush) {
+ FLUSH_BLOCK_ONLY(s, 0);
+ }
+ s->strstart++;
+ s->lookahead--;
+ if (s->strm->avail_out == 0) return need_more;
+ } else {
+ /* There is no previous match to compare with, wait for
+ * the next step to decide.
+ */
+ s->match_available = 1;
+ s->strstart++;
+ s->lookahead--;
+ }
+ }
+ Assert (flush != Z_NO_FLUSH, "no flush?");
+ if (s->match_available) {
+ Tracevv((stderr,"%c", s->window[s->strstart-1]));
+ _tr_tally_lit(s, s->window[s->strstart-1], bflush);
+ s->match_available = 0;
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif /* FASTEST */
+
+#if 0
+/* ===========================================================================
+ * For Z_RLE, simply look for runs of bytes, generate matches only of distance
+ * one. Do not maintain a hash table. (It will be regenerated if this run of
+ * deflate switches away from Z_RLE.)
+ */
+local block_state deflate_rle(s, flush)
+ deflate_state *s;
+ int flush;
+{
+ int bflush; /* set if current block must be flushed */
+ uInt run; /* length of run */
+ uInt max; /* maximum length of run */
+ uInt prev; /* byte at distance one to match */
+ Bytef *scan; /* scan for end of run */
+
+ for (;;) {
+ /* Make sure that we always have enough lookahead, except
+ * at the end of the input file. We need MAX_MATCH bytes
+ * for the longest encodable run.
+ */
+ if (s->lookahead < MAX_MATCH) {
+ fill_window(s);
+ if (s->lookahead < MAX_MATCH && flush == Z_NO_FLUSH) {
+ return need_more;
+ }
+ if (s->lookahead == 0) break; /* flush the current block */
+ }
+
+ /* See how many times the previous byte repeats */
+ run = 0;
+ if (s->strstart > 0) { /* if there is a previous byte, that is */
+ max = s->lookahead < MAX_MATCH ? s->lookahead : MAX_MATCH;
+ scan = s->window + s->strstart - 1;
+ prev = *scan++;
+ do {
+ if (*scan++ != prev)
+ break;
+ } while (++run < max);
+ }
+
+ /* Emit match if have run of MIN_MATCH or longer, else emit literal */
+ if (run >= MIN_MATCH) {
+ check_match(s, s->strstart, s->strstart - 1, run);
+ _tr_tally_dist(s, 1, run - MIN_MATCH, bflush);
+ s->lookahead -= run;
+ s->strstart += run;
+ } else {
+ /* No match, output a literal byte */
+ Tracevv((stderr,"%c", s->window[s->strstart]));
+ _tr_tally_lit (s, s->window[s->strstart], bflush);
+ s->lookahead--;
+ s->strstart++;
+ }
+ if (bflush) FLUSH_BLOCK(s, 0);
+ }
+ FLUSH_BLOCK(s, flush == Z_FINISH);
+ return flush == Z_FINISH ? finish_done : block_done;
+}
+#endif
diff --git a/src/lib/zlib/deflate.h b/src/lib/zlib/deflate.h
new file mode 100644
index 00000000000..05a5ab3a2c1
--- /dev/null
+++ b/src/lib/zlib/deflate.h
@@ -0,0 +1,331 @@
+/* deflate.h -- internal compression state
+ * Copyright (C) 1995-2004 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef DEFLATE_H
+#define DEFLATE_H
+
+#include "zutil.h"
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer creation by deflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip encoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GZIP
+#endif
+
+/* ===========================================================================
+ * Internal compression state.
+ */
+
+#define LENGTH_CODES 29
+/* number of length codes, not counting the special END_BLOCK code */
+
+#define LITERALS 256
+/* number of literal bytes 0..255 */
+
+#define L_CODES (LITERALS+1+LENGTH_CODES)
+/* number of Literal or Length codes, including the END_BLOCK code */
+
+#define D_CODES 30
+/* number of distance codes */
+
+#define BL_CODES 19
+/* number of codes used to transfer the bit lengths */
+
+#define HEAP_SIZE (2*L_CODES+1)
+/* maximum heap size */
+
+#define MAX_BITS 15
+/* All codes must not exceed MAX_BITS bits */
+
+#define INIT_STATE 42
+#define EXTRA_STATE 69
+#define NAME_STATE 73
+#define COMMENT_STATE 91
+#define HCRC_STATE 103
+#define BUSY_STATE 113
+#define FINISH_STATE 666
+/* Stream status */
+
+
+/* Data structure describing a single value and its code string. */
+typedef struct ct_data_s {
+ union {
+ ush freq; /* frequency count */
+ ush code; /* bit string */
+ } fc;
+ union {
+ ush dad; /* father node in Huffman tree */
+ ush len; /* length of bit string */
+ } dl;
+} FAR ct_data;
+
+#define Freq fc.freq
+#define Code fc.code
+#define Dad dl.dad
+#define Len dl.len
+
+typedef struct static_tree_desc_s static_tree_desc;
+
+typedef struct tree_desc_s {
+ ct_data *dyn_tree; /* the dynamic tree */
+ int max_code; /* largest code with non zero frequency */
+ static_tree_desc *stat_desc; /* the corresponding static tree */
+} FAR tree_desc;
+
+typedef ush Pos;
+typedef Pos FAR Posf;
+typedef unsigned IPos;
+
+/* A Pos is an index in the character window. We use short instead of int to
+ * save space in the various tables. IPos is used only for parameter passing.
+ */
+
+typedef struct internal_state {
+ z_streamp strm; /* pointer back to this zlib stream */
+ int status; /* as the name implies */
+ Bytef *pending_buf; /* output still pending */
+ ulg pending_buf_size; /* size of pending_buf */
+ Bytef *pending_out; /* next pending byte to output to the stream */
+ uInt pending; /* nb of bytes in the pending buffer */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ gz_headerp gzhead; /* gzip header information to write */
+ uInt gzindex; /* where in extra, name, or comment */
+ Byte method; /* STORED (for zip only) or DEFLATED */
+ int last_flush; /* value of flush param for previous deflate call */
+
+ /* used by deflate.c: */
+
+ uInt w_size; /* LZ77 window size (32K by default) */
+ uInt w_bits; /* log2(w_size) (8..16) */
+ uInt w_mask; /* w_size - 1 */
+
+ Bytef *window;
+ /* Sliding window. Input bytes are read into the second half of the window,
+ * and move to the first half later to keep a dictionary of at least wSize
+ * bytes. With this organization, matches are limited to a distance of
+ * wSize-MAX_MATCH bytes, but this ensures that IO is always
+ * performed with a length multiple of the block size. Also, it limits
+ * the window size to 64K, which is quite useful on MSDOS.
+ * To do: use the user input buffer as sliding window.
+ */
+
+ ulg window_size;
+ /* Actual size of window: 2*wSize, except when the user input buffer
+ * is directly used as sliding window.
+ */
+
+ Posf *prev;
+ /* Link to older string with same hash index. To limit the size of this
+ * array to 64K, this link is maintained only for the last 32K strings.
+ * An index in this array is thus a window index modulo 32K.
+ */
+
+ Posf *head; /* Heads of the hash chains or NIL. */
+
+ uInt ins_h; /* hash index of string to be inserted */
+ uInt hash_size; /* number of elements in hash table */
+ uInt hash_bits; /* log2(hash_size) */
+ uInt hash_mask; /* hash_size-1 */
+
+ uInt hash_shift;
+ /* Number of bits by which ins_h must be shifted at each input
+ * step. It must be such that after MIN_MATCH steps, the oldest
+ * byte no longer takes part in the hash key, that is:
+ * hash_shift * MIN_MATCH >= hash_bits
+ */
+
+ long block_start;
+ /* Window position at the beginning of the current output block. Gets
+ * negative when the window is moved backwards.
+ */
+
+ uInt match_length; /* length of best match */
+ IPos prev_match; /* previous match */
+ int match_available; /* set if previous match exists */
+ uInt strstart; /* start of string to insert */
+ uInt match_start; /* start of matching string */
+ uInt lookahead; /* number of valid bytes ahead in window */
+
+ uInt prev_length;
+ /* Length of the best match at previous step. Matches not greater than this
+ * are discarded. This is used in the lazy match evaluation.
+ */
+
+ uInt max_chain_length;
+ /* To speed up deflation, hash chains are never searched beyond this
+ * length. A higher limit improves compression ratio but degrades the
+ * speed.
+ */
+
+ uInt max_lazy_match;
+ /* Attempt to find a better match only when the current match is strictly
+ * smaller than this value. This mechanism is used only for compression
+ * levels >= 4.
+ */
+# define max_insert_length max_lazy_match
+ /* Insert new strings in the hash table only if the match length is not
+ * greater than this length. This saves time but degrades compression.
+ * max_insert_length is used only for compression levels <= 3.
+ */
+
+ int level; /* compression level (1..9) */
+ int strategy; /* favor or force Huffman coding*/
+
+ uInt good_match;
+ /* Use a faster search when the previous match is longer than this */
+
+ int nice_match; /* Stop searching when current match exceeds this */
+
+ /* used by trees.c: */
+ /* Didn't use ct_data typedef below to supress compiler warning */
+ struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
+ struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
+ struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
+
+ struct tree_desc_s l_desc; /* desc. for literal tree */
+ struct tree_desc_s d_desc; /* desc. for distance tree */
+ struct tree_desc_s bl_desc; /* desc. for bit length tree */
+
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
+ int heap_len; /* number of elements in the heap */
+ int heap_max; /* element of largest frequency */
+ /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
+ * The same heap array is used to build all trees.
+ */
+
+ uch depth[2*L_CODES+1];
+ /* Depth of each subtree used as tie breaker for trees of equal frequency
+ */
+
+ uchf *l_buf; /* buffer for literals or lengths */
+
+ uInt lit_bufsize;
+ /* Size of match buffer for literals/lengths. There are 4 reasons for
+ * limiting lit_bufsize to 64K:
+ * - frequencies can be kept in 16 bit counters
+ * - if compression is not successful for the first block, all input
+ * data is still in the window so we can still emit a stored block even
+ * when input comes from standard input. (This can also be done for
+ * all blocks if lit_bufsize is not greater than 32K.)
+ * - if compression is not successful for a file smaller than 64K, we can
+ * even emit a stored file instead of a stored block (saving 5 bytes).
+ * This is applicable only for zip (not gzip or zlib).
+ * - creating new Huffman trees less frequently may not provide fast
+ * adaptation to changes in the input data statistics. (Take for
+ * example a binary file with poorly compressible code followed by
+ * a highly compressible string table.) Smaller buffer sizes give
+ * fast adaptation but have of course the overhead of transmitting
+ * trees more frequently.
+ * - I can't count above 4
+ */
+
+ uInt last_lit; /* running index in l_buf */
+
+ ushf *d_buf;
+ /* Buffer for distances. To simplify the code, d_buf and l_buf have
+ * the same number of elements. To use different lengths, an extra flag
+ * array would be necessary.
+ */
+
+ ulg opt_len; /* bit length of current block with optimal trees */
+ ulg static_len; /* bit length of current block with static trees */
+ uInt matches; /* number of string matches in current block */
+ int last_eob_len; /* bit length of EOB code for last block */
+
+#ifdef DEBUG
+ ulg compressed_len; /* total bit length of compressed file mod 2^32 */
+ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
+#endif
+
+ ush bi_buf;
+ /* Output buffer. bits are inserted starting at the bottom (least
+ * significant bits).
+ */
+ int bi_valid;
+ /* Number of valid bits in bi_buf. All bits above the last valid bit
+ * are always zero.
+ */
+
+} FAR deflate_state;
+
+/* Output a byte on the stream.
+ * IN assertion: there is enough room in pending_buf.
+ */
+#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);}
+
+
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+/* Minimum amount of lookahead, except at the end of the input file.
+ * See deflate.c for comments about the MIN_MATCH+1.
+ */
+
+#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD)
+/* In order to simplify the code, particularly on 16 bit machines, match
+ * distances are limited to MAX_DIST instead of WSIZE.
+ */
+
+ /* in trees.c */
+void _tr_init OF((deflate_state *s));
+int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc));
+void _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+void _tr_align OF((deflate_state *s));
+void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len,
+ int eof));
+
+#define d_code(dist) \
+ ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)])
+/* Mapping from a distance to a distance code. dist is the distance - 1 and
+ * must not have side effects. _dist_code[256] and _dist_code[257] are never
+ * used.
+ */
+
+#ifndef DEBUG
+/* Inline versions of _tr_tally for speed: */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+ extern uch _length_code[];
+ extern uch _dist_code[];
+#else
+ extern const uch _length_code[];
+ extern const uch _dist_code[];
+#endif
+
+# define _tr_tally_lit(s, c, flush) \
+ { uch cc = (c); \
+ s->d_buf[s->last_lit] = 0; \
+ s->l_buf[s->last_lit++] = cc; \
+ s->dyn_ltree[cc].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+# define _tr_tally_dist(s, distance, length, flush) \
+ { uch len = (length); \
+ ush dist = (distance); \
+ s->d_buf[s->last_lit] = dist; \
+ s->l_buf[s->last_lit++] = len; \
+ dist--; \
+ s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \
+ s->dyn_dtree[d_code(dist)].Freq++; \
+ flush = (s->last_lit == s->lit_bufsize-1); \
+ }
+#else
+# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c)
+# define _tr_tally_dist(s, distance, length, flush) \
+ flush = _tr_tally(s, distance, length)
+#endif
+
+#endif /* DEFLATE_H */
diff --git a/src/lib/zlib/example.c b/src/lib/zlib/example.c
new file mode 100644
index 00000000000..6c8a0ee7633
--- /dev/null
+++ b/src/lib/zlib/example.c
@@ -0,0 +1,565 @@
+/* example.c -- usage example of the zlib compression library
+ * Copyright (C) 1995-2004 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#if defined(VMS) || defined(RISCOS)
+# define TESTFILE "foo-gz"
+#else
+# define TESTFILE "foo.gz"
+#endif
+
+#define CHECK_ERR(err, msg) { \
+ if (err != Z_OK) { \
+ fprintf(stderr, "%s error: %d\n", msg, err); \
+ exit(1); \
+ } \
+}
+
+const char hello[] = "hello, hello!";
+/* "hello world" would be more standard, but the repeated "hello"
+ * stresses the compression code better, sorry...
+ */
+
+const char dictionary[] = "hello";
+uLong dictId; /* Adler32 value of the dictionary */
+
+void test_compress OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_gzio OF((const char *fname,
+ Byte *uncompr, uLong uncomprLen));
+void test_deflate OF((Byte *compr, uLong comprLen));
+void test_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_large_deflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_large_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_flush OF((Byte *compr, uLong *comprLen));
+void test_sync OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+void test_dict_deflate OF((Byte *compr, uLong comprLen));
+void test_dict_inflate OF((Byte *compr, uLong comprLen,
+ Byte *uncompr, uLong uncomprLen));
+int main OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Test compress() and uncompress()
+ */
+void test_compress(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ uLong len = (uLong)strlen(hello)+1;
+
+ err = compress(compr, &comprLen, (const Bytef*)hello, len);
+ CHECK_ERR(err, "compress");
+
+ strcpy((char*)uncompr, "garbage");
+
+ err = uncompress(uncompr, &uncomprLen, compr, comprLen);
+ CHECK_ERR(err, "uncompress");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad uncompress\n");
+ exit(1);
+ } else {
+ printf("uncompress(): %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test read/write of .gz files
+ */
+void test_gzio(fname, uncompr, uncomprLen)
+ const char *fname; /* compressed file name */
+ Byte *uncompr;
+ uLong uncomprLen;
+{
+#ifdef NO_GZCOMPRESS
+ fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");
+#else
+ int err;
+ int len = (int)strlen(hello)+1;
+ gzFile file;
+ z_off_t pos;
+
+ file = gzopen(fname, "wb");
+ if (file == NULL) {
+ fprintf(stderr, "gzopen error\n");
+ exit(1);
+ }
+ gzputc(file, 'h');
+ if (gzputs(file, "ello") != 4) {
+ fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (gzprintf(file, ", %s!", "hello") != 8) {
+ fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ gzseek(file, 1L, SEEK_CUR); /* add one zero byte */
+ gzclose(file);
+
+ file = gzopen(fname, "rb");
+ if (file == NULL) {
+ fprintf(stderr, "gzopen error\n");
+ exit(1);
+ }
+ strcpy((char*)uncompr, "garbage");
+
+ if (gzread(file, uncompr, (unsigned)uncomprLen) != len) {
+ fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad gzread: %s\n", (char*)uncompr);
+ exit(1);
+ } else {
+ printf("gzread(): %s\n", (char*)uncompr);
+ }
+
+ pos = gzseek(file, -8L, SEEK_CUR);
+ if (pos != 6 || gztell(file) != pos) {
+ fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n",
+ (long)pos, (long)gztell(file));
+ exit(1);
+ }
+
+ if (gzgetc(file) != ' ') {
+ fprintf(stderr, "gzgetc error\n");
+ exit(1);
+ }
+
+ if (gzungetc(' ', file) != ' ') {
+ fprintf(stderr, "gzungetc error\n");
+ exit(1);
+ }
+
+ gzgets(file, (char*)uncompr, (int)uncomprLen);
+ if (strlen((char*)uncompr) != 7) { /* " hello!" */
+ fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err));
+ exit(1);
+ }
+ if (strcmp((char*)uncompr, hello + 6)) {
+ fprintf(stderr, "bad gzgets after gzseek\n");
+ exit(1);
+ } else {
+ printf("gzgets() after gzseek: %s\n", (char*)uncompr);
+ }
+
+ gzclose(file);
+#endif
+}
+
+/* ===========================================================================
+ * Test deflate() with small buffers
+ */
+void test_deflate(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+ uLong len = (uLong)strlen(hello)+1;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.next_out = compr;
+
+ while (c_stream.total_in != len && c_stream.total_out < comprLen) {
+ c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+ }
+ /* Finish the stream, still forcing small buffers: */
+ for (;;) {
+ c_stream.avail_out = 1;
+ err = deflate(&c_stream, Z_FINISH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "deflate");
+ }
+
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with small buffers
+ */
+void test_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = 0;
+ d_stream.next_out = uncompr;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) {
+ d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "inflate");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad inflate\n");
+ exit(1);
+ } else {
+ printf("inflate(): %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with large buffers and dynamic change of compression level
+ */
+void test_large_deflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_BEST_SPEED);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_out = compr;
+ c_stream.avail_out = (uInt)comprLen;
+
+ /* At this point, uncompr is still mostly zeroes, so it should compress
+ * very well:
+ */
+ c_stream.next_in = uncompr;
+ c_stream.avail_in = (uInt)uncomprLen;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+ if (c_stream.avail_in != 0) {
+ fprintf(stderr, "deflate not greedy\n");
+ exit(1);
+ }
+
+ /* Feed in already compressed data and switch to no compression: */
+ deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
+ c_stream.next_in = compr;
+ c_stream.avail_in = (uInt)comprLen/2;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ /* Switch back to compressing mode: */
+ deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
+ c_stream.next_in = uncompr;
+ c_stream.avail_in = (uInt)uncomprLen;
+ err = deflate(&c_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ fprintf(stderr, "deflate should report Z_STREAM_END\n");
+ exit(1);
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with large buffers
+ */
+void test_large_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ for (;;) {
+ d_stream.next_out = uncompr; /* discard the output */
+ d_stream.avail_out = (uInt)uncomprLen;
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ CHECK_ERR(err, "large inflate");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (d_stream.total_out != 2*uncomprLen + comprLen/2) {
+ fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);
+ exit(1);
+ } else {
+ printf("large_inflate(): OK\n");
+ }
+}
+
+/* ===========================================================================
+ * Test deflate() with full flush
+ */
+void test_flush(compr, comprLen)
+ Byte *compr;
+ uLong *comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+ uInt len = (uInt)strlen(hello)+1;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.next_out = compr;
+ c_stream.avail_in = 3;
+ c_stream.avail_out = (uInt)*comprLen;
+ err = deflate(&c_stream, Z_FULL_FLUSH);
+ CHECK_ERR(err, "deflate");
+
+ compr[3]++; /* force an error in first compressed block */
+ c_stream.avail_in = len - 3;
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ CHECK_ERR(err, "deflate");
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+
+ *comprLen = c_stream.total_out;
+}
+
+/* ===========================================================================
+ * Test inflateSync()
+ */
+void test_sync(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = 2; /* just read the zlib header */
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_out = uncompr;
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ inflate(&d_stream, Z_NO_FLUSH);
+ CHECK_ERR(err, "inflate");
+
+ d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */
+ err = inflateSync(&d_stream); /* but skip the damaged part */
+ CHECK_ERR(err, "inflateSync");
+
+ err = inflate(&d_stream, Z_FINISH);
+ if (err != Z_DATA_ERROR) {
+ fprintf(stderr, "inflate should report DATA_ERROR\n");
+ /* Because of incorrect adler32 */
+ exit(1);
+ }
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ printf("after inflateSync(): hel%s\n", (char *)uncompr);
+}
+
+/* ===========================================================================
+ * Test deflate() with preset dictionary
+ */
+void test_dict_deflate(compr, comprLen)
+ Byte *compr;
+ uLong comprLen;
+{
+ z_stream c_stream; /* compression stream */
+ int err;
+
+ c_stream.zalloc = (alloc_func)0;
+ c_stream.zfree = (free_func)0;
+ c_stream.opaque = (voidpf)0;
+
+ err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
+ CHECK_ERR(err, "deflateInit");
+
+ err = deflateSetDictionary(&c_stream,
+ (const Bytef*)dictionary, sizeof(dictionary));
+ CHECK_ERR(err, "deflateSetDictionary");
+
+ dictId = c_stream.adler;
+ c_stream.next_out = compr;
+ c_stream.avail_out = (uInt)comprLen;
+
+ c_stream.next_in = (Bytef*)hello;
+ c_stream.avail_in = (uInt)strlen(hello)+1;
+
+ err = deflate(&c_stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ fprintf(stderr, "deflate should report Z_STREAM_END\n");
+ exit(1);
+ }
+ err = deflateEnd(&c_stream);
+ CHECK_ERR(err, "deflateEnd");
+}
+
+/* ===========================================================================
+ * Test inflate() with a preset dictionary
+ */
+void test_dict_inflate(compr, comprLen, uncompr, uncomprLen)
+ Byte *compr, *uncompr;
+ uLong comprLen, uncomprLen;
+{
+ int err;
+ z_stream d_stream; /* decompression stream */
+
+ strcpy((char*)uncompr, "garbage");
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+
+ d_stream.next_in = compr;
+ d_stream.avail_in = (uInt)comprLen;
+
+ err = inflateInit(&d_stream);
+ CHECK_ERR(err, "inflateInit");
+
+ d_stream.next_out = uncompr;
+ d_stream.avail_out = (uInt)uncomprLen;
+
+ for (;;) {
+ err = inflate(&d_stream, Z_NO_FLUSH);
+ if (err == Z_STREAM_END) break;
+ if (err == Z_NEED_DICT) {
+ if (d_stream.adler != dictId) {
+ fprintf(stderr, "unexpected dictionary");
+ exit(1);
+ }
+ err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary,
+ sizeof(dictionary));
+ }
+ CHECK_ERR(err, "inflate with dict");
+ }
+
+ err = inflateEnd(&d_stream);
+ CHECK_ERR(err, "inflateEnd");
+
+ if (strcmp((char*)uncompr, hello)) {
+ fprintf(stderr, "bad inflate with dict\n");
+ exit(1);
+ } else {
+ printf("inflate with dictionary: %s\n", (char *)uncompr);
+ }
+}
+
+/* ===========================================================================
+ * Usage: example [output.gz [input.gz]]
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ Byte *compr, *uncompr;
+ uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */
+ uLong uncomprLen = comprLen;
+ static const char* myVersion = ZLIB_VERSION;
+
+ if (zlibVersion()[0] != myVersion[0]) {
+ fprintf(stderr, "incompatible zlib version\n");
+ exit(1);
+
+ } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
+ fprintf(stderr, "warning: different zlib version\n");
+ }
+
+ printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n",
+ ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags());
+
+ compr = (Byte*)calloc((uInt)comprLen, 1);
+ uncompr = (Byte*)calloc((uInt)uncomprLen, 1);
+ /* compr and uncompr are cleared to avoid reading uninitialized
+ * data and to ensure that uncompr compresses well.
+ */
+ if (compr == Z_NULL || uncompr == Z_NULL) {
+ printf("out of memory\n");
+ exit(1);
+ }
+ test_compress(compr, comprLen, uncompr, uncomprLen);
+
+ test_gzio((argc > 1 ? argv[1] : TESTFILE),
+ uncompr, uncomprLen);
+
+ test_deflate(compr, comprLen);
+ test_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ test_large_deflate(compr, comprLen, uncompr, uncomprLen);
+ test_large_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ test_flush(compr, &comprLen);
+ test_sync(compr, comprLen, uncompr, uncomprLen);
+ comprLen = uncomprLen;
+
+ test_dict_deflate(compr, comprLen);
+ test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
+
+ free(compr);
+ free(uncompr);
+
+ return 0;
+}
diff --git a/src/lib/zlib/gzio.c b/src/lib/zlib/gzio.c
new file mode 100644
index 00000000000..7e90f4928fc
--- /dev/null
+++ b/src/lib/zlib/gzio.c
@@ -0,0 +1,1026 @@
+/* gzio.c -- IO on .gz files
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Compile this file with -DNO_GZCOMPRESS to avoid the compression code.
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+
+#include "zutil.h"
+
+#ifdef NO_DEFLATE /* for compatibility with old definition */
+# define NO_GZCOMPRESS
+#endif
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+#ifndef Z_BUFSIZE
+# ifdef MAXSEG_64K
+# define Z_BUFSIZE 4096 /* minimize memory usage for 16-bit DOS */
+# else
+# define Z_BUFSIZE 16384
+# endif
+#endif
+#ifndef Z_PRINTF_BUFSIZE
+# define Z_PRINTF_BUFSIZE 4096
+#endif
+
+#ifdef __MVS__
+# pragma map (fdopen , "\174\174FDOPEN")
+ FILE *fdopen(int, const char *);
+#endif
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+#define ALLOC(size) malloc(size)
+#define TRYFREE(p) {if (p) free(p);}
+
+static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+typedef struct gz_stream {
+ z_stream stream;
+ int z_err; /* error code for last stream operation */
+ int z_eof; /* set if end of input file */
+ FILE *file; /* .gz file */
+ Byte *inbuf; /* input buffer */
+ Byte *outbuf; /* output buffer */
+ uLong crc; /* crc32 of uncompressed data */
+ char *msg; /* error message */
+ char *path; /* path name for debugging only */
+ int transparent; /* 1 if input file is not a .gz file */
+ char mode; /* 'w' or 'r' */
+ z_off_t start; /* start of compressed data in file (header skipped) */
+ z_off_t in; /* bytes into deflate or inflate */
+ z_off_t out; /* bytes out of deflate or inflate */
+ int back; /* one character push-back */
+ int last; /* true if push-back is last character */
+} gz_stream;
+
+
+local gzFile gz_open OF((const char *path, const char *mode, int fd));
+local int do_flush OF((gzFile file, int flush));
+local int get_byte OF((gz_stream *s));
+local void check_header OF((gz_stream *s));
+local int destroy OF((gz_stream *s));
+local void putLong OF((FILE *file, uLong x));
+local uLong getLong OF((gz_stream *s));
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb"). The file is given either by file descriptor
+ or path name (if fd == -1).
+ gz_open returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR).
+*/
+local gzFile gz_open (path, mode, fd)
+ const char *path;
+ const char *mode;
+ int fd;
+{
+ int err;
+ int level = Z_DEFAULT_COMPRESSION; /* compression level */
+ int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
+ char *p = (char*)mode;
+ gz_stream *s;
+ char fmode[80]; /* copy of mode, without the compression level */
+ char *m = fmode;
+
+ if (!path || !mode) return Z_NULL;
+
+ s = (gz_stream *)ALLOC(sizeof(gz_stream));
+ if (!s) return Z_NULL;
+
+ s->stream.zalloc = (alloc_func)0;
+ s->stream.zfree = (free_func)0;
+ s->stream.opaque = (voidpf)0;
+ s->stream.next_in = s->inbuf = Z_NULL;
+ s->stream.next_out = s->outbuf = Z_NULL;
+ s->stream.avail_in = s->stream.avail_out = 0;
+ s->file = NULL;
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->in = 0;
+ s->out = 0;
+ s->back = EOF;
+ s->crc = crc32(0L, Z_NULL, 0);
+ s->msg = NULL;
+ s->transparent = 0;
+
+ s->path = (char*)ALLOC(strlen(path)+1);
+ if (s->path == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ strcpy(s->path, path); /* do this early for debugging */
+
+ s->mode = '\0';
+ do {
+ if (*p == 'r') s->mode = 'r';
+ if (*p == 'w' || *p == 'a') s->mode = 'w';
+ if (*p >= '0' && *p <= '9') {
+ level = *p - '0';
+ } else if (*p == 'f') {
+ strategy = Z_FILTERED;
+ } else if (*p == 'h') {
+ strategy = Z_HUFFMAN_ONLY;
+ } else if (*p == 'R') {
+ strategy = Z_RLE;
+ } else {
+ *m++ = *p; /* copy the mode */
+ }
+ } while (*p++ && m != fmode + sizeof(fmode));
+ if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL;
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateInit2(&(s->stream), level,
+ Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, strategy);
+ /* windowBits is passed < 0 to suppress zlib header */
+
+ s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+#endif
+ if (err != Z_OK || s->outbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ } else {
+ s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE);
+
+ err = inflateInit2(&(s->stream), -MAX_WBITS);
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
+ * present after the compressed stream.
+ */
+ if (err != Z_OK || s->inbuf == Z_NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+
+ errno = 0;
+ s->file = fd < 0 ? F_OPEN(path, fmode) : (FILE*)fdopen(fd, fmode);
+
+ if (s->file == NULL) {
+ return destroy(s), (gzFile)Z_NULL;
+ }
+ if (s->mode == 'w') {
+ /* Write a very simple .gz header:
+ */
+ fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1],
+ Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE);
+ s->start = 10L;
+ /* We use 10L instead of ftell(s->file) to because ftell causes an
+ * fflush on some systems. This version of the library doesn't use
+ * start anyway in write mode, so this initialization is not
+ * necessary.
+ */
+ } else {
+ check_header(s); /* skip the .gz header */
+ s->start = ftell(s->file) - s->stream.avail_in;
+ }
+
+ return (gzFile)s;
+}
+
+/* ===========================================================================
+ Opens a gzip (.gz) file for reading or writing.
+*/
+gzFile ZEXPORT gzopen (path, mode)
+ const char *path;
+ const char *mode;
+{
+ return gz_open (path, mode, -1);
+}
+
+/* ===========================================================================
+ Associate a gzFile with the file descriptor fd. fd is not dup'ed here
+ to mimic the behavio(u)r of fdopen.
+*/
+gzFile ZEXPORT gzdopen (fd, mode)
+ int fd;
+ const char *mode;
+{
+ char name[46]; /* allow for up to 128-bit integers */
+
+ if (fd < 0) return (gzFile)Z_NULL;
+ sprintf(name, "<fd:%d>", fd); /* for debugging */
+
+ return gz_open (name, mode, fd);
+}
+
+/* ===========================================================================
+ * Update the compression level and strategy
+ */
+int ZEXPORT gzsetparams (file, level, strategy)
+ gzFile file;
+ int level;
+ int strategy;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ /* Make room to allow flushing */
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+
+ return deflateParams (&(s->stream), level, strategy);
+}
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+local int get_byte(s)
+ gz_stream *s;
+{
+ if (s->z_eof) return EOF;
+ if (s->stream.avail_in == 0) {
+ errno = 0;
+ s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) s->z_err = Z_ERRNO;
+ return EOF;
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->stream.avail_in--;
+ return *(s->stream.next_in)++;
+}
+
+/* ===========================================================================
+ Check the gzip header of a gz_stream opened for reading. Set the stream
+ mode to transparent if the gzip magic header is not present; set s->err
+ to Z_DATA_ERROR if the magic header is present but the rest of the header
+ is incorrect.
+ IN assertion: the stream s has already been created sucessfully;
+ s->stream.avail_in is zero for the first time, but may be non-zero
+ for concatenated .gz files.
+*/
+local void check_header(s)
+ gz_stream *s;
+{
+ int method; /* method byte */
+ int flags; /* flags byte */
+ uInt len;
+ int c;
+
+ /* Assure two bytes in the buffer so we can peek ahead -- handle case
+ where first byte of header is at the end of the buffer after the last
+ gzip segment */
+ len = s->stream.avail_in;
+ if (len < 2) {
+ if (len) s->inbuf[0] = s->stream.next_in[0];
+ errno = 0;
+ len = (uInt)fread(s->inbuf + len, 1, Z_BUFSIZE >> len, s->file);
+ if (len == 0 && ferror(s->file)) s->z_err = Z_ERRNO;
+ s->stream.avail_in += len;
+ s->stream.next_in = s->inbuf;
+ if (s->stream.avail_in < 2) {
+ s->transparent = s->stream.avail_in;
+ return;
+ }
+ }
+
+ /* Peek ahead to check the gzip magic header */
+ if (s->stream.next_in[0] != gz_magic[0] ||
+ s->stream.next_in[1] != gz_magic[1]) {
+ s->transparent = 1;
+ return;
+ }
+ s->stream.avail_in -= 2;
+ s->stream.next_in += 2;
+
+ /* Check the rest of the gzip header */
+ method = get_byte(s);
+ flags = get_byte(s);
+ if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ s->z_err = Z_DATA_ERROR;
+ return;
+ }
+
+ /* Discard time, xflags and OS code: */
+ for (len = 0; len < 6; len++) (void)get_byte(s);
+
+ if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
+ len = (uInt)get_byte(s);
+ len += ((uInt)get_byte(s))<<8;
+ /* len is garbage if EOF but the loop below will quit anyway */
+ while (len-- != 0 && get_byte(s) != EOF) ;
+ }
+ if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
+ while ((c = get_byte(s)) != 0 && c != EOF) ;
+ }
+ if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
+ for (len = 0; len < 2; len++) (void)get_byte(s);
+ }
+ s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
+}
+
+ /* ===========================================================================
+ * Cleanup then free the given gz_stream. Return a zlib error code.
+ Try freeing in the reverse order of allocations.
+ */
+local int destroy (s)
+ gz_stream *s;
+{
+ int err = Z_OK;
+
+ if (!s) return Z_STREAM_ERROR;
+
+ TRYFREE(s->msg);
+
+ if (s->stream.state != NULL) {
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ err = Z_STREAM_ERROR;
+#else
+ err = deflateEnd(&(s->stream));
+#endif
+ } else if (s->mode == 'r') {
+ err = inflateEnd(&(s->stream));
+ }
+ }
+ if (s->file != NULL && fclose(s->file)) {
+#ifdef ESPIPE
+ if (errno != ESPIPE) /* fclose is broken for pipes in HP/UX */
+#endif
+ err = Z_ERRNO;
+ }
+ if (s->z_err < 0) err = s->z_err;
+
+ TRYFREE(s->inbuf);
+ TRYFREE(s->outbuf);
+ TRYFREE(s->path);
+ TRYFREE(s);
+ return err;
+}
+
+/* ===========================================================================
+ Reads the given number of uncompressed bytes from the compressed file.
+ gzread returns the number of bytes actually read (0 for end of file).
+*/
+int ZEXPORT gzread (file, buf, len)
+ gzFile file;
+ voidp buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+ Bytef *start = (Bytef*)buf; /* starting point for crc computation */
+ Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
+
+ if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR;
+
+ if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1;
+ if (s->z_err == Z_STREAM_END) return 0; /* EOF */
+
+ next_out = (Byte*)buf;
+ s->stream.next_out = (Bytef*)buf;
+ s->stream.avail_out = len;
+
+ if (s->stream.avail_out && s->back != EOF) {
+ *next_out++ = s->back;
+ s->stream.next_out++;
+ s->stream.avail_out--;
+ s->back = EOF;
+ s->out++;
+ start++;
+ if (s->last) {
+ s->z_err = Z_STREAM_END;
+ return 1;
+ }
+ }
+
+ while (s->stream.avail_out != 0) {
+
+ if (s->transparent) {
+ /* Copy first the lookahead bytes: */
+ uInt n = s->stream.avail_in;
+ if (n > s->stream.avail_out) n = s->stream.avail_out;
+ if (n > 0) {
+ zmemcpy(s->stream.next_out, s->stream.next_in, n);
+ next_out += n;
+ s->stream.next_out = next_out;
+ s->stream.next_in += n;
+ s->stream.avail_out -= n;
+ s->stream.avail_in -= n;
+ }
+ if (s->stream.avail_out > 0) {
+ s->stream.avail_out -=
+ (uInt)fread(next_out, 1, s->stream.avail_out, s->file);
+ }
+ len -= s->stream.avail_out;
+ s->in += len;
+ s->out += len;
+ if (len == 0) s->z_eof = 1;
+ return (int)len;
+ }
+ if (s->stream.avail_in == 0 && !s->z_eof) {
+
+ errno = 0;
+ s->stream.avail_in = (uInt)fread(s->inbuf, 1, Z_BUFSIZE, s->file);
+ if (s->stream.avail_in == 0) {
+ s->z_eof = 1;
+ if (ferror(s->file)) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ }
+ s->stream.next_in = s->inbuf;
+ }
+ s->in += s->stream.avail_in;
+ s->out += s->stream.avail_out;
+ s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
+ s->in -= s->stream.avail_in;
+ s->out -= s->stream.avail_out;
+
+ if (s->z_err == Z_STREAM_END) {
+ /* Check CRC and original size */
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+ start = s->stream.next_out;
+
+ if (getLong(s) != s->crc) {
+ s->z_err = Z_DATA_ERROR;
+ } else {
+ (void)getLong(s);
+ /* The uncompressed length returned by above getlong() may be
+ * different from s->out in case of concatenated .gz files.
+ * Check for such files:
+ */
+ check_header(s);
+ if (s->z_err == Z_OK) {
+ inflateReset(&(s->stream));
+ s->crc = crc32(0L, Z_NULL, 0);
+ }
+ }
+ }
+ if (s->z_err != Z_OK || s->z_eof) break;
+ }
+ s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
+
+ if (len == s->stream.avail_out &&
+ (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
+ return -1;
+ return (int)(len - s->stream.avail_out);
+}
+
+
+/* ===========================================================================
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+int ZEXPORT gzgetc(file)
+ gzFile file;
+{
+ unsigned char c;
+
+ return gzread(file, &c, 1) == 1 ? c : -1;
+}
+
+
+/* ===========================================================================
+ Push one byte back onto the stream.
+*/
+int ZEXPORT gzungetc(c, file)
+ int c;
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r' || c == EOF || s->back != EOF) return EOF;
+ s->back = c;
+ s->out--;
+ s->last = (s->z_err == Z_STREAM_END);
+ if (s->last) s->z_err = Z_OK;
+ s->z_eof = 0;
+ return c;
+}
+
+
+/* ===========================================================================
+ Reads bytes from the compressed file until len-1 characters are
+ read, or a newline character is read and transferred to buf, or an
+ end-of-file condition is encountered. The string is then terminated
+ with a null character.
+ gzgets returns buf, or Z_NULL in case of error.
+
+ The current implementation is not optimized at all.
+*/
+char * ZEXPORT gzgets(file, buf, len)
+ gzFile file;
+ char *buf;
+ int len;
+{
+ char *b = buf;
+ if (buf == Z_NULL || len <= 0) return Z_NULL;
+
+ while (--len > 0 && gzread(file, buf, 1) == 1 && *buf++ != '\n') ;
+ *buf = '\0';
+ return b == buf && len > 0 ? Z_NULL : b;
+}
+
+
+#ifndef NO_GZCOMPRESS
+/* ===========================================================================
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of bytes actually written (0 in case of error).
+*/
+int ZEXPORT gzwrite (file, buf, len)
+ gzFile file;
+ voidpc buf;
+ unsigned len;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.next_in = (Bytef*)buf;
+ s->stream.avail_in = len;
+
+ while (s->stream.avail_in != 0) {
+
+ if (s->stream.avail_out == 0) {
+
+ s->stream.next_out = s->outbuf;
+ if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) {
+ s->z_err = Z_ERRNO;
+ break;
+ }
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ s->in += s->stream.avail_in;
+ s->out += s->stream.avail_out;
+ s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
+ s->in -= s->stream.avail_in;
+ s->out -= s->stream.avail_out;
+ if (s->z_err != Z_OK) break;
+ }
+ s->crc = crc32(s->crc, (const Bytef *)buf, len);
+
+ return (int)(len - s->stream.avail_in);
+}
+
+
+/* ===========================================================================
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error).
+*/
+#ifdef STDC
+#include <stdarg.h>
+
+int ZEXPORTVA gzprintf (gzFile file, const char *format, /* args */ ...)
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ va_list va;
+ int len;
+
+ buf[sizeof(buf) - 1] = 0;
+ va_start(va, format);
+#ifdef NO_vsnprintf
+# ifdef HAS_vsprintf_void
+ (void)vsprintf(buf, format, va);
+ va_end(va);
+ for (len = 0; len < sizeof(buf); len++)
+ if (buf[len] == 0) break;
+# else
+ len = vsprintf(buf, format, va);
+ va_end(va);
+# endif
+#else
+# ifdef HAS_vsnprintf_void
+ (void)vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+ len = strlen(buf);
+# else
+ len = vsnprintf(buf, sizeof(buf), format, va);
+ va_end(va);
+# endif
+#endif
+ if (len <= 0 || len >= (int)sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+ return 0;
+ return gzwrite(file, buf, (unsigned)len);
+}
+#else /* not ANSI C */
+
+int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20)
+ gzFile file;
+ const char *format;
+ int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10,
+ a11, a12, a13, a14, a15, a16, a17, a18, a19, a20;
+{
+ char buf[Z_PRINTF_BUFSIZE];
+ int len;
+
+ buf[sizeof(buf) - 1] = 0;
+#ifdef NO_snprintf
+# ifdef HAS_sprintf_void
+ sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ for (len = 0; len < sizeof(buf); len++)
+ if (buf[len] == 0) break;
+# else
+ len = sprintf(buf, format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#else
+# ifdef HAS_snprintf_void
+ snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+ len = strlen(buf);
+# else
+ len = snprintf(buf, sizeof(buf), format, a1, a2, a3, a4, a5, a6, a7, a8,
+ a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20);
+# endif
+#endif
+ if (len <= 0 || len >= sizeof(buf) || buf[sizeof(buf) - 1] != 0)
+ return 0;
+ return gzwrite(file, buf, len);
+}
+#endif
+
+/* ===========================================================================
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+int ZEXPORT gzputc(file, c)
+ gzFile file;
+ int c;
+{
+ unsigned char cc = (unsigned char) c; /* required for big endian systems */
+
+ return gzwrite(file, &cc, 1) == 1 ? (int)cc : -1;
+}
+
+
+/* ===========================================================================
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+int ZEXPORT gzputs(file, s)
+ gzFile file;
+ const char *s;
+{
+ return gzwrite(file, (char*)s, (unsigned)strlen(s));
+}
+
+
+/* ===========================================================================
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function.
+*/
+local int do_flush (file, flush)
+ gzFile file;
+ int flush;
+{
+ uInt len;
+ int done = 0;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
+
+ s->stream.avail_in = 0; /* should be zero already anyway */
+
+ for (;;) {
+ len = Z_BUFSIZE - s->stream.avail_out;
+
+ if (len != 0) {
+ if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) {
+ s->z_err = Z_ERRNO;
+ return Z_ERRNO;
+ }
+ s->stream.next_out = s->outbuf;
+ s->stream.avail_out = Z_BUFSIZE;
+ }
+ if (done) break;
+ s->out += s->stream.avail_out;
+ s->z_err = deflate(&(s->stream), flush);
+ s->out -= s->stream.avail_out;
+
+ /* Ignore the second of two consecutive flushes: */
+ if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
+
+ /* deflate has finished flushing only when it hasn't used up
+ * all the available space in the output buffer:
+ */
+ done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
+
+ if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
+ }
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+
+int ZEXPORT gzflush (file, flush)
+ gzFile file;
+ int flush;
+{
+ gz_stream *s = (gz_stream*)file;
+ int err = do_flush (file, flush);
+
+ if (err) return err;
+ fflush(s->file);
+ return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
+}
+#endif /* NO_GZCOMPRESS */
+
+/* ===========================================================================
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error.
+ SEEK_END is not implemented, returns error.
+ In this version of the library, gzseek can be extremely slow.
+*/
+z_off_t ZEXPORT gzseek (file, offset, whence)
+ gzFile file;
+ z_off_t offset;
+ int whence;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || whence == SEEK_END ||
+ s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
+ return -1L;
+ }
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ return -1L;
+#else
+ if (whence == SEEK_SET) {
+ offset -= s->in;
+ }
+ if (offset < 0) return -1L;
+
+ /* At this point, offset is the number of zero bytes to write. */
+ if (s->inbuf == Z_NULL) {
+ s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); /* for seeking */
+ if (s->inbuf == Z_NULL) return -1L;
+ zmemzero(s->inbuf, Z_BUFSIZE);
+ }
+ while (offset > 0) {
+ uInt size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (uInt)offset;
+
+ size = gzwrite(file, s->inbuf, size);
+ if (size == 0) return -1L;
+
+ offset -= size;
+ }
+ return s->in;
+#endif
+ }
+ /* Rest of function is for reading only */
+
+ /* compute absolute position */
+ if (whence == SEEK_CUR) {
+ offset += s->out;
+ }
+ if (offset < 0) return -1L;
+
+ if (s->transparent) {
+ /* map to fseek */
+ s->back = EOF;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ if (fseek(s->file, offset, SEEK_SET) < 0) return -1L;
+
+ s->in = s->out = offset;
+ return offset;
+ }
+
+ /* For a negative seek, rewind and use positive seek */
+ if (offset >= s->out) {
+ offset -= s->out;
+ } else if (gzrewind(file) < 0) {
+ return -1L;
+ }
+ /* offset is now the number of bytes to skip. */
+
+ if (offset != 0 && s->outbuf == Z_NULL) {
+ s->outbuf = (Byte*)ALLOC(Z_BUFSIZE);
+ if (s->outbuf == Z_NULL) return -1L;
+ }
+ if (offset && s->back != EOF) {
+ s->back = EOF;
+ s->out++;
+ offset--;
+ if (s->last) s->z_err = Z_STREAM_END;
+ }
+ while (offset > 0) {
+ int size = Z_BUFSIZE;
+ if (offset < Z_BUFSIZE) size = (int)offset;
+
+ size = gzread(file, s->outbuf, (uInt)size);
+ if (size <= 0) return -1L;
+ offset -= size;
+ }
+ return s->out;
+}
+
+/* ===========================================================================
+ Rewinds input file.
+*/
+int ZEXPORT gzrewind (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return -1;
+
+ s->z_err = Z_OK;
+ s->z_eof = 0;
+ s->back = EOF;
+ s->stream.avail_in = 0;
+ s->stream.next_in = s->inbuf;
+ s->crc = crc32(0L, Z_NULL, 0);
+ if (!s->transparent) (void)inflateReset(&s->stream);
+ s->in = 0;
+ s->out = 0;
+ return fseek(s->file, s->start, SEEK_SET);
+}
+
+/* ===========================================================================
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+*/
+z_off_t ZEXPORT gztell (file)
+ gzFile file;
+{
+ return gzseek(file, 0L, SEEK_CUR);
+}
+
+/* ===========================================================================
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+int ZEXPORT gzeof (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ /* With concatenated compressed files that can have embedded
+ * crc trailers, z_eof is no longer the only/best indicator of EOF
+ * on a gz_stream. Handle end-of-stream error explicitly here.
+ */
+ if (s == NULL || s->mode != 'r') return 0;
+ if (s->z_eof) return 1;
+ return s->z_err == Z_STREAM_END;
+}
+
+/* ===========================================================================
+ Returns 1 if reading and doing so transparently, otherwise zero.
+*/
+int ZEXPORT gzdirect (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL || s->mode != 'r') return 0;
+ return s->transparent;
+}
+
+/* ===========================================================================
+ Outputs a long in LSB order to the given file
+*/
+local void putLong (file, x)
+ FILE *file;
+ uLong x;
+{
+ int n;
+ for (n = 0; n < 4; n++) {
+ fputc((int)(x & 0xff), file);
+ x >>= 8;
+ }
+}
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets z_err in case
+ of error.
+*/
+local uLong getLong (s)
+ gz_stream *s;
+{
+ uLong x = (uLong)get_byte(s);
+ int c;
+
+ x += ((uLong)get_byte(s))<<8;
+ x += ((uLong)get_byte(s))<<16;
+ c = get_byte(s);
+ if (c == EOF) s->z_err = Z_DATA_ERROR;
+ x += ((uLong)c)<<24;
+ return x;
+}
+
+/* ===========================================================================
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state.
+*/
+int ZEXPORT gzclose (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return Z_STREAM_ERROR;
+
+ if (s->mode == 'w') {
+#ifdef NO_GZCOMPRESS
+ return Z_STREAM_ERROR;
+#else
+ if (do_flush (file, Z_FINISH) != Z_OK)
+ return destroy((gz_stream*)file);
+
+ putLong (s->file, s->crc);
+ putLong (s->file, (uLong)(s->in & 0xffffffff));
+#endif
+ }
+ return destroy((gz_stream*)file);
+}
+
+#ifdef STDC
+# define zstrerror(errnum) strerror(errnum)
+#else
+# define zstrerror(errnum) ""
+#endif
+
+/* ===========================================================================
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+const char * ZEXPORT gzerror (file, errnum)
+ gzFile file;
+ int *errnum;
+{
+ char *m;
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) {
+ *errnum = Z_STREAM_ERROR;
+ return (const char*)ERR_MSG(Z_STREAM_ERROR);
+ }
+ *errnum = s->z_err;
+ if (*errnum == Z_OK) return (const char*)"";
+
+ m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg);
+
+ if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err);
+
+ TRYFREE(s->msg);
+ s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3);
+ if (s->msg == Z_NULL) return (const char*)ERR_MSG(Z_MEM_ERROR);
+ strcpy(s->msg, s->path);
+ strcat(s->msg, ": ");
+ strcat(s->msg, m);
+ return (const char*)s->msg;
+}
+
+/* ===========================================================================
+ Clear the error and end-of-file flags, and do the same for the real file.
+*/
+void ZEXPORT gzclearerr (file)
+ gzFile file;
+{
+ gz_stream *s = (gz_stream*)file;
+
+ if (s == NULL) return;
+ if (s->z_err != Z_STREAM_END) s->z_err = Z_OK;
+ s->z_eof = 0;
+ clearerr(s->file);
+}
diff --git a/src/lib/zlib/infback.c b/src/lib/zlib/infback.c
new file mode 100644
index 00000000000..455dbc9ee84
--- /dev/null
+++ b/src/lib/zlib/infback.c
@@ -0,0 +1,623 @@
+/* infback.c -- inflate using a call-back interface
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ This code is largely copied from inflate.c. Normally either infback.o or
+ inflate.o would be linked into an application--not both. The interface
+ with inffast.c is retained so that optimized assembler-coded versions of
+ inflate_fast() can be used with either inflate.c or infback.c.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+
+/*
+ strm provides memory allocation functions in zalloc and zfree, or
+ Z_NULL to use the library memory allocation functions.
+
+ windowBits is in the range 8..15, and window is a user-supplied
+ window and output buffer that is 2**windowBits bytes.
+ */
+int ZEXPORT inflateBackInit_(strm, windowBits, window, version, stream_size)
+z_streamp strm;
+int windowBits;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL || window == Z_NULL ||
+ windowBits < 8 || windowBits > 15)
+ return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+ sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ state->dmax = 32768U;
+ state->wbits = windowBits;
+ state->wsize = 1U << windowBits;
+ state->window = window;
+ state->write = 0;
+ state->whave = 0;
+ return Z_OK;
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+/* Macros for inflateBack(): */
+
+/* Load returned state from inflate_fast() */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Set state from registers for inflate_fast() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Assure that some input is available. If input is requested, but denied,
+ then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+ do { \
+ if (have == 0) { \
+ have = in(in_desc, &next); \
+ if (have == 0) { \
+ next = Z_NULL; \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+ with an error if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ PULL(); \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflateBack() with
+ an error. */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Assure that some output space is available, by writing out the window
+ if it's full. If the write fails, return from inflateBack() with a
+ Z_BUF_ERROR. */
+#define ROOM() \
+ do { \
+ if (left == 0) { \
+ put = state->window; \
+ left = state->wsize; \
+ state->whave = left; \
+ if (out(out_desc, put, left)) { \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/*
+ strm provides the memory allocation functions and window buffer on input,
+ and provides information on the unused input on return. For Z_DATA_ERROR
+ returns, strm will also provide an error message.
+
+ in() and out() are the call-back input and output functions. When
+ inflateBack() needs more input, it calls in(). When inflateBack() has
+ filled the window with output, or when it completes with data in the
+ window, it calls out() to write out the data. The application must not
+ change the provided input until in() is called again or inflateBack()
+ returns. The application must not change the window/output buffer until
+ inflateBack() returns.
+
+ in() and out() are called with a descriptor parameter provided in the
+ inflateBack() call. This parameter can be a structure that provides the
+ information required to do the read or write, as well as accumulated
+ information on the input and output such as totals and check values.
+
+ in() should return zero on failure. out() should return non-zero on
+ failure. If either in() or out() fails, than inflateBack() returns a
+ Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
+ was in() or out() that caused in the error. Otherwise, inflateBack()
+ returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+ error, or Z_MEM_ERROR if it could not allocate memory for the state.
+ inflateBack() can also return Z_STREAM_ERROR if the input parameters
+ are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack(strm, in, in_desc, out, out_desc)
+z_streamp strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ /* Check that the strm exists and that the state was initialized */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* Reset the state */
+ strm->msg = Z_NULL;
+ state->mode = TYPE;
+ state->last = 0;
+ state->whave = 0;
+ next = strm->next_in;
+ have = next != Z_NULL ? strm->avail_in : 0;
+ hold = 0;
+ bits = 0;
+ put = state->window;
+ left = state->wsize;
+
+ /* Inflate until end of block marked as last */
+ for (;;)
+ switch (state->mode) {
+ case TYPE:
+ /* determine and dispatch block type */
+ if (state->last) {
+ BYTEBITS();
+ state->mode = DONE;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+
+ case STORED:
+ /* get and verify stored block length */
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+
+ /* copy stored block from input to output */
+ while (state->length != 0) {
+ copy = state->length;
+ PULL();
+ ROOM();
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+
+ case TABLE:
+ /* get dynamic table entries descriptor */
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+
+ /* get code length code lengths (not a typo) */
+ state->have = 0;
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+
+ /* get length and distance code code lengths */
+ state->have = 0;
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = (unsigned)(state->lens[state->have - 1]);
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+
+ case LEN:
+ /* use inflate_fast() if we have enough input and output */
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ if (state->whave < state->wsize)
+ state->whave = state->wsize - left;
+ inflate_fast(strm, state->wsize);
+ LOAD();
+ break;
+ }
+
+ /* get a literal, length, or end-of-block code */
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+
+ /* process literal */
+ if (this.op == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ ROOM();
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ }
+
+ /* process end of block */
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+
+ /* invalid code */
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+
+ /* length code -- get extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+
+ /* get distance code */
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+
+ /* get distance extra bits, if any */
+ state->extra = (unsigned)(this.op) & 15;
+ if (state->extra != 0) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ if (state->offset > state->wsize - (state->whave < state->wsize ?
+ left : 0)) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+
+ /* copy match from window to output */
+ do {
+ ROOM();
+ copy = state->wsize - state->offset;
+ if (copy < left) {
+ from = put + copy;
+ copy = left - copy;
+ }
+ else {
+ from = put - state->offset;
+ copy = left;
+ }
+ if (copy > state->length) copy = state->length;
+ state->length -= copy;
+ left -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ } while (state->length != 0);
+ break;
+
+ case DONE:
+ /* inflate stream terminated properly -- write leftover output */
+ ret = Z_STREAM_END;
+ if (left < state->wsize) {
+ if (out(out_desc, state->window, state->wsize - left))
+ ret = Z_BUF_ERROR;
+ }
+ goto inf_leave;
+
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+
+ default: /* can't happen, but makes compilers happy */
+ ret = Z_STREAM_ERROR;
+ goto inf_leave;
+ }
+
+ /* Return unused input */
+ inf_leave:
+ strm->next_in = next;
+ strm->avail_in = have;
+ return ret;
+}
+
+int ZEXPORT inflateBackEnd(strm)
+z_streamp strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
diff --git a/src/lib/zlib/inffast.c b/src/lib/zlib/inffast.c
new file mode 100644
index 00000000000..bbee92ed1e6
--- /dev/null
+++ b/src/lib/zlib/inffast.c
@@ -0,0 +1,318 @@
+/* inffast.c -- fast decoding
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifndef ASMINF
+
+/* Allow machine dependent optimization for post-increment or pre-increment.
+ Based on testing to date,
+ Pre-increment preferred for:
+ - PowerPC G3 (Adler)
+ - MIPS R5000 (Randers-Pehrson)
+ Post-increment preferred for:
+ - none
+ No measurable difference:
+ - Pentium III (Anderson)
+ - M68060 (Nikl)
+ */
+#ifdef POSTINC
+# define OFF 0
+# define PUP(a) *(a)++
+#else
+# define OFF 1
+# define PUP(a) *++(a)
+#endif
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *in; /* local strm->next_in */
+ unsigned char FAR *last; /* while in < last, enough input available */
+ unsigned char FAR *out; /* local strm->next_out */
+ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */
+ unsigned char FAR *end; /* while out < end, enough space available */
+#ifdef INFLATE_STRICT
+ unsigned dmax; /* maximum distance from zlib header */
+#endif
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */
+ unsigned long hold; /* local strm->hold */
+ unsigned bits; /* local strm->bits */
+ code const FAR *lcode; /* local strm->lencode */
+ code const FAR *dcode; /* local strm->distcode */
+ unsigned lmask; /* mask for first level of length codes */
+ unsigned dmask; /* mask for first level of distance codes */
+ code this; /* retrieved table entry */
+ unsigned op; /* code bits, operation, extra bits, or */
+ /* window position, window bytes to copy */
+ unsigned len; /* match length, unused bytes */
+ unsigned dist; /* match distance */
+ unsigned char FAR *from; /* where to copy match from */
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ in = strm->next_in - OFF;
+ last = in + (strm->avail_in - 5);
+ out = strm->next_out - OFF;
+ beg = out - (start - strm->avail_out);
+ end = out + (strm->avail_out - 257);
+#ifdef INFLATE_STRICT
+ dmax = state->dmax;
+#endif
+ wsize = state->wsize;
+ whave = state->whave;
+ write = state->write;
+ window = state->window;
+ hold = state->hold;
+ bits = state->bits;
+ lcode = state->lencode;
+ dcode = state->distcode;
+ lmask = (1U << state->lenbits) - 1;
+ dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+ do {
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = lcode[hold & lmask];
+ dolen:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op == 0) { /* literal */
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ PUP(out) = (unsigned char)(this.val);
+ }
+ else if (op & 16) { /* length base */
+ len = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (op) {
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ len += (unsigned)hold & ((1U << op) - 1);
+ hold >>= op;
+ bits -= op;
+ }
+ Tracevv((stderr, "inflate: length %u\n", len));
+ if (bits < 15) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ this = dcode[hold & dmask];
+ dodist:
+ op = (unsigned)(this.bits);
+ hold >>= op;
+ bits -= op;
+ op = (unsigned)(this.op);
+ if (op & 16) { /* distance base */
+ dist = (unsigned)(this.val);
+ op &= 15; /* number of extra bits */
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ if (bits < op) {
+ hold += (unsigned long)(PUP(in)) << bits;
+ bits += 8;
+ }
+ }
+ dist += (unsigned)hold & ((1U << op) - 1);
+#ifdef INFLATE_STRICT
+ if (dist > dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ hold >>= op;
+ bits -= op;
+ Tracevv((stderr, "inflate: distance %u\n", dist));
+ op = (unsigned)(out - beg); /* max distance in output */
+ if (dist > op) { /* see if copy from window */
+ op = dist - op; /* distance back in window */
+ if (op > whave) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ from = window - OFF;
+ if (write == 0) { /* very common case */
+ from += wsize - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ else if (write < op) { /* wrap around window */
+ from += wsize + write - op;
+ op -= write;
+ if (op < len) { /* some from end of window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = window - OFF;
+ if (write < len) { /* some from start of window */
+ op = write;
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ }
+ else { /* contiguous in window */
+ from += write - op;
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ PUP(out) = PUP(from);
+ } while (--op);
+ from = out - dist; /* rest from output */
+ }
+ }
+ while (len > 2) {
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ }
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ else {
+ from = out - dist; /* copy direct from output */
+ do { /* minimum length is three */
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ PUP(out) = PUP(from);
+ len -= 3;
+ } while (len > 2);
+ if (len) {
+ PUP(out) = PUP(from);
+ if (len > 1)
+ PUP(out) = PUP(from);
+ }
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level distance code */
+ this = dcode[this.val + (hold & ((1U << op) - 1))];
+ goto dodist;
+ }
+ else {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ }
+ else if ((op & 64) == 0) { /* 2nd level length code */
+ this = lcode[this.val + (hold & ((1U << op) - 1))];
+ goto dolen;
+ }
+ else if (op & 32) { /* end-of-block */
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ else {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ } while (in < last && out < end);
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ len = bits >> 3;
+ in -= len;
+ bits -= len << 3;
+ hold &= (1U << bits) - 1;
+
+ /* update state and return */
+ strm->next_in = in + OFF;
+ strm->next_out = out + OFF;
+ strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last));
+ strm->avail_out = (unsigned)(out < end ?
+ 257 + (end - out) : 257 - (out - end));
+ state->hold = hold;
+ state->bits = bits;
+ return;
+}
+
+/*
+ inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe):
+ - Using bit fields for code structure
+ - Different op definition to avoid & for extra bits (do & for table bits)
+ - Three separate decoding do-loops for direct, window, and write == 0
+ - Special case for distance > 1 copies to do overlapped load and store copy
+ - Explicit branch predictions (based on measured branch probabilities)
+ - Deferring match copy and interspersed it with decoding subsequent codes
+ - Swapping literal/length else
+ - Swapping window/direct else
+ - Larger unrolled copy loops (three is about right)
+ - Moving len -= 3 statement into middle of loop
+ */
+
+#endif /* !ASMINF */
diff --git a/src/lib/zlib/inffast.h b/src/lib/zlib/inffast.h
new file mode 100644
index 00000000000..1e88d2d97b5
--- /dev/null
+++ b/src/lib/zlib/inffast.h
@@ -0,0 +1,11 @@
+/* inffast.h -- header to use inffast.c
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+void inflate_fast OF((z_streamp strm, unsigned start));
diff --git a/src/lib/zlib/inffixed.h b/src/lib/zlib/inffixed.h
new file mode 100644
index 00000000000..75ed4b5978d
--- /dev/null
+++ b/src/lib/zlib/inffixed.h
@@ -0,0 +1,94 @@
+ /* inffixed.h -- table for decoding fixed codes
+ * Generated automatically by makefixed().
+ */
+
+ /* WARNING: this file should *not* be used by applications. It
+ is part of the implementation of the compression library and
+ is subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48},
+ {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59},
+ {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176},
+ {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20},
+ {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8},
+ {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216},
+ {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76},
+ {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114},
+ {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},
+ {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42},
+ {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86},
+ {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15},
+ {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236},
+ {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62},
+ {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31},
+ {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25},
+ {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105},
+ {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4},
+ {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69},
+ {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125},
+ {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13},
+ {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195},
+ {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35},
+ {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19},
+ {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246},
+ {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55},
+ {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135},
+ {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99},
+ {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16},
+ {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96},
+ {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6},
+ {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209},
+ {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},
+ {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4},
+ {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153},
+ {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44},
+ {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82},
+ {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11},
+ {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58},
+ {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138},
+ {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51},
+ {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30},
+ {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0},
+ {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195},
+ {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65},
+ {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121},
+ {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},
+ {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258},
+ {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37},
+ {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93},
+ {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23},
+ {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251},
+ {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51},
+ {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67},
+ {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183},
+ {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23},
+ {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103},
+ {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9},
+ {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79},
+ {0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025},
+ {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193},
+ {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385},
+ {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577},
+ {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073},
+ {22,5,193},{64,5,0}
+ };
diff --git a/src/lib/zlib/inflate.c b/src/lib/zlib/inflate.c
new file mode 100644
index 00000000000..792fdee8e9c
--- /dev/null
+++ b/src/lib/zlib/inflate.c
@@ -0,0 +1,1368 @@
+/* inflate.c -- zlib decompression
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * Change history:
+ *
+ * 1.2.beta0 24 Nov 2002
+ * - First version -- complete rewrite of inflate to simplify code, avoid
+ * creation of window when not needed, minimize use of window when it is
+ * needed, make inffast.c even faster, implement gzip decoding, and to
+ * improve code readability and style over the previous zlib inflate code
+ *
+ * 1.2.beta1 25 Nov 2002
+ * - Use pointers for available input and output checking in inffast.c
+ * - Remove input and output counters in inffast.c
+ * - Change inffast.c entry and loop from avail_in >= 7 to >= 6
+ * - Remove unnecessary second byte pull from length extra in inffast.c
+ * - Unroll direct copy to three copies per loop in inffast.c
+ *
+ * 1.2.beta2 4 Dec 2002
+ * - Change external routine names to reduce potential conflicts
+ * - Correct filename to inffixed.h for fixed tables in inflate.c
+ * - Make hbuf[] unsigned char to match parameter type in inflate.c
+ * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset)
+ * to avoid negation problem on Alphas (64 bit) in inflate.c
+ *
+ * 1.2.beta3 22 Dec 2002
+ * - Add comments on state->bits assertion in inffast.c
+ * - Add comments on op field in inftrees.h
+ * - Fix bug in reuse of allocated window after inflateReset()
+ * - Remove bit fields--back to byte structure for speed
+ * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths
+ * - Change post-increments to pre-increments in inflate_fast(), PPC biased?
+ * - Add compile time option, POSTINC, to use post-increments instead (Intel?)
+ * - Make MATCH copy in inflate() much faster for when inflate_fast() not used
+ * - Use local copies of stream next and avail values, as well as local bit
+ * buffer and bit count in inflate()--for speed when inflate_fast() not used
+ *
+ * 1.2.beta4 1 Jan 2003
+ * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings
+ * - Move a comment on output buffer sizes from inffast.c to inflate.c
+ * - Add comments in inffast.c to introduce the inflate_fast() routine
+ * - Rearrange window copies in inflate_fast() for speed and simplification
+ * - Unroll last copy for window match in inflate_fast()
+ * - Use local copies of window variables in inflate_fast() for speed
+ * - Pull out common write == 0 case for speed in inflate_fast()
+ * - Make op and len in inflate_fast() unsigned for consistency
+ * - Add FAR to lcode and dcode declarations in inflate_fast()
+ * - Simplified bad distance check in inflate_fast()
+ * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new
+ * source file infback.c to provide a call-back interface to inflate for
+ * programs like gzip and unzip -- uses window as output buffer to avoid
+ * window copying
+ *
+ * 1.2.beta5 1 Jan 2003
+ * - Improved inflateBack() interface to allow the caller to provide initial
+ * input in strm.
+ * - Fixed stored blocks bug in inflateBack()
+ *
+ * 1.2.beta6 4 Jan 2003
+ * - Added comments in inffast.c on effectiveness of POSTINC
+ * - Typecasting all around to reduce compiler warnings
+ * - Changed loops from while (1) or do {} while (1) to for (;;), again to
+ * make compilers happy
+ * - Changed type of window in inflateBackInit() to unsigned char *
+ *
+ * 1.2.beta7 27 Jan 2003
+ * - Changed many types to unsigned or unsigned short to avoid warnings
+ * - Added inflateCopy() function
+ *
+ * 1.2.0 9 Mar 2003
+ * - Changed inflateBack() interface to provide separate opaque descriptors
+ * for the in() and out() functions
+ * - Changed inflateBack() argument and in_func typedef to swap the length
+ * and buffer address return values for the input function
+ * - Check next_in and next_out for Z_NULL on entry to inflate()
+ *
+ * The history for versions after 1.2.0 are in ChangeLog in zlib distribution.
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+#ifdef MAKEFIXED
+# ifndef BUILDFIXED
+# define BUILDFIXED
+# endif
+#endif
+
+/* function prototypes */
+local void fixedtables OF((struct inflate_state FAR *state));
+local int updatewindow OF((z_streamp strm, unsigned out));
+#ifdef BUILDFIXED
+ void makefixed OF((void));
+#endif
+local unsigned syncsearch OF((unsigned FAR *have, unsigned char FAR *buf,
+ unsigned len));
+
+int ZEXPORT inflateReset(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ strm->total_in = strm->total_out = state->total = 0;
+ strm->msg = Z_NULL;
+ strm->adler = 1; /* to support ill-conceived Java test suite */
+ state->mode = HEAD;
+ state->last = 0;
+ state->havedict = 0;
+ state->dmax = 32768U;
+ state->head = Z_NULL;
+ state->wsize = 0;
+ state->whave = 0;
+ state->write = 0;
+ state->hold = 0;
+ state->bits = 0;
+ state->lencode = state->distcode = state->next = state->codes;
+ Tracev((stderr, "inflate: reset\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflatePrime(strm, bits, value)
+z_streamp strm;
+int bits;
+int value;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR;
+ value &= (1L << bits) - 1;
+ state->hold += value << state->bits;
+ state->bits += bits;
+ return Z_OK;
+}
+
+int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size)
+z_streamp strm;
+int windowBits;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL) return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)
+ ZALLOC(strm, 1, sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (struct internal_state FAR *)state;
+ if (windowBits < 0) {
+ state->wrap = 0;
+ windowBits = -windowBits;
+ }
+ else {
+ state->wrap = (windowBits >> 4) + 1;
+#ifdef GUNZIP
+ if (windowBits < 48) windowBits &= 15;
+#endif
+ }
+ if (windowBits < 8 || windowBits > 15) {
+ ZFREE(strm, state);
+ strm->state = Z_NULL;
+ return Z_STREAM_ERROR;
+ }
+ state->wbits = (unsigned)windowBits;
+ state->window = Z_NULL;
+ return inflateReset(strm);
+}
+
+int ZEXPORT inflateInit_(strm, version, stream_size)
+z_streamp strm;
+const char *version;
+int stream_size;
+{
+ return inflateInit2_(strm, DEF_WBITS, version, stream_size);
+}
+
+/*
+ Return state with length and distance decoding tables and index sizes set to
+ fixed code decoding. Normally this returns fixed tables from inffixed.h.
+ If BUILDFIXED is defined, then instead this routine builds the tables the
+ first time it's called, and returns those tables the first time and
+ thereafter. This reduces the size of the code by about 2K bytes, in
+ exchange for a little execution time. However, BUILDFIXED should not be
+ used for threaded applications, since the rewriting of the tables and virgin
+ may not be thread-safe.
+ */
+local void fixedtables(state)
+struct inflate_state FAR *state;
+{
+#ifdef BUILDFIXED
+ static int virgin = 1;
+ static code *lenfix, *distfix;
+ static code fixed[544];
+
+ /* build fixed huffman tables if first call (may not be thread safe) */
+ if (virgin) {
+ unsigned sym, bits;
+ static code *next;
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state->lens[sym++] = 8;
+ while (sym < 256) state->lens[sym++] = 9;
+ while (sym < 280) state->lens[sym++] = 7;
+ while (sym < 288) state->lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state->lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work);
+
+ /* do this just once */
+ virgin = 0;
+ }
+#else /* !BUILDFIXED */
+# include "inffixed.h"
+#endif /* BUILDFIXED */
+ state->lencode = lenfix;
+ state->lenbits = 9;
+ state->distcode = distfix;
+ state->distbits = 5;
+}
+
+#ifdef MAKEFIXED
+#include <stdio.h>
+
+/*
+ Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also
+ defines BUILDFIXED, so the tables are built on the fly. makefixed() writes
+ those tables to stdout, which would be piped to inffixed.h. A small program
+ can simply call makefixed to do this:
+
+ void makefixed(void);
+
+ int main(void)
+ {
+ makefixed();
+ return 0;
+ }
+
+ Then that can be linked with zlib built with MAKEFIXED defined and run:
+
+ a.out > inffixed.h
+ */
+void makefixed()
+{
+ unsigned low, size;
+ struct inflate_state state;
+
+ fixedtables(&state);
+ puts(" /* inffixed.h -- table for decoding fixed codes");
+ puts(" * Generated automatically by makefixed().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 7) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.lencode[low].op, state.lencode[low].bits,
+ state.lencode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits,
+ state.distcode[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/*
+ Update the window with the last wsize (normally 32K) bytes written before
+ returning. If window does not exist yet, create it. This is only called
+ when a window is already in use, or when output has been written during this
+ inflate call, but the end of the deflate stream has not been reached yet.
+ It is also called to create a window for dictionary data when a dictionary
+ is loaded.
+
+ Providing output buffers larger than 32K to inflate() should provide a speed
+ advantage, since only the last 32K of output is copied to the sliding window
+ upon return from inflate(), and since all distances after the first 32K of
+ output will fall in the output data, making match copies simpler and faster.
+ The advantage may be dependent on the size of the processor's data caches.
+ */
+local int updatewindow(strm, out)
+z_streamp strm;
+unsigned out;
+{
+ struct inflate_state FAR *state;
+ unsigned copy, dist;
+
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* if it hasn't been done already, allocate space for the window */
+ if (state->window == Z_NULL) {
+ state->window = (unsigned char FAR *)
+ ZALLOC(strm, 1U << state->wbits,
+ sizeof(unsigned char));
+ if (state->window == Z_NULL) return 1;
+ }
+
+ /* if window not in use yet, initialize */
+ if (state->wsize == 0) {
+ state->wsize = 1U << state->wbits;
+ state->write = 0;
+ state->whave = 0;
+ }
+
+ /* copy state->wsize or less output bytes into the circular window */
+ copy = out - strm->avail_out;
+ if (copy >= state->wsize) {
+ zmemcpy(state->window, strm->next_out - state->wsize, state->wsize);
+ state->write = 0;
+ state->whave = state->wsize;
+ }
+ else {
+ dist = state->wsize - state->write;
+ if (dist > copy) dist = copy;
+ zmemcpy(state->window + state->write, strm->next_out - copy, dist);
+ copy -= dist;
+ if (copy) {
+ zmemcpy(state->window, strm->next_out - copy, copy);
+ state->write = copy;
+ state->whave = state->wsize;
+ }
+ else {
+ state->write += dist;
+ if (state->write == state->wsize) state->write = 0;
+ if (state->whave < state->wsize) state->whave += dist;
+ }
+ }
+ return 0;
+}
+
+/* Macros for inflate(): */
+
+/* check function to use adler32() for zlib or crc32() for gzip */
+#ifdef GUNZIP
+# define UPDATE(check, buf, len) \
+ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len))
+#else
+# define UPDATE(check, buf, len) adler32(check, buf, len)
+#endif
+
+/* check macros for header crc */
+#ifdef GUNZIP
+# define CRC2(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ check = crc32(check, hbuf, 2); \
+ } while (0)
+
+# define CRC4(check, word) \
+ do { \
+ hbuf[0] = (unsigned char)(word); \
+ hbuf[1] = (unsigned char)((word) >> 8); \
+ hbuf[2] = (unsigned char)((word) >> 16); \
+ hbuf[3] = (unsigned char)((word) >> 24); \
+ check = crc32(check, hbuf, 4); \
+ } while (0)
+#endif
+
+/* Load registers with state in inflate() for speed */
+#define LOAD() \
+ do { \
+ put = strm->next_out; \
+ left = strm->avail_out; \
+ next = strm->next_in; \
+ have = strm->avail_in; \
+ hold = state->hold; \
+ bits = state->bits; \
+ } while (0)
+
+/* Restore state from registers in inflate() */
+#define RESTORE() \
+ do { \
+ strm->next_out = put; \
+ strm->avail_out = left; \
+ strm->next_in = next; \
+ strm->avail_in = have; \
+ state->hold = hold; \
+ state->bits = bits; \
+ } while (0)
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflate()
+ if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ if (have == 0) goto inf_leave; \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflate(). */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n < 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Reverse the bytes in a 32-bit value */
+#define REVERSE(q) \
+ ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \
+ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24))
+
+/*
+ inflate() uses a state machine to process as much input data and generate as
+ much output data as possible before returning. The state machine is
+ structured roughly as follows:
+
+ for (;;) switch (state) {
+ ...
+ case STATEn:
+ if (not enough input data or output space to make progress)
+ return;
+ ... make progress ...
+ state = STATEm;
+ break;
+ ...
+ }
+
+ so when inflate() is called again, the same case is attempted again, and
+ if the appropriate resources are provided, the machine proceeds to the
+ next state. The NEEDBITS() macro is usually the way the state evaluates
+ whether it can proceed or should return. NEEDBITS() does the return if
+ the requested bits are not available. The typical use of the BITS macros
+ is:
+
+ NEEDBITS(n);
+ ... do something with BITS(n) ...
+ DROPBITS(n);
+
+ where NEEDBITS(n) either returns from inflate() if there isn't enough
+ input left to load n bits into the accumulator, or it continues. BITS(n)
+ gives the low n bits in the accumulator. When done, DROPBITS(n) drops
+ the low n bits off the accumulator. INITBITS() clears the accumulator
+ and sets the number of available bits to zero. BYTEBITS() discards just
+ enough bits to put the accumulator on a byte boundary. After BYTEBITS()
+ and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
+
+ NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
+ if there is no input available. The decoding of variable length codes uses
+ PULLBYTE() directly in order to pull just enough bytes to decode the next
+ code, and no more.
+
+ Some states loop until they get enough input, making sure that enough
+ state information is maintained to continue the loop where it left off
+ if NEEDBITS() returns in the loop. For example, want, need, and keep
+ would all have to actually be part of the saved state in case NEEDBITS()
+ returns:
+
+ case STATEw:
+ while (want < need) {
+ NEEDBITS(n);
+ keep[want++] = BITS(n);
+ DROPBITS(n);
+ }
+ state = STATEx;
+ case STATEx:
+
+ As shown above, if the next state is also the next case, then the break
+ is omitted.
+
+ A state may also return if there is not enough output space available to
+ complete that state. Those states are copying stored data, writing a
+ literal byte, and copying a matching string.
+
+ When returning, a "goto inf_leave" is used to update the total counters,
+ update the check value, and determine whether any progress has been made
+ during that inflate() call in order to return the proper return code.
+ Progress is defined as a change in either strm->avail_in or strm->avail_out.
+ When there is a window, goto inf_leave will update the window with the last
+ output written. If a goto inf_leave occurs in the middle of decompression
+ and there is no window currently, goto inf_leave will create one and copy
+ output to the window for the next call of inflate().
+
+ In this implementation, the flush parameter of inflate() only affects the
+ return code (per zlib.h). inflate() always writes as much as possible to
+ strm->next_out, given the space available and the provided input--the effect
+ documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
+ the allocation of and copying into a sliding window until necessary, which
+ provides the effect documented in zlib.h for Z_FINISH when the entire input
+ stream available. So the only thing the flush parameter actually does is:
+ when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
+ will return Z_BUF_ERROR if it has not reached the end of the stream.
+ */
+
+int ZEXPORT inflate(strm, flush)
+z_streamp strm;
+int flush;
+{
+ struct inflate_state FAR *state;
+ unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have, left; /* available input and output */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned in, out; /* save starting available input and output */
+ unsigned copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code this; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+#ifdef GUNZIP
+ unsigned char hbuf[4]; /* buffer for gzip header crc calculation */
+#endif
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL ||
+ (strm->next_in == Z_NULL && strm->avail_in != 0))
+ return Z_STREAM_ERROR;
+
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */
+ LOAD();
+ in = have;
+ out = left;
+ ret = Z_OK;
+ for (;;)
+ switch (state->mode) {
+ case HEAD:
+ if (state->wrap == 0) {
+ state->mode = TYPEDO;
+ break;
+ }
+ NEEDBITS(16);
+#ifdef GUNZIP
+ if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */
+ state->check = crc32(0L, Z_NULL, 0);
+ CRC2(state->check, hold);
+ INITBITS();
+ state->mode = FLAGS;
+ break;
+ }
+ state->flags = 0; /* expect zlib header */
+ if (state->head != Z_NULL)
+ state->head->done = -1;
+ if (!(state->wrap & 1) || /* check if zlib header allowed */
+#else
+ if (
+#endif
+ ((BITS(8) << 8) + (hold >> 8)) % 31) {
+ strm->msg = (char *)"incorrect header check";
+ state->mode = BAD;
+ break;
+ }
+ if (BITS(4) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ DROPBITS(4);
+ len = BITS(4) + 8;
+ if (len > state->wbits) {
+ strm->msg = (char *)"invalid window size";
+ state->mode = BAD;
+ break;
+ }
+ state->dmax = 1U << len;
+ Tracev((stderr, "inflate: zlib header ok\n"));
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = hold & 0x200 ? DICTID : TYPE;
+ INITBITS();
+ break;
+#ifdef GUNZIP
+ case FLAGS:
+ NEEDBITS(16);
+ state->flags = (int)(hold);
+ if ((state->flags & 0xff) != Z_DEFLATED) {
+ strm->msg = (char *)"unknown compression method";
+ state->mode = BAD;
+ break;
+ }
+ if (state->flags & 0xe000) {
+ strm->msg = (char *)"unknown header flags set";
+ state->mode = BAD;
+ break;
+ }
+ if (state->head != Z_NULL)
+ state->head->text = (int)((hold >> 8) & 1);
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = TIME;
+ case TIME:
+ NEEDBITS(32);
+ if (state->head != Z_NULL)
+ state->head->time = hold;
+ if (state->flags & 0x0200) CRC4(state->check, hold);
+ INITBITS();
+ state->mode = OS;
+ case OS:
+ NEEDBITS(16);
+ if (state->head != Z_NULL) {
+ state->head->xflags = (int)(hold & 0xff);
+ state->head->os = (int)(hold >> 8);
+ }
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ state->mode = EXLEN;
+ case EXLEN:
+ if (state->flags & 0x0400) {
+ NEEDBITS(16);
+ state->length = (unsigned)(hold);
+ if (state->head != Z_NULL)
+ state->head->extra_len = (unsigned)hold;
+ if (state->flags & 0x0200) CRC2(state->check, hold);
+ INITBITS();
+ }
+ else if (state->head != Z_NULL)
+ state->head->extra = Z_NULL;
+ state->mode = EXTRA;
+ case EXTRA:
+ if (state->flags & 0x0400) {
+ copy = state->length;
+ if (copy > have) copy = have;
+ if (copy) {
+ if (state->head != Z_NULL &&
+ state->head->extra != Z_NULL) {
+ len = state->head->extra_len - state->length;
+ zmemcpy(state->head->extra + len, next,
+ len + copy > state->head->extra_max ?
+ state->head->extra_max - len : copy);
+ }
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ state->length -= copy;
+ }
+ if (state->length) goto inf_leave;
+ }
+ state->length = 0;
+ state->mode = NAME;
+ case NAME:
+ if (state->flags & 0x0800) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->name != Z_NULL &&
+ state->length < state->head->name_max)
+ state->head->name[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->name = Z_NULL;
+ state->length = 0;
+ state->mode = COMMENT;
+ case COMMENT:
+ if (state->flags & 0x1000) {
+ if (have == 0) goto inf_leave;
+ copy = 0;
+ do {
+ len = (unsigned)(next[copy++]);
+ if (state->head != Z_NULL &&
+ state->head->comment != Z_NULL &&
+ state->length < state->head->comm_max)
+ state->head->comment[state->length++] = len;
+ } while (len && copy < have);
+ if (state->flags & 0x0200)
+ state->check = crc32(state->check, next, copy);
+ have -= copy;
+ next += copy;
+ if (len) goto inf_leave;
+ }
+ else if (state->head != Z_NULL)
+ state->head->comment = Z_NULL;
+ state->mode = HCRC;
+ case HCRC:
+ if (state->flags & 0x0200) {
+ NEEDBITS(16);
+ if (hold != (state->check & 0xffff)) {
+ strm->msg = (char *)"header crc mismatch";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ }
+ if (state->head != Z_NULL) {
+ state->head->hcrc = (int)((state->flags >> 9) & 1);
+ state->head->done = 1;
+ }
+ strm->adler = state->check = crc32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ break;
+#endif
+ case DICTID:
+ NEEDBITS(32);
+ strm->adler = state->check = REVERSE(hold);
+ INITBITS();
+ state->mode = DICT;
+ case DICT:
+ if (state->havedict == 0) {
+ RESTORE();
+ return Z_NEED_DICT;
+ }
+ strm->adler = state->check = adler32(0L, Z_NULL, 0);
+ state->mode = TYPE;
+ case TYPE:
+ if (flush == Z_BLOCK) goto inf_leave;
+ case TYPEDO:
+ if (state->last) {
+ BYTEBITS();
+ state->mode = CHECK;
+ break;
+ }
+ NEEDBITS(3);
+ state->last = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = STORED;
+ break;
+ case 1: /* fixed block */
+ fixedtables(state);
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ state->last ? " (last)" : ""));
+ state->mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ state->mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+ case STORED:
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ state->mode = BAD;
+ break;
+ }
+ state->length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %u\n",
+ state->length));
+ INITBITS();
+ state->mode = COPY;
+ case COPY:
+ copy = state->length;
+ if (copy) {
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ if (copy == 0) goto inf_leave;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ state->length -= copy;
+ break;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ state->mode = TYPE;
+ break;
+ case TABLE:
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+#ifndef PKZIP_BUG_WORKAROUND
+ if (state->nlen > 286 || state->ndist > 30) {
+ strm->msg = (char *)"too many length or distance symbols";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ Tracev((stderr, "inflate: table sizes ok\n"));
+ state->have = 0;
+ state->mode = LENLENS;
+ case LENLENS:
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 7;
+ ret = inflate_table(CODES, state->lens, 19, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+ state->have = 0;
+ state->mode = CODELENS;
+ case CODELENS:
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.val < 16) {
+ NEEDBITS(this.bits);
+ DROPBITS(this.bits);
+ state->lens[state->have++] = this.val;
+ }
+ else {
+ if (this.val == 16) {
+ NEEDBITS(this.bits + 2);
+ DROPBITS(this.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ len = state->lens[state->have - 1];
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (this.val == 17) {
+ NEEDBITS(this.bits + 3);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(this.bits + 7);
+ DROPBITS(this.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ state->mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (state->mode == BAD) break;
+
+ /* build code tables */
+ state->next = state->codes;
+ state->lencode = (code const FAR *)(state->next);
+ state->lenbits = 9;
+ ret = inflate_table(LENS, state->lens, state->nlen, &(state->next),
+ &(state->lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ state->mode = BAD;
+ break;
+ }
+ state->distcode = (code const FAR *)(state->next);
+ state->distbits = 6;
+ ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist,
+ &(state->next), &(state->distbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ state->mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ state->mode = LEN;
+ case LEN:
+ if (have >= 6 && left >= 258) {
+ RESTORE();
+ inflate_fast(strm, out);
+ LOAD();
+ break;
+ }
+ for (;;) {
+ this = state->lencode[BITS(state->lenbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (this.op && (this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ state->length = (unsigned)this.val;
+ if ((int)(this.op) == 0) {
+ Tracevv((stderr, this.val >= 0x20 && this.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", this.val));
+ state->mode = LIT;
+ break;
+ }
+ if (this.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ state->mode = TYPE;
+ break;
+ }
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ state->mode = BAD;
+ break;
+ }
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = LENEXT;
+ case LENEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->length += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+ Tracevv((stderr, "inflate: length %u\n", state->length));
+ state->mode = DIST;
+ case DIST:
+ for (;;) {
+ this = state->distcode[BITS(state->distbits)];
+ if ((unsigned)(this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((this.op & 0xf0) == 0) {
+ last = this;
+ for (;;) {
+ this = state->distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + this.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(this.bits);
+ if (this.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ state->mode = BAD;
+ break;
+ }
+ state->offset = (unsigned)this.val;
+ state->extra = (unsigned)(this.op) & 15;
+ state->mode = DISTEXT;
+ case DISTEXT:
+ if (state->extra) {
+ NEEDBITS(state->extra);
+ state->offset += BITS(state->extra);
+ DROPBITS(state->extra);
+ }
+#ifdef INFLATE_STRICT
+ if (state->offset > state->dmax) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+#endif
+ if (state->offset > state->whave + out - left) {
+ strm->msg = (char *)"invalid distance too far back";
+ state->mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %u\n", state->offset));
+ state->mode = MATCH;
+ case MATCH:
+ if (left == 0) goto inf_leave;
+ copy = out - left;
+ if (state->offset > copy) { /* copy from window */
+ copy = state->offset - copy;
+ if (copy > state->write) {
+ copy -= state->write;
+ from = state->window + (state->wsize - copy);
+ }
+ else
+ from = state->window + (state->write - copy);
+ if (copy > state->length) copy = state->length;
+ }
+ else { /* copy from output */
+ from = put - state->offset;
+ copy = state->length;
+ }
+ if (copy > left) copy = left;
+ left -= copy;
+ state->length -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ if (state->length == 0) state->mode = LEN;
+ break;
+ case LIT:
+ if (left == 0) goto inf_leave;
+ *put++ = (unsigned char)(state->length);
+ left--;
+ state->mode = LEN;
+ break;
+ case CHECK:
+ if (state->wrap) {
+ NEEDBITS(32);
+ out -= left;
+ strm->total_out += out;
+ state->total += out;
+ if (out)
+ strm->adler = state->check =
+ UPDATE(state->check, put - out, out);
+ out = left;
+ if ((
+#ifdef GUNZIP
+ state->flags ? hold :
+#endif
+ REVERSE(hold)) != state->check) {
+ strm->msg = (char *)"incorrect data check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: check matches trailer\n"));
+ }
+#ifdef GUNZIP
+ state->mode = LENGTH;
+ case LENGTH:
+ if (state->wrap && state->flags) {
+ NEEDBITS(32);
+ if (hold != (state->total & 0xffffffffUL)) {
+ strm->msg = (char *)"incorrect length check";
+ state->mode = BAD;
+ break;
+ }
+ INITBITS();
+ Tracev((stderr, "inflate: length matches trailer\n"));
+ }
+#endif
+ state->mode = DONE;
+ case DONE:
+ ret = Z_STREAM_END;
+ goto inf_leave;
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+ case MEM:
+ return Z_MEM_ERROR;
+ case SYNC:
+ default:
+ return Z_STREAM_ERROR;
+ }
+
+ /*
+ Return from inflate(), updating the total counts and the check value.
+ If there was no progress during the inflate() call, return a buffer
+ error. Call updatewindow() to create and/or update the window state.
+ Note: a memory error from inflate() is non-recoverable.
+ */
+ inf_leave:
+ RESTORE();
+ if (state->wsize || (state->mode < CHECK && out != strm->avail_out))
+ if (updatewindow(strm, out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ in -= strm->avail_in;
+ out -= strm->avail_out;
+ strm->total_in += in;
+ strm->total_out += out;
+ state->total += out;
+ if (state->wrap && out)
+ strm->adler = state->check =
+ UPDATE(state->check, strm->next_out - out, out);
+ strm->data_type = state->bits + (state->last ? 64 : 0) +
+ (state->mode == TYPE ? 128 : 0);
+ if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
+ ret = Z_BUF_ERROR;
+ return ret;
+}
+
+int ZEXPORT inflateEnd(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->window != Z_NULL) ZFREE(strm, state->window);
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength)
+z_streamp strm;
+const Bytef *dictionary;
+uInt dictLength;
+{
+ struct inflate_state FAR *state;
+ unsigned long id;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (state->wrap != 0 && state->mode != DICT)
+ return Z_STREAM_ERROR;
+
+ /* check for correct dictionary id */
+ if (state->mode == DICT) {
+ id = adler32(0L, Z_NULL, 0);
+ id = adler32(id, dictionary, dictLength);
+ if (id != state->check)
+ return Z_DATA_ERROR;
+ }
+
+ /* copy dictionary to window */
+ if (updatewindow(strm, strm->avail_out)) {
+ state->mode = MEM;
+ return Z_MEM_ERROR;
+ }
+ if (dictLength > state->wsize) {
+ zmemcpy(state->window, dictionary + dictLength - state->wsize,
+ state->wsize);
+ state->whave = state->wsize;
+ }
+ else {
+ zmemcpy(state->window + state->wsize - dictLength, dictionary,
+ dictLength);
+ state->whave = dictLength;
+ }
+ state->havedict = 1;
+ Tracev((stderr, "inflate: dictionary set\n"));
+ return Z_OK;
+}
+
+int ZEXPORT inflateGetHeader(strm, head)
+z_streamp strm;
+gz_headerp head;
+{
+ struct inflate_state FAR *state;
+
+ /* check state */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if ((state->wrap & 2) == 0) return Z_STREAM_ERROR;
+
+ /* save header structure */
+ state->head = head;
+ head->done = 0;
+ return Z_OK;
+}
+
+/*
+ Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found
+ or when out of input. When called, *have is the number of pattern bytes
+ found in order so far, in 0..3. On return *have is updated to the new
+ state. If on return *have equals four, then the pattern was found and the
+ return value is how many bytes were read including the last byte of the
+ pattern. If *have is less than four, then the pattern has not been found
+ yet and the return value is len. In the latter case, syncsearch() can be
+ called again with more data and the *have state. *have is initialized to
+ zero for the first call.
+ */
+local unsigned syncsearch(have, buf, len)
+unsigned FAR *have;
+unsigned char FAR *buf;
+unsigned len;
+{
+ unsigned got;
+ unsigned next;
+
+ got = *have;
+ next = 0;
+ while (next < len && got < 4) {
+ if ((int)(buf[next]) == (got < 2 ? 0 : 0xff))
+ got++;
+ else if (buf[next])
+ got = 0;
+ else
+ got = 4 - got;
+ next++;
+ }
+ *have = got;
+ return next;
+}
+
+int ZEXPORT inflateSync(strm)
+z_streamp strm;
+{
+ unsigned len; /* number of bytes to look at or looked at */
+ unsigned long in, out; /* temporary to save total_in and total_out */
+ unsigned char buf[4]; /* to restore bit buffer to byte string */
+ struct inflate_state FAR *state;
+
+ /* check parameters */
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR;
+
+ /* if first time, start search in bit buffer */
+ if (state->mode != SYNC) {
+ state->mode = SYNC;
+ state->hold <<= state->bits & 7;
+ state->bits -= state->bits & 7;
+ len = 0;
+ while (state->bits >= 8) {
+ buf[len++] = (unsigned char)(state->hold);
+ state->hold >>= 8;
+ state->bits -= 8;
+ }
+ state->have = 0;
+ syncsearch(&(state->have), buf, len);
+ }
+
+ /* search available input */
+ len = syncsearch(&(state->have), strm->next_in, strm->avail_in);
+ strm->avail_in -= len;
+ strm->next_in += len;
+ strm->total_in += len;
+
+ /* return no joy or set up to restart inflate() on a new block */
+ if (state->have != 4) return Z_DATA_ERROR;
+ in = strm->total_in; out = strm->total_out;
+ inflateReset(strm);
+ strm->total_in = in; strm->total_out = out;
+ state->mode = TYPE;
+ return Z_OK;
+}
+
+/*
+ Returns true if inflate is currently at the end of a block generated by
+ Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP
+ implementation to provide an additional safety check. PPP uses
+ Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored
+ block. When decompressing, PPP checks that at the end of input packet,
+ inflate is waiting for these length bytes.
+ */
+int ZEXPORT inflateSyncPoint(strm)
+z_streamp strm;
+{
+ struct inflate_state FAR *state;
+
+ if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+ return state->mode == STORED && state->bits == 0;
+}
+
+int ZEXPORT inflateCopy(dest, source)
+z_streamp dest;
+z_streamp source;
+{
+ struct inflate_state FAR *state;
+ struct inflate_state FAR *copy;
+ unsigned char FAR *window;
+ unsigned wsize;
+
+ /* check input */
+ if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL ||
+ source->zalloc == (alloc_func)0 || source->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)source->state;
+
+ /* allocate space */
+ copy = (struct inflate_state FAR *)
+ ZALLOC(source, 1, sizeof(struct inflate_state));
+ if (copy == Z_NULL) return Z_MEM_ERROR;
+ window = Z_NULL;
+ if (state->window != Z_NULL) {
+ window = (unsigned char FAR *)
+ ZALLOC(source, 1U << state->wbits, sizeof(unsigned char));
+ if (window == Z_NULL) {
+ ZFREE(source, copy);
+ return Z_MEM_ERROR;
+ }
+ }
+
+ /* copy state */
+ zmemcpy(dest, source, sizeof(z_stream));
+ zmemcpy(copy, state, sizeof(struct inflate_state));
+ if (state->lencode >= state->codes &&
+ state->lencode <= state->codes + ENOUGH - 1) {
+ copy->lencode = copy->codes + (state->lencode - state->codes);
+ copy->distcode = copy->codes + (state->distcode - state->codes);
+ }
+ copy->next = copy->codes + (state->next - state->codes);
+ if (window != Z_NULL) {
+ wsize = 1U << state->wbits;
+ zmemcpy(window, state->window, wsize);
+ }
+ copy->window = window;
+ dest->state = (struct internal_state FAR *)copy;
+ return Z_OK;
+}
diff --git a/src/lib/zlib/inflate.h b/src/lib/zlib/inflate.h
new file mode 100644
index 00000000000..07bd3e78a7c
--- /dev/null
+++ b/src/lib/zlib/inflate.h
@@ -0,0 +1,115 @@
+/* inflate.h -- internal inflate state definition
+ * Copyright (C) 1995-2004 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* define NO_GZIP when compiling if you want to disable gzip header and
+ trailer decoding by inflate(). NO_GZIP would be used to avoid linking in
+ the crc code when it is not needed. For shared libraries, gzip decoding
+ should be left enabled. */
+#ifndef NO_GZIP
+# define GUNZIP
+#endif
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ HEAD, /* i: waiting for magic header */
+ FLAGS, /* i: waiting for method and flags (gzip) */
+ TIME, /* i: waiting for modification time (gzip) */
+ OS, /* i: waiting for extra flags and operating system (gzip) */
+ EXLEN, /* i: waiting for extra length (gzip) */
+ EXTRA, /* i: waiting for extra bytes (gzip) */
+ NAME, /* i: waiting for end of file name (gzip) */
+ COMMENT, /* i: waiting for end of comment (gzip) */
+ HCRC, /* i: waiting for header crc (gzip) */
+ DICTID, /* i: waiting for dictionary check value */
+ DICT, /* waiting for inflateSetDictionary() call */
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ TYPEDO, /* i: same, but skip check to exit inflate on new block */
+ STORED, /* i: waiting for stored size (length and complement) */
+ COPY, /* i/o: waiting for input or output to copy stored block */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LENLENS, /* i: waiting for code length code lengths */
+ CODELENS, /* i: waiting for length/lit and distance code lengths */
+ LEN, /* i: waiting for length/lit code */
+ LENEXT, /* i: waiting for length extra bits */
+ DIST, /* i: waiting for distance code */
+ DISTEXT, /* i: waiting for distance extra bits */
+ MATCH, /* o: waiting for output space to copy string */
+ LIT, /* o: waiting for output space to write literal */
+ CHECK, /* i: waiting for 32-bit check value */
+ LENGTH, /* i: waiting for 32-bit length (gzip) */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD, /* got a data error -- remain here until reset */
+ MEM, /* got an inflate() memory error -- remain here until reset */
+ SYNC /* looking for synchronization bytes to restart inflate() */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to the BAD or MEM mode -- not shown for clarity)
+
+ Process header:
+ HEAD -> (gzip) or (zlib)
+ (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME
+ NAME -> COMMENT -> HCRC -> TYPE
+ (zlib) -> DICTID or TYPE
+ DICTID -> DICT -> TYPE
+ Read deflate blocks:
+ TYPE -> STORED or TABLE or LEN or CHECK
+ STORED -> COPY -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN
+ Read deflate codes:
+ LEN -> LENEXT or LIT or TYPE
+ LENEXT -> DIST -> DISTEXT -> MATCH -> LEN
+ LIT -> LEN
+ Process trailer:
+ CHECK -> LENGTH -> DONE
+ */
+
+/* state maintained between inflate() calls. Approximately 7K bytes. */
+struct inflate_state {
+ inflate_mode mode; /* current inflate mode */
+ int last; /* true if processing last block */
+ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
+ int havedict; /* true if dictionary provided */
+ int flags; /* gzip header method and flags (0 if zlib) */
+ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
+ unsigned long check; /* protected copy of check value */
+ unsigned long total; /* protected copy of output count */
+ gz_headerp head; /* where to save gzip header information */
+ /* sliding window */
+ unsigned wbits; /* log base 2 of requested window size */
+ unsigned wsize; /* window size or zero if not using window */
+ unsigned whave; /* valid bytes in the window */
+ unsigned write; /* window write index */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* bit accumulator */
+ unsigned long hold; /* input bit accumulator */
+ unsigned bits; /* number of bits in "in" */
+ /* for string and stored block copying */
+ unsigned length; /* literal or length of data to copy */
+ unsigned offset; /* distance back to copy string from */
+ /* for table and code decoding */
+ unsigned extra; /* extra bits needed */
+ /* fixed and dynamic code tables */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+};
diff --git a/src/lib/zlib/inftrees.c b/src/lib/zlib/inftrees.c
new file mode 100644
index 00000000000..8a9c13ff03d
--- /dev/null
+++ b/src/lib/zlib/inftrees.c
@@ -0,0 +1,329 @@
+/* inftrees.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+
+#define MAXBITS 15
+
+const char inflate_copyright[] =
+ " inflate 1.2.3 Copyright 1995-2005 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int inflate_table(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code this; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
+ 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
+ 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196};
+ static const unsigned short dbase[32] = { /* Distance codes 0..29 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
+ 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
+ 8193, 12289, 16385, 24577, 0, 0};
+ static const unsigned short dext[32] = { /* Distance codes 0..29 extra */
+ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
+ 28, 28, 29, 29, 64, 64};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) { /* no symbols to code at all */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)1;
+ this.val = (unsigned short)0;
+ *(*table)++ = this; /* make a table to force an error */
+ *(*table)++ = this;
+ *bits = 1;
+ return 0; /* no symbols, but wait for decoding to report error */
+ }
+ for (min = 1; min <= MAXBITS; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked when a LENS table is being made
+ against the space in *table, ENOUGH, minus the maximum space needed by
+ the worst case distance code, MAXD. This should never happen, but the
+ sufficiency of ENOUGH has not been proven exhaustively, hence the check.
+ This assumes that when type == LENS, bits == 9.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ this.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ this.op = (unsigned char)0;
+ this.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ this.op = (unsigned char)(extra[work[sym]]);
+ this.val = base[work[sym]];
+ }
+ else {
+ this.op = (unsigned char)(32 + 64); /* end of block */
+ this.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ min = fill; /* save offset to next table */
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = this;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += min; /* here min is 1 << curr */
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if (type == LENS && used >= ENOUGH - MAXD)
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)(len - drop);
+ this.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ this.bits = (unsigned char)len;
+ }
+
+ /* put invalid code marker in table */
+ next[huff >> drop] = this;
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
diff --git a/src/lib/zlib/inftrees.h b/src/lib/zlib/inftrees.h
new file mode 100644
index 00000000000..b1104c87e76
--- /dev/null
+++ b/src/lib/zlib/inftrees.h
@@ -0,0 +1,55 @@
+/* inftrees.h -- header to use inftrees.c
+ * Copyright (C) 1995-2005 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 0001eeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of dynamic tree. The maximum found in a long but non-
+ exhaustive search was 1444 code structures (852 for length/literals
+ and 592 for distances, the latter actually the result of an
+ exhaustive search). The true maximum is not known, but the value
+ below is more than safe. */
+#define ENOUGH 2048
+#define MAXD 592
+
+/* Type of code to build for inftable() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+extern int inflate_table OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
diff --git a/src/lib/zlib/minigzip.c b/src/lib/zlib/minigzip.c
new file mode 100644
index 00000000000..4524b96a1d6
--- /dev/null
+++ b/src/lib/zlib/minigzip.c
@@ -0,0 +1,322 @@
+/* minigzip.c -- simulate gzip using the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * minigzip is a minimal implementation of the gzip utility. This is
+ * only an example of using zlib and isn't meant to replace the
+ * full-featured gzip. No attempt is made to deal with file systems
+ * limiting names to 14 or 8+3 characters, etc... Error checking is
+ * very limited. So use minigzip only for testing; use gzip for the
+ * real thing. On MSDOS, use only on file names without extension
+ * or in pipe mode.
+ */
+
+/* @(#) $Id$ */
+
+#include <stdio.h>
+#include "zlib.h"
+
+#ifdef STDC
+# include <string.h>
+# include <stdlib.h>
+#endif
+
+#ifdef USE_MMAP
+# include <sys/types.h>
+# include <sys/mman.h>
+# include <sys/stat.h>
+#endif
+
+#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
+# include <fcntl.h>
+# include <io.h>
+# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+# define SET_BINARY_MODE(file)
+#endif
+
+#ifdef VMS
+# define unlink delete
+# define GZ_SUFFIX "-gz"
+#endif
+#ifdef RISCOS
+# define unlink remove
+# define GZ_SUFFIX "-gz"
+# define fileno(file) file->__file
+#endif
+#if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fileno */
+#endif
+
+#ifndef WIN32 /* unlink already in stdio.h for WIN32 */
+ extern int unlink OF((const char *));
+#endif
+
+#ifndef GZ_SUFFIX
+# define GZ_SUFFIX ".gz"
+#endif
+#define SUFFIX_LEN (sizeof(GZ_SUFFIX)-1)
+
+#define BUFLEN 16384
+#define MAX_NAME_LEN 1024
+
+#ifdef MAXSEG_64K
+# define local static
+ /* Needed for systems with limitation on stack size. */
+#else
+# define local
+#endif
+
+char *prog;
+
+void error OF((const char *msg));
+void gz_compress OF((FILE *in, gzFile out));
+#ifdef USE_MMAP
+int gz_compress_mmap OF((FILE *in, gzFile out));
+#endif
+void gz_uncompress OF((gzFile in, FILE *out));
+void file_compress OF((char *file, char *mode));
+void file_uncompress OF((char *file));
+int main OF((int argc, char *argv[]));
+
+/* ===========================================================================
+ * Display error message and exit
+ */
+void error(msg)
+ const char *msg;
+{
+ fprintf(stderr, "%s: %s\n", prog, msg);
+ exit(1);
+}
+
+/* ===========================================================================
+ * Compress input to output then close both files.
+ */
+
+void gz_compress(in, out)
+ FILE *in;
+ gzFile out;
+{
+ local char buf[BUFLEN];
+ int len;
+ int err;
+
+#ifdef USE_MMAP
+ /* Try first compressing with mmap. If mmap fails (minigzip used in a
+ * pipe), use the normal fread loop.
+ */
+ if (gz_compress_mmap(in, out) == Z_OK) return;
+#endif
+ for (;;) {
+ len = (int)fread(buf, 1, sizeof(buf), in);
+ if (ferror(in)) {
+ perror("fread");
+ exit(1);
+ }
+ if (len == 0) break;
+
+ if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err));
+ }
+ fclose(in);
+ if (gzclose(out) != Z_OK) error("failed gzclose");
+}
+
+#ifdef USE_MMAP /* MMAP version, Miguel Albrecht <malbrech@eso.org> */
+
+/* Try compressing the input file at once using mmap. Return Z_OK if
+ * if success, Z_ERRNO otherwise.
+ */
+int gz_compress_mmap(in, out)
+ FILE *in;
+ gzFile out;
+{
+ int len;
+ int err;
+ int ifd = fileno(in);
+ caddr_t buf; /* mmap'ed buffer for the entire input file */
+ off_t buf_len; /* length of the input file */
+ struct stat sb;
+
+ /* Determine the size of the file, needed for mmap: */
+ if (fstat(ifd, &sb) < 0) return Z_ERRNO;
+ buf_len = sb.st_size;
+ if (buf_len <= 0) return Z_ERRNO;
+
+ /* Now do the actual mmap: */
+ buf = mmap((caddr_t) 0, buf_len, PROT_READ, MAP_SHARED, ifd, (off_t)0);
+ if (buf == (caddr_t)(-1)) return Z_ERRNO;
+
+ /* Compress the whole file at once: */
+ len = gzwrite(out, (char *)buf, (unsigned)buf_len);
+
+ if (len != (int)buf_len) error(gzerror(out, &err));
+
+ munmap(buf, buf_len);
+ fclose(in);
+ if (gzclose(out) != Z_OK) error("failed gzclose");
+ return Z_OK;
+}
+#endif /* USE_MMAP */
+
+/* ===========================================================================
+ * Uncompress input to output then close both files.
+ */
+void gz_uncompress(in, out)
+ gzFile in;
+ FILE *out;
+{
+ local char buf[BUFLEN];
+ int len;
+ int err;
+
+ for (;;) {
+ len = gzread(in, buf, sizeof(buf));
+ if (len < 0) error (gzerror(in, &err));
+ if (len == 0) break;
+
+ if ((int)fwrite(buf, 1, (unsigned)len, out) != len) {
+ error("failed fwrite");
+ }
+ }
+ if (fclose(out)) error("failed fclose");
+
+ if (gzclose(in) != Z_OK) error("failed gzclose");
+}
+
+
+/* ===========================================================================
+ * Compress the given file: create a corresponding .gz file and remove the
+ * original.
+ */
+void file_compress(file, mode)
+ char *file;
+ char *mode;
+{
+ local char outfile[MAX_NAME_LEN];
+ FILE *in;
+ gzFile out;
+
+ strcpy(outfile, file);
+ strcat(outfile, GZ_SUFFIX);
+
+ in = fopen(file, "rb");
+ if (in == NULL) {
+ perror(file);
+ exit(1);
+ }
+ out = gzopen(outfile, mode);
+ if (out == NULL) {
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile);
+ exit(1);
+ }
+ gz_compress(in, out);
+
+ unlink(file);
+}
+
+
+/* ===========================================================================
+ * Uncompress the given file and remove the original.
+ */
+void file_uncompress(file)
+ char *file;
+{
+ local char buf[MAX_NAME_LEN];
+ char *infile, *outfile;
+ FILE *out;
+ gzFile in;
+ uInt len = (uInt)strlen(file);
+
+ strcpy(buf, file);
+
+ if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) {
+ infile = file;
+ outfile = buf;
+ outfile[len-3] = '\0';
+ } else {
+ outfile = file;
+ infile = buf;
+ strcat(infile, GZ_SUFFIX);
+ }
+ in = gzopen(infile, "rb");
+ if (in == NULL) {
+ fprintf(stderr, "%s: can't gzopen %s\n", prog, infile);
+ exit(1);
+ }
+ out = fopen(outfile, "wb");
+ if (out == NULL) {
+ perror(file);
+ exit(1);
+ }
+
+ gz_uncompress(in, out);
+
+ unlink(infile);
+}
+
+
+/* ===========================================================================
+ * Usage: minigzip [-d] [-f] [-h] [-r] [-1 to -9] [files...]
+ * -d : decompress
+ * -f : compress with Z_FILTERED
+ * -h : compress with Z_HUFFMAN_ONLY
+ * -r : compress with Z_RLE
+ * -1 to -9 : compression level
+ */
+
+int main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int uncompr = 0;
+ gzFile file;
+ char outmode[20];
+
+ strcpy(outmode, "wb6 ");
+
+ prog = argv[0];
+ argc--, argv++;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "-d") == 0)
+ uncompr = 1;
+ else if (strcmp(*argv, "-f") == 0)
+ outmode[3] = 'f';
+ else if (strcmp(*argv, "-h") == 0)
+ outmode[3] = 'h';
+ else if (strcmp(*argv, "-r") == 0)
+ outmode[3] = 'R';
+ else if ((*argv)[0] == '-' && (*argv)[1] >= '1' && (*argv)[1] <= '9' &&
+ (*argv)[2] == 0)
+ outmode[2] = (*argv)[1];
+ else
+ break;
+ argc--, argv++;
+ }
+ if (outmode[3] == ' ')
+ outmode[3] = 0;
+ if (argc == 0) {
+ SET_BINARY_MODE(stdin);
+ SET_BINARY_MODE(stdout);
+ if (uncompr) {
+ file = gzdopen(fileno(stdin), "rb");
+ if (file == NULL) error("can't gzdopen stdin");
+ gz_uncompress(file, stdout);
+ } else {
+ file = gzdopen(fileno(stdout), outmode);
+ if (file == NULL) error("can't gzdopen stdout");
+ gz_compress(stdin, file);
+ }
+ } else {
+ do {
+ if (uncompr) {
+ file_uncompress(*argv);
+ } else {
+ file_compress(*argv, outmode);
+ }
+ } while (argv++, --argc);
+ }
+ return 0;
+}
diff --git a/src/lib/zlib/readme b/src/lib/zlib/readme
new file mode 100644
index 00000000000..758cc50020d
--- /dev/null
+++ b/src/lib/zlib/readme
@@ -0,0 +1,125 @@
+ZLIB DATA COMPRESSION LIBRARY
+
+zlib 1.2.3 is a general purpose data compression library. All the code is
+thread safe. The data format used by the zlib library is described by RFCs
+(Request for Comments) 1950 to 1952 in the files
+http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format)
+and rfc1952.txt (gzip format). These documents are also available in other
+formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
+of the library is given in the file example.c which also tests that the library
+is working correctly. Another example is given in the file minigzip.c. The
+compression library itself is composed of all source files except example.c and
+minigzip.c.
+
+To compile all files and run the test program, follow the instructions given at
+the top of Makefile. In short "make test; make install" should work for most
+machines. For Unix: "./configure; make test; make install". For MSDOS, use one
+of the special makefiles such as Makefile.msc. For VMS, use make_vms.com.
+
+Questions about zlib should be sent to <zlib@gzip.org>, or to Gilles Vollant
+<info@winimage.com> for the Windows DLL version. The zlib home page is
+http://www.zlib.org or http://www.gzip.org/zlib/ Before reporting a problem,
+please check this site to verify that you have the latest version of zlib;
+otherwise get the latest version and check whether the problem still exists or
+not.
+
+PLEASE read the zlib FAQ http://www.gzip.org/zlib/zlib_faq.html before asking
+for help.
+
+Mark Nelson <markn@ieee.org> wrote an article about zlib for the Jan. 1997
+issue of Dr. Dobb's Journal; a copy of the article is available in
+http://dogma.net/markn/articles/zlibtool/zlibtool.htm
+
+The changes made in version 1.2.3 are documented in the file ChangeLog.
+
+Unsupported third party contributions are provided in directory "contrib".
+
+A Java implementation of zlib is available in the Java Development Kit
+http://java.sun.com/j2se/1.4.2/docs/api/java/util/zip/package-summary.html
+See the zlib home page http://www.zlib.org for details.
+
+A Perl interface to zlib written by Paul Marquess <pmqs@cpan.org> is in the
+CPAN (Comprehensive Perl Archive Network) sites
+http://www.cpan.org/modules/by-module/Compress/
+
+A Python interface to zlib written by A.M. Kuchling <amk@amk.ca> is
+available in Python 1.5 and later versions, see
+http://www.python.org/doc/lib/module-zlib.html
+
+A zlib binding for TCL written by Andreas Kupries <a.kupries@westend.com> is
+availlable at http://www.oche.de/~akupries/soft/trf/trf_zip.html
+
+An experimental package to read and write files in .zip format, written on top
+of zlib by Gilles Vollant <info@winimage.com>, is available in the
+contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- For Windows DLL versions, please see win32/DLL_FAQ.txt
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization. With
+ -O, one libpng test fails. The test works in 32 bit mode (with the -n32
+ compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
+ when compiled with cc.
+
+- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
+ necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
+ other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS, BEOS and by some Mac compilers.
+
+- For PalmOs, see http://palmzlib.sourceforge.net/
+
+- When building a shared, i.e. dynamic library on Mac OS X, the library must be
+ installed before testing (do "make install" before "make test"), since the
+ library location is specified in the library.
+
+
+Acknowledgments:
+
+ The deflate format used by zlib was defined by Phil Katz. The deflate
+ and zlib specifications were written by L. Peter Deutsch. Thanks to all the
+ people who reported problems and suggested various improvements in zlib;
+ they are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-2004 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not*
+receiving lengthy legal documents to sign. The sources are provided
+for free but without warranty of any kind. The library has been
+entirely written by Jean-loup Gailly and Mark Adler; it does not
+include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include
+in the file ChangeLog history information documenting your changes. Please
+read the FAQ for more information on the distribution of modified source
+versions.
diff --git a/src/lib/zlib/trees.c b/src/lib/zlib/trees.c
new file mode 100644
index 00000000000..395e4e16814
--- /dev/null
+++ b/src/lib/zlib/trees.c
@@ -0,0 +1,1219 @@
+/* trees.c -- output deflated data using Huffman coding
+ * Copyright (C) 1995-2005 Jean-loup Gailly
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * ALGORITHM
+ *
+ * The "deflation" process uses several Huffman trees. The more
+ * common source values are represented by shorter bit sequences.
+ *
+ * Each code tree is stored in a compressed form which is itself
+ * a Huffman encoding of the lengths of all the code strings (in
+ * ascending order by source values). The actual code strings are
+ * reconstructed from the lengths in the inflate process, as described
+ * in the deflate specification.
+ *
+ * REFERENCES
+ *
+ * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification".
+ * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc
+ *
+ * Storer, James A.
+ * Data Compression: Methods and Theory, pp. 49-50.
+ * Computer Science Press, 1988. ISBN 0-7167-8156-5.
+ *
+ * Sedgewick, R.
+ * Algorithms, p290.
+ * Addison-Wesley, 1983. ISBN 0-201-06672-6.
+ */
+
+/* @(#) $Id$ */
+
+/* #define GEN_TREES_H */
+
+#include "deflate.h"
+
+#ifdef DEBUG
+# include <ctype.h>
+#endif
+
+/* ===========================================================================
+ * Constants
+ */
+
+#define MAX_BL_BITS 7
+/* Bit length codes must not exceed MAX_BL_BITS bits */
+
+#define END_BLOCK 256
+/* end of block literal code */
+
+#define REP_3_6 16
+/* repeat previous bit length 3-6 times (2 bits of repeat count) */
+
+#define REPZ_3_10 17
+/* repeat a zero length 3-10 times (3 bits of repeat count) */
+
+#define REPZ_11_138 18
+/* repeat a zero length 11-138 times (7 bits of repeat count) */
+
+local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */
+ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0};
+
+local const int extra_dbits[D_CODES] /* extra bits for each distance code */
+ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */
+ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7};
+
+local const uch bl_order[BL_CODES]
+ = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
+/* The lengths of the bit length codes are sent in order of decreasing
+ * probability, to avoid transmitting the lengths for unused bit length codes.
+ */
+
+#define Buf_size (8 * 2*sizeof(char))
+/* Number of bits used within bi_buf. (bi_buf might be implemented on
+ * more than 16 bits on some systems.)
+ */
+
+/* ===========================================================================
+ * Local data. These are initialized only once.
+ */
+
+#define DIST_CODE_LEN 512 /* see definition of array dist_code below */
+
+#if defined(GEN_TREES_H) || !defined(STDC)
+/* non ANSI compilers may not accept trees.h */
+
+local ct_data static_ltree[L_CODES+2];
+/* The static literal tree. Since the bit lengths are imposed, there is no
+ * need for the L_CODES extra codes used during heap construction. However
+ * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
+ * below).
+ */
+
+local ct_data static_dtree[D_CODES];
+/* The static distance tree. (Actually a trivial tree since all codes use
+ * 5 bits.)
+ */
+
+uch _dist_code[DIST_CODE_LEN];
+/* Distance codes. The first 256 values correspond to the distances
+ * 3 .. 258, the last 256 values correspond to the top 8 bits of
+ * the 15 bit distances.
+ */
+
+uch _length_code[MAX_MATCH-MIN_MATCH+1];
+/* length code for each normalized match length (0 == MIN_MATCH) */
+
+local int base_length[LENGTH_CODES];
+/* First normalized length for each code (0 = MIN_MATCH) */
+
+local int base_dist[D_CODES];
+/* First normalized distance for each code (0 = distance of 1) */
+
+#else
+# include "trees.h"
+#endif /* GEN_TREES_H */
+
+struct static_tree_desc_s {
+ const ct_data *static_tree; /* static tree or NULL */
+ const intf *extra_bits; /* extra bits for each code or NULL */
+ int extra_base; /* base index for extra_bits */
+ int elems; /* max number of elements in the tree */
+ int max_length; /* max bit length for the codes */
+};
+
+local static_tree_desc static_l_desc =
+{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS};
+
+local static_tree_desc static_d_desc =
+{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS};
+
+local static_tree_desc static_bl_desc =
+{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS};
+
+/* ===========================================================================
+ * Local (static) routines in this file.
+ */
+
+local void tr_static_init OF((void));
+local void init_block OF((deflate_state *s));
+local void pqdownheap OF((deflate_state *s, ct_data *tree, int k));
+local void gen_bitlen OF((deflate_state *s, tree_desc *desc));
+local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count));
+local void build_tree OF((deflate_state *s, tree_desc *desc));
+local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local void send_tree OF((deflate_state *s, ct_data *tree, int max_code));
+local int build_bl_tree OF((deflate_state *s));
+local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes,
+ int blcodes));
+local void compress_block OF((deflate_state *s, ct_data *ltree,
+ ct_data *dtree));
+local void set_data_type OF((deflate_state *s));
+local unsigned bi_reverse OF((unsigned value, int length));
+local void bi_windup OF((deflate_state *s));
+local void bi_flush OF((deflate_state *s));
+local void copy_block OF((deflate_state *s, charf *buf, unsigned len,
+ int header));
+
+#ifdef GEN_TREES_H
+local void gen_trees_header OF((void));
+#endif
+
+#ifndef DEBUG
+# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len)
+ /* Send a code of the given tree. c and tree must not have side effects */
+
+#else /* DEBUG */
+# define send_code(s, c, tree) \
+ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \
+ send_bits(s, tree[c].Code, tree[c].Len); }
+#endif
+
+/* ===========================================================================
+ * Output a short LSB first on the stream.
+ * IN assertion: there is enough room in pendingBuf.
+ */
+#define put_short(s, w) { \
+ put_byte(s, (uch)((w) & 0xff)); \
+ put_byte(s, (uch)((ush)(w) >> 8)); \
+}
+
+/* ===========================================================================
+ * Send a value on a given number of bits.
+ * IN assertion: length <= 16 and value fits in length bits.
+ */
+#ifdef DEBUG
+local void send_bits OF((deflate_state *s, int value, int length));
+
+local void send_bits(s, value, length)
+ deflate_state *s;
+ int value; /* value to send */
+ int length; /* number of bits */
+{
+ Tracevv((stderr," l %2d v %4x ", length, value));
+ Assert(length > 0 && length <= 15, "invalid length");
+ s->bits_sent += (ulg)length;
+
+ /* If not enough room in bi_buf, use (valid) bits from bi_buf and
+ * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid))
+ * unused bits in value.
+ */
+ if (s->bi_valid > (int)Buf_size - length) {
+ s->bi_buf |= (value << s->bi_valid);
+ put_short(s, s->bi_buf);
+ s->bi_buf = (ush)value >> (Buf_size - s->bi_valid);
+ s->bi_valid += length - Buf_size;
+ } else {
+ s->bi_buf |= value << s->bi_valid;
+ s->bi_valid += length;
+ }
+}
+#else /* !DEBUG */
+
+#define send_bits(s, value, length) \
+{ int len = length;\
+ if (s->bi_valid > (int)Buf_size - len) {\
+ int val = value;\
+ s->bi_buf |= (val << s->bi_valid);\
+ put_short(s, s->bi_buf);\
+ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\
+ s->bi_valid += len - Buf_size;\
+ } else {\
+ s->bi_buf |= (value) << s->bi_valid;\
+ s->bi_valid += len;\
+ }\
+}
+#endif /* DEBUG */
+
+
+/* the arguments must not have side effects */
+
+/* ===========================================================================
+ * Initialize the various 'constant' tables.
+ */
+local void tr_static_init()
+{
+#if defined(GEN_TREES_H) || !defined(STDC)
+ static int static_init_done = 0;
+ int n; /* iterates over tree elements */
+ int bits; /* bit counter */
+ int length; /* length value */
+ int code; /* code value */
+ int dist; /* distance index */
+ ush bl_count[MAX_BITS+1];
+ /* number of codes at each bit length for an optimal tree */
+
+ if (static_init_done) return;
+
+ /* For some embedded targets, global variables are not initialized: */
+ static_l_desc.static_tree = static_ltree;
+ static_l_desc.extra_bits = extra_lbits;
+ static_d_desc.static_tree = static_dtree;
+ static_d_desc.extra_bits = extra_dbits;
+ static_bl_desc.extra_bits = extra_blbits;
+
+ /* Initialize the mapping length (0..255) -> length code (0..28) */
+ length = 0;
+ for (code = 0; code < LENGTH_CODES-1; code++) {
+ base_length[code] = length;
+ for (n = 0; n < (1<<extra_lbits[code]); n++) {
+ _length_code[length++] = (uch)code;
+ }
+ }
+ Assert (length == 256, "tr_static_init: length != 256");
+ /* Note that the length 255 (match length 258) can be represented
+ * in two different ways: code 284 + 5 bits or code 285, so we
+ * overwrite length_code[255] to use the best encoding:
+ */
+ _length_code[length-1] = (uch)code;
+
+ /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
+ dist = 0;
+ for (code = 0 ; code < 16; code++) {
+ base_dist[code] = dist;
+ for (n = 0; n < (1<<extra_dbits[code]); n++) {
+ _dist_code[dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: dist != 256");
+ dist >>= 7; /* from now on, all distances are divided by 128 */
+ for ( ; code < D_CODES; code++) {
+ base_dist[code] = dist << 7;
+ for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
+ _dist_code[256 + dist++] = (uch)code;
+ }
+ }
+ Assert (dist == 256, "tr_static_init: 256+dist != 512");
+
+ /* Construct the codes of the static literal tree */
+ for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0;
+ n = 0;
+ while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++;
+ while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++;
+ while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++;
+ while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++;
+ /* Codes 286 and 287 do not exist, but we must include them in the
+ * tree construction to get a canonical Huffman tree (longest code
+ * all ones)
+ */
+ gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count);
+
+ /* The static distance tree is trivial: */
+ for (n = 0; n < D_CODES; n++) {
+ static_dtree[n].Len = 5;
+ static_dtree[n].Code = bi_reverse((unsigned)n, 5);
+ }
+ static_init_done = 1;
+
+# ifdef GEN_TREES_H
+ gen_trees_header();
+# endif
+#endif /* defined(GEN_TREES_H) || !defined(STDC) */
+}
+
+/* ===========================================================================
+ * Genererate the file trees.h describing the static trees.
+ */
+#ifdef GEN_TREES_H
+# ifndef DEBUG
+# include <stdio.h>
+# endif
+
+# define SEPARATOR(i, last, width) \
+ ((i) == (last)? "\n};\n\n" : \
+ ((i) % (width) == (width)-1 ? ",\n" : ", "))
+
+void gen_trees_header()
+{
+ FILE *header = fopen("trees.h", "w");
+ int i;
+
+ Assert (header != NULL, "Can't open trees.h");
+ fprintf(header,
+ "/* header created automatically with -DGEN_TREES_H */\n\n");
+
+ fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n");
+ for (i = 0; i < L_CODES+2; i++) {
+ fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code,
+ static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5));
+ }
+
+ fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code,
+ static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5));
+ }
+
+ fprintf(header, "const uch _dist_code[DIST_CODE_LEN] = {\n");
+ for (i = 0; i < DIST_CODE_LEN; i++) {
+ fprintf(header, "%2u%s", _dist_code[i],
+ SEPARATOR(i, DIST_CODE_LEN-1, 20));
+ }
+
+ fprintf(header, "const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {\n");
+ for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) {
+ fprintf(header, "%2u%s", _length_code[i],
+ SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20));
+ }
+
+ fprintf(header, "local const int base_length[LENGTH_CODES] = {\n");
+ for (i = 0; i < LENGTH_CODES; i++) {
+ fprintf(header, "%1u%s", base_length[i],
+ SEPARATOR(i, LENGTH_CODES-1, 20));
+ }
+
+ fprintf(header, "local const int base_dist[D_CODES] = {\n");
+ for (i = 0; i < D_CODES; i++) {
+ fprintf(header, "%5u%s", base_dist[i],
+ SEPARATOR(i, D_CODES-1, 10));
+ }
+
+ fclose(header);
+}
+#endif /* GEN_TREES_H */
+
+/* ===========================================================================
+ * Initialize the tree data structures for a new zlib stream.
+ */
+void _tr_init(s)
+ deflate_state *s;
+{
+ tr_static_init();
+
+ s->l_desc.dyn_tree = s->dyn_ltree;
+ s->l_desc.stat_desc = &static_l_desc;
+
+ s->d_desc.dyn_tree = s->dyn_dtree;
+ s->d_desc.stat_desc = &static_d_desc;
+
+ s->bl_desc.dyn_tree = s->bl_tree;
+ s->bl_desc.stat_desc = &static_bl_desc;
+
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+#ifdef DEBUG
+ s->compressed_len = 0L;
+ s->bits_sent = 0L;
+#endif
+
+ /* Initialize the first block of the first file: */
+ init_block(s);
+}
+
+/* ===========================================================================
+ * Initialize a new block.
+ */
+local void init_block(s)
+ deflate_state *s;
+{
+ int n; /* iterates over tree elements */
+
+ /* Initialize the trees. */
+ for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0;
+ for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0;
+ for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0;
+
+ s->dyn_ltree[END_BLOCK].Freq = 1;
+ s->opt_len = s->static_len = 0L;
+ s->last_lit = s->matches = 0;
+}
+
+#define SMALLEST 1
+/* Index within the heap array of least frequent node in the Huffman tree */
+
+
+/* ===========================================================================
+ * Remove the smallest element from the heap and recreate the heap with
+ * one less element. Updates heap and heap_len.
+ */
+#define pqremove(s, tree, top) \
+{\
+ top = s->heap[SMALLEST]; \
+ s->heap[SMALLEST] = s->heap[s->heap_len--]; \
+ pqdownheap(s, tree, SMALLEST); \
+}
+
+/* ===========================================================================
+ * Compares to subtrees, using the tree depth as tie breaker when
+ * the subtrees have equal frequency. This minimizes the worst case length.
+ */
+#define smaller(tree, n, m, depth) \
+ (tree[n].Freq < tree[m].Freq || \
+ (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m]))
+
+/* ===========================================================================
+ * Restore the heap property by moving down the tree starting at node k,
+ * exchanging a node with the smallest of its two sons if necessary, stopping
+ * when the heap property is re-established (each father smaller than its
+ * two sons).
+ */
+local void pqdownheap(s, tree, k)
+ deflate_state *s;
+ ct_data *tree; /* the tree to restore */
+ int k; /* node to move down */
+{
+ int v = s->heap[k];
+ int j = k << 1; /* left son of k */
+ while (j <= s->heap_len) {
+ /* Set j to the smallest of the two sons: */
+ if (j < s->heap_len &&
+ smaller(tree, s->heap[j+1], s->heap[j], s->depth)) {
+ j++;
+ }
+ /* Exit if v is smaller than both sons */
+ if (smaller(tree, v, s->heap[j], s->depth)) break;
+
+ /* Exchange v with the smallest son */
+ s->heap[k] = s->heap[j]; k = j;
+
+ /* And continue down the tree, setting j to the left son of k */
+ j <<= 1;
+ }
+ s->heap[k] = v;
+}
+
+/* ===========================================================================
+ * Compute the optimal bit lengths for a tree and update the total bit length
+ * for the current block.
+ * IN assertion: the fields freq and dad are set, heap[heap_max] and
+ * above are the tree nodes sorted by increasing frequency.
+ * OUT assertions: the field len is set to the optimal bit length, the
+ * array bl_count contains the frequencies for each bit length.
+ * The length opt_len is updated; static_len is also updated if stree is
+ * not null.
+ */
+local void gen_bitlen(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ int max_code = desc->max_code;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ const intf *extra = desc->stat_desc->extra_bits;
+ int base = desc->stat_desc->extra_base;
+ int max_length = desc->stat_desc->max_length;
+ int h; /* heap index */
+ int n, m; /* iterate over the tree elements */
+ int bits; /* bit length */
+ int xbits; /* extra bits */
+ ush f; /* frequency */
+ int overflow = 0; /* number of elements with bit length too large */
+
+ for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0;
+
+ /* In a first pass, compute the optimal bit lengths (which may
+ * overflow in the case of the bit length tree).
+ */
+ tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */
+
+ for (h = s->heap_max+1; h < HEAP_SIZE; h++) {
+ n = s->heap[h];
+ bits = tree[tree[n].Dad].Len + 1;
+ if (bits > max_length) bits = max_length, overflow++;
+ tree[n].Len = (ush)bits;
+ /* We overwrite tree[n].Dad which is no longer needed */
+
+ if (n > max_code) continue; /* not a leaf node */
+
+ s->bl_count[bits]++;
+ xbits = 0;
+ if (n >= base) xbits = extra[n-base];
+ f = tree[n].Freq;
+ s->opt_len += (ulg)f * (bits + xbits);
+ if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits);
+ }
+ if (overflow == 0) return;
+
+ Trace((stderr,"\nbit length overflow\n"));
+ /* This happens for example on obj2 and pic of the Calgary corpus */
+
+ /* Find the first bit length which could increase: */
+ do {
+ bits = max_length-1;
+ while (s->bl_count[bits] == 0) bits--;
+ s->bl_count[bits]--; /* move one leaf down the tree */
+ s->bl_count[bits+1] += 2; /* move one overflow item as its brother */
+ s->bl_count[max_length]--;
+ /* The brother of the overflow item also moves one step up,
+ * but this does not affect bl_count[max_length]
+ */
+ overflow -= 2;
+ } while (overflow > 0);
+
+ /* Now recompute all bit lengths, scanning in increasing frequency.
+ * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
+ * lengths instead of fixing only the wrong ones. This idea is taken
+ * from 'ar' written by Haruhiko Okumura.)
+ */
+ for (bits = max_length; bits != 0; bits--) {
+ n = s->bl_count[bits];
+ while (n != 0) {
+ m = s->heap[--h];
+ if (m > max_code) continue;
+ if ((unsigned) tree[m].Len != (unsigned) bits) {
+ Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
+ s->opt_len += ((long)bits - (long)tree[m].Len)
+ *(long)tree[m].Freq;
+ tree[m].Len = (ush)bits;
+ }
+ n--;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Generate the codes for a given tree and bit counts (which need not be
+ * optimal).
+ * IN assertion: the array bl_count contains the bit length statistics for
+ * the given tree and the field len is set for all tree elements.
+ * OUT assertion: the field code is set for all tree elements of non
+ * zero code length.
+ */
+local void gen_codes (tree, max_code, bl_count)
+ ct_data *tree; /* the tree to decorate */
+ int max_code; /* largest code with non zero frequency */
+ ushf *bl_count; /* number of codes at each bit length */
+{
+ ush next_code[MAX_BITS+1]; /* next code value for each bit length */
+ ush code = 0; /* running code value */
+ int bits; /* bit index */
+ int n; /* code index */
+
+ /* The distribution counts are first used to generate the code values
+ * without bit reversal.
+ */
+ for (bits = 1; bits <= MAX_BITS; bits++) {
+ next_code[bits] = code = (code + bl_count[bits-1]) << 1;
+ }
+ /* Check that the bit counts in bl_count are consistent. The last code
+ * must be all ones.
+ */
+ Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
+ "inconsistent bit counts");
+ Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
+
+ for (n = 0; n <= max_code; n++) {
+ int len = tree[n].Len;
+ if (len == 0) continue;
+ /* Now reverse the bits */
+ tree[n].Code = bi_reverse(next_code[len]++, len);
+
+ Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
+ n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
+ }
+}
+
+/* ===========================================================================
+ * Construct one Huffman tree and assigns the code bit strings and lengths.
+ * Update the total bit length for the current block.
+ * IN assertion: the field freq is set for all tree elements.
+ * OUT assertions: the fields len and code are set to the optimal bit length
+ * and corresponding code. The length opt_len is updated; static_len is
+ * also updated if stree is not null. The field max_code is set.
+ */
+local void build_tree(s, desc)
+ deflate_state *s;
+ tree_desc *desc; /* the tree descriptor */
+{
+ ct_data *tree = desc->dyn_tree;
+ const ct_data *stree = desc->stat_desc->static_tree;
+ int elems = desc->stat_desc->elems;
+ int n, m; /* iterate over heap elements */
+ int max_code = -1; /* largest code with non zero frequency */
+ int node; /* new node being created */
+
+ /* Construct the initial heap, with least frequent element in
+ * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
+ * heap[0] is not used.
+ */
+ s->heap_len = 0, s->heap_max = HEAP_SIZE;
+
+ for (n = 0; n < elems; n++) {
+ if (tree[n].Freq != 0) {
+ s->heap[++(s->heap_len)] = max_code = n;
+ s->depth[n] = 0;
+ } else {
+ tree[n].Len = 0;
+ }
+ }
+
+ /* The pkzip format requires that at least one distance code exists,
+ * and that at least one bit should be sent even if there is only one
+ * possible code. So to avoid special checks later on we force at least
+ * two codes of non zero frequency.
+ */
+ while (s->heap_len < 2) {
+ node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0);
+ tree[node].Freq = 1;
+ s->depth[node] = 0;
+ s->opt_len--; if (stree) s->static_len -= stree[node].Len;
+ /* node is 0 or 1 so it does not have extra bits */
+ }
+ desc->max_code = max_code;
+
+ /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
+ * establish sub-heaps of increasing lengths:
+ */
+ for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n);
+
+ /* Construct the Huffman tree by repeatedly combining the least two
+ * frequent nodes.
+ */
+ node = elems; /* next internal node of the tree */
+ do {
+ pqremove(s, tree, n); /* n = node of least frequency */
+ m = s->heap[SMALLEST]; /* m = node of next least frequency */
+
+ s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */
+ s->heap[--(s->heap_max)] = m;
+
+ /* Create a new node father of n and m */
+ tree[node].Freq = tree[n].Freq + tree[m].Freq;
+ s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ?
+ s->depth[n] : s->depth[m]) + 1);
+ tree[n].Dad = tree[m].Dad = (ush)node;
+#ifdef DUMP_BL_TREE
+ if (tree == s->bl_tree) {
+ fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)",
+ node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq);
+ }
+#endif
+ /* and insert the new node in the heap */
+ s->heap[SMALLEST] = node++;
+ pqdownheap(s, tree, SMALLEST);
+
+ } while (s->heap_len >= 2);
+
+ s->heap[--(s->heap_max)] = s->heap[SMALLEST];
+
+ /* At this point, the fields freq and dad are set. We can now
+ * generate the bit lengths.
+ */
+ gen_bitlen(s, (tree_desc *)desc);
+
+ /* The field len is now set, we can generate the bit codes */
+ gen_codes ((ct_data *)tree, max_code, s->bl_count);
+}
+
+/* ===========================================================================
+ * Scan a literal or distance tree to determine the frequencies of the codes
+ * in the bit length tree.
+ */
+local void scan_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ if (nextlen == 0) max_count = 138, min_count = 3;
+ tree[max_code+1].Len = (ush)0xffff; /* guard */
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ s->bl_tree[curlen].Freq += count;
+ } else if (curlen != 0) {
+ if (curlen != prevlen) s->bl_tree[curlen].Freq++;
+ s->bl_tree[REP_3_6].Freq++;
+ } else if (count <= 10) {
+ s->bl_tree[REPZ_3_10].Freq++;
+ } else {
+ s->bl_tree[REPZ_11_138].Freq++;
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Send a literal or distance tree in compressed form, using the codes in
+ * bl_tree.
+ */
+local void send_tree (s, tree, max_code)
+ deflate_state *s;
+ ct_data *tree; /* the tree to be scanned */
+ int max_code; /* and its largest code of non zero frequency */
+{
+ int n; /* iterates over all tree elements */
+ int prevlen = -1; /* last emitted length */
+ int curlen; /* length of current code */
+ int nextlen = tree[0].Len; /* length of next code */
+ int count = 0; /* repeat count of the current code */
+ int max_count = 7; /* max repeat count */
+ int min_count = 4; /* min repeat count */
+
+ /* tree[max_code+1].Len = -1; */ /* guard already set */
+ if (nextlen == 0) max_count = 138, min_count = 3;
+
+ for (n = 0; n <= max_code; n++) {
+ curlen = nextlen; nextlen = tree[n+1].Len;
+ if (++count < max_count && curlen == nextlen) {
+ continue;
+ } else if (count < min_count) {
+ do { send_code(s, curlen, s->bl_tree); } while (--count != 0);
+
+ } else if (curlen != 0) {
+ if (curlen != prevlen) {
+ send_code(s, curlen, s->bl_tree); count--;
+ }
+ Assert(count >= 3 && count <= 6, " 3_6?");
+ send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2);
+
+ } else if (count <= 10) {
+ send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3);
+
+ } else {
+ send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7);
+ }
+ count = 0; prevlen = curlen;
+ if (nextlen == 0) {
+ max_count = 138, min_count = 3;
+ } else if (curlen == nextlen) {
+ max_count = 6, min_count = 3;
+ } else {
+ max_count = 7, min_count = 4;
+ }
+ }
+}
+
+/* ===========================================================================
+ * Construct the Huffman tree for the bit lengths and return the index in
+ * bl_order of the last bit length code to send.
+ */
+local int build_bl_tree(s)
+ deflate_state *s;
+{
+ int max_blindex; /* index of last bit length code of non zero freq */
+
+ /* Determine the bit length frequencies for literal and distance trees */
+ scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code);
+ scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code);
+
+ /* Build the bit length tree: */
+ build_tree(s, (tree_desc *)(&(s->bl_desc)));
+ /* opt_len now includes the length of the tree representations, except
+ * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
+ */
+
+ /* Determine the number of bit length codes to send. The pkzip format
+ * requires that at least 4 bit length codes be sent. (appnote.txt says
+ * 3 but the actual value used is 4.)
+ */
+ for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
+ if (s->bl_tree[bl_order[max_blindex]].Len != 0) break;
+ }
+ /* Update opt_len to include the bit length tree and counts */
+ s->opt_len += 3*(max_blindex+1) + 5+5+4;
+ Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
+ s->opt_len, s->static_len));
+
+ return max_blindex;
+}
+
+/* ===========================================================================
+ * Send the header for a block using dynamic Huffman trees: the counts, the
+ * lengths of the bit length codes, the literal tree and the distance tree.
+ * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
+ */
+local void send_all_trees(s, lcodes, dcodes, blcodes)
+ deflate_state *s;
+ int lcodes, dcodes, blcodes; /* number of codes for each tree */
+{
+ int rank; /* index in bl_order */
+
+ Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
+ Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
+ "too many codes");
+ Tracev((stderr, "\nbl counts: "));
+ send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
+ send_bits(s, dcodes-1, 5);
+ send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
+ for (rank = 0; rank < blcodes; rank++) {
+ Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
+ send_bits(s, s->bl_tree[bl_order[rank]].Len, 3);
+ }
+ Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */
+ Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
+
+ send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */
+ Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
+}
+
+/* ===========================================================================
+ * Send a stored block
+ */
+void _tr_stored_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */
+#ifdef DEBUG
+ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L;
+ s->compressed_len += (stored_len + 4) << 3;
+#endif
+ copy_block(s, buf, (unsigned)stored_len, 1); /* with header */
+}
+
+/* ===========================================================================
+ * Send one empty static block to give enough lookahead for inflate.
+ * This takes 10 bits, of which 7 may remain in the bit buffer.
+ * The current inflate code requires 9 bits of lookahead. If the
+ * last two codes for the previous block (real code plus EOB) were coded
+ * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode
+ * the last real code. In this case we send two empty static blocks instead
+ * of one. (There are no problems if the previous block is stored or fixed.)
+ * To simplify the code, we assume the worst case of last real code encoded
+ * on one bit only.
+ */
+void _tr_align(s)
+ deflate_state *s;
+{
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L; /* 3 for block type, 7 for EOB */
+#endif
+ bi_flush(s);
+ /* Of the 10 bits for the empty block, we have already sent
+ * (10 - bi_valid) bits. The lookahead for the last real code (before
+ * the EOB of the previous block) was thus at least one plus the length
+ * of the EOB plus what we have just sent of the empty static block.
+ */
+ if (1 + s->last_eob_len + 10 - s->bi_valid < 9) {
+ send_bits(s, STATIC_TREES<<1, 3);
+ send_code(s, END_BLOCK, static_ltree);
+#ifdef DEBUG
+ s->compressed_len += 10L;
+#endif
+ bi_flush(s);
+ }
+ s->last_eob_len = 7;
+}
+
+/* ===========================================================================
+ * Determine the best encoding for the current block: dynamic trees, static
+ * trees or store, and output the encoded block to the zip file.
+ */
+void _tr_flush_block(s, buf, stored_len, eof)
+ deflate_state *s;
+ charf *buf; /* input block, or NULL if too old */
+ ulg stored_len; /* length of input block */
+ int eof; /* true if this is the last block for a file */
+{
+ ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */
+ int max_blindex = 0; /* index of last bit length code of non zero freq */
+
+ /* Build the Huffman trees unless a stored block is forced */
+ if (s->level > 0) {
+
+ /* Check if the file is binary or text */
+ if (stored_len > 0 && s->strm->data_type == Z_UNKNOWN)
+ set_data_type(s);
+
+ /* Construct the literal and distance trees */
+ build_tree(s, (tree_desc *)(&(s->l_desc)));
+ Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+
+ build_tree(s, (tree_desc *)(&(s->d_desc)));
+ Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
+ s->static_len));
+ /* At this point, opt_len and static_len are the total bit lengths of
+ * the compressed block data, excluding the tree representations.
+ */
+
+ /* Build the bit length tree for the above two trees, and get the index
+ * in bl_order of the last bit length code to send.
+ */
+ max_blindex = build_bl_tree(s);
+
+ /* Determine the best encoding. Compute the block lengths in bytes. */
+ opt_lenb = (s->opt_len+3+7)>>3;
+ static_lenb = (s->static_len+3+7)>>3;
+
+ Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
+ opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
+ s->last_lit));
+
+ if (static_lenb <= opt_lenb) opt_lenb = static_lenb;
+
+ } else {
+ Assert(buf != (char*)0, "lost buf");
+ opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
+ }
+
+#ifdef FORCE_STORED
+ if (buf != (char*)0) { /* force stored block */
+#else
+ if (stored_len+4 <= opt_lenb && buf != (char*)0) {
+ /* 4: two words for the lengths */
+#endif
+ /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
+ * Otherwise we can't have processed more than WSIZE input bytes since
+ * the last block flush, because compression would have been
+ * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
+ * transform a block into a stored block.
+ */
+ _tr_stored_block(s, buf, stored_len, eof);
+
+#ifdef FORCE_STATIC
+ } else if (static_lenb >= 0) { /* force static trees */
+#else
+ } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) {
+#endif
+ send_bits(s, (STATIC_TREES<<1)+eof, 3);
+ compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->static_len;
+#endif
+ } else {
+ send_bits(s, (DYN_TREES<<1)+eof, 3);
+ send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1,
+ max_blindex+1);
+ compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree);
+#ifdef DEBUG
+ s->compressed_len += 3 + s->opt_len;
+#endif
+ }
+ Assert (s->compressed_len == s->bits_sent, "bad compressed size");
+ /* The above check is made mod 2^32, for files larger than 512 MB
+ * and uLong implemented on 32 bits.
+ */
+ init_block(s);
+
+ if (eof) {
+ bi_windup(s);
+#ifdef DEBUG
+ s->compressed_len += 7; /* align on byte boundary */
+#endif
+ }
+ Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
+ s->compressed_len-7*eof));
+}
+
+/* ===========================================================================
+ * Save the match info and tally the frequency counts. Return true if
+ * the current block must be flushed.
+ */
+int _tr_tally (s, dist, lc)
+ deflate_state *s;
+ unsigned dist; /* distance of matched string */
+ unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
+{
+ s->d_buf[s->last_lit] = (ush)dist;
+ s->l_buf[s->last_lit++] = (uch)lc;
+ if (dist == 0) {
+ /* lc is the unmatched char */
+ s->dyn_ltree[lc].Freq++;
+ } else {
+ s->matches++;
+ /* Here, lc is the match length - MIN_MATCH */
+ dist--; /* dist = match distance - 1 */
+ Assert((ush)dist < (ush)MAX_DIST(s) &&
+ (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
+ (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
+
+ s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++;
+ s->dyn_dtree[d_code(dist)].Freq++;
+ }
+
+#ifdef TRUNCATE_BLOCK
+ /* Try to guess if it is profitable to stop the current block here */
+ if ((s->last_lit & 0x1fff) == 0 && s->level > 2) {
+ /* Compute an upper bound for the compressed length */
+ ulg out_length = (ulg)s->last_lit*8L;
+ ulg in_length = (ulg)((long)s->strstart - s->block_start);
+ int dcode;
+ for (dcode = 0; dcode < D_CODES; dcode++) {
+ out_length += (ulg)s->dyn_dtree[dcode].Freq *
+ (5L+extra_dbits[dcode]);
+ }
+ out_length >>= 3;
+ Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
+ s->last_lit, in_length, out_length,
+ 100L - out_length*100L/in_length));
+ if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1;
+ }
+#endif
+ return (s->last_lit == s->lit_bufsize-1);
+ /* We avoid equality with lit_bufsize because of wraparound at 64K
+ * on 16 bit machines and because stored blocks are restricted to
+ * 64K-1 bytes.
+ */
+}
+
+/* ===========================================================================
+ * Send the block data compressed using the given Huffman trees
+ */
+local void compress_block(s, ltree, dtree)
+ deflate_state *s;
+ ct_data *ltree; /* literal tree */
+ ct_data *dtree; /* distance tree */
+{
+ unsigned dist; /* distance of matched string */
+ int lc; /* match length or unmatched char (if dist == 0) */
+ unsigned lx = 0; /* running index in l_buf */
+ unsigned code; /* the code to send */
+ int extra; /* number of extra bits to send */
+
+ if (s->last_lit != 0) do {
+ dist = s->d_buf[lx];
+ lc = s->l_buf[lx++];
+ if (dist == 0) {
+ send_code(s, lc, ltree); /* send a literal byte */
+ Tracecv(isgraph(lc), (stderr," '%c' ", lc));
+ } else {
+ /* Here, lc is the match length - MIN_MATCH */
+ code = _length_code[lc];
+ send_code(s, code+LITERALS+1, ltree); /* send the length code */
+ extra = extra_lbits[code];
+ if (extra != 0) {
+ lc -= base_length[code];
+ send_bits(s, lc, extra); /* send the extra length bits */
+ }
+ dist--; /* dist is now the match distance - 1 */
+ code = d_code(dist);
+ Assert (code < D_CODES, "bad d_code");
+
+ send_code(s, code, dtree); /* send the distance code */
+ extra = extra_dbits[code];
+ if (extra != 0) {
+ dist -= base_dist[code];
+ send_bits(s, dist, extra); /* send the extra distance bits */
+ }
+ } /* literal or match pair ? */
+
+ /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
+ Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
+ "pendingBuf overflow");
+
+ } while (lx < s->last_lit);
+
+ send_code(s, END_BLOCK, ltree);
+ s->last_eob_len = ltree[END_BLOCK].Len;
+}
+
+/* ===========================================================================
+ * Set the data type to BINARY or TEXT, using a crude approximation:
+ * set it to Z_TEXT if all symbols are either printable characters (33 to 255)
+ * or white spaces (9 to 13, or 32); or set it to Z_BINARY otherwise.
+ * IN assertion: the fields Freq of dyn_ltree are set.
+ */
+local void set_data_type(s)
+ deflate_state *s;
+{
+ int n;
+
+ for (n = 0; n < 9; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ break;
+ if (n == 9)
+ for (n = 14; n < 32; n++)
+ if (s->dyn_ltree[n].Freq != 0)
+ break;
+ s->strm->data_type = (n == 32) ? Z_TEXT : Z_BINARY;
+}
+
+/* ===========================================================================
+ * Reverse the first len bits of a code, using straightforward code (a faster
+ * method would use a table)
+ * IN assertion: 1 <= len <= 15
+ */
+local unsigned bi_reverse(code, len)
+ unsigned code; /* the value to invert */
+ int len; /* its bit length */
+{
+ register unsigned res = 0;
+ do {
+ res |= code & 1;
+ code >>= 1, res <<= 1;
+ } while (--len > 0);
+ return res >> 1;
+}
+
+/* ===========================================================================
+ * Flush the bit buffer, keeping at most 7 bits in it.
+ */
+local void bi_flush(s)
+ deflate_state *s;
+{
+ if (s->bi_valid == 16) {
+ put_short(s, s->bi_buf);
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+ } else if (s->bi_valid >= 8) {
+ put_byte(s, (Byte)s->bi_buf);
+ s->bi_buf >>= 8;
+ s->bi_valid -= 8;
+ }
+}
+
+/* ===========================================================================
+ * Flush the bit buffer and align the output on a byte boundary
+ */
+local void bi_windup(s)
+ deflate_state *s;
+{
+ if (s->bi_valid > 8) {
+ put_short(s, s->bi_buf);
+ } else if (s->bi_valid > 0) {
+ put_byte(s, (Byte)s->bi_buf);
+ }
+ s->bi_buf = 0;
+ s->bi_valid = 0;
+#ifdef DEBUG
+ s->bits_sent = (s->bits_sent+7) & ~7;
+#endif
+}
+
+/* ===========================================================================
+ * Copy a stored block, storing first the length and its
+ * one's complement if requested.
+ */
+local void copy_block(s, buf, len, header)
+ deflate_state *s;
+ charf *buf; /* the input data */
+ unsigned len; /* its length */
+ int header; /* true if block header must be written */
+{
+ bi_windup(s); /* align on byte boundary */
+ s->last_eob_len = 8; /* enough lookahead for inflate */
+
+ if (header) {
+ put_short(s, (ush)len);
+ put_short(s, (ush)~len);
+#ifdef DEBUG
+ s->bits_sent += 2*16;
+#endif
+ }
+#ifdef DEBUG
+ s->bits_sent += (ulg)len<<3;
+#endif
+ while (len--) {
+ put_byte(s, *buf++);
+ }
+}
diff --git a/src/lib/zlib/trees.h b/src/lib/zlib/trees.h
new file mode 100644
index 00000000000..72facf900f7
--- /dev/null
+++ b/src/lib/zlib/trees.h
@@ -0,0 +1,128 @@
+/* header created automatically with -DGEN_TREES_H */
+
+local const ct_data static_ltree[L_CODES+2] = {
+{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}},
+{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}},
+{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}},
+{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}},
+{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}},
+{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}},
+{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}},
+{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}},
+{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}},
+{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}},
+{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}},
+{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}},
+{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}},
+{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}},
+{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}},
+{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}},
+{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}},
+{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}},
+{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}},
+{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}},
+{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}},
+{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}},
+{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}},
+{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}},
+{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}},
+{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}},
+{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}},
+{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}},
+{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}},
+{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}},
+{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}},
+{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}},
+{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}},
+{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}},
+{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}},
+{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}},
+{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}},
+{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}},
+{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}},
+{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}},
+{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}},
+{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}},
+{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}},
+{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}},
+{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}},
+{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}},
+{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}},
+{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}},
+{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}},
+{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}},
+{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}},
+{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}},
+{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}},
+{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}},
+{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}},
+{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}},
+{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}},
+{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}}
+};
+
+local const ct_data static_dtree[D_CODES] = {
+{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}},
+{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}},
+{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}},
+{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}},
+{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}},
+{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}}
+};
+
+const uch _dist_code[DIST_CODE_LEN] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8,
+ 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10,
+10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17,
+18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
+29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+};
+
+const uch _length_code[MAX_MATCH-MIN_MATCH+1]= {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12,
+13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16,
+17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19,
+19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22,
+22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23,
+23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28
+};
+
+local const int base_length[LENGTH_CODES] = {
+0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56,
+64, 80, 96, 112, 128, 160, 192, 224, 0
+};
+
+local const int base_dist[D_CODES] = {
+ 0, 1, 2, 3, 4, 6, 8, 12, 16, 24,
+ 32, 48, 64, 96, 128, 192, 256, 384, 512, 768,
+ 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576
+};
+
diff --git a/src/lib/zlib/uncompr.c b/src/lib/zlib/uncompr.c
new file mode 100644
index 00000000000..b59e3d0defb
--- /dev/null
+++ b/src/lib/zlib/uncompr.c
@@ -0,0 +1,61 @@
+/* uncompr.c -- decompress a memory buffer
+ * Copyright (C) 1995-2003 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+/* ===========================================================================
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted.
+*/
+int ZEXPORT uncompress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ z_stream stream;
+ int err;
+
+ stream.next_in = (Bytef*)source;
+ stream.avail_in = (uInt)sourceLen;
+ /* Check for source > 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+
+ err = inflateInit(&stream);
+ if (err != Z_OK) return err;
+
+ err = inflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ inflateEnd(&stream);
+ if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0))
+ return Z_DATA_ERROR;
+ return err;
+ }
+ *destLen = stream.total_out;
+
+ err = inflateEnd(&stream);
+ return err;
+}
diff --git a/src/lib/zlib/zconf.h b/src/lib/zlib/zconf.h
new file mode 100644
index 00000000000..03a9431c8be
--- /dev/null
+++ b/src/lib/zlib/zconf.h
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define deflateBound z_deflateBound
+# define deflatePrime z_deflatePrime
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateCopy z_inflateCopy
+# define inflateReset z_inflateReset
+# define inflateBack z_inflateBack
+# define inflateBackEnd z_inflateBackEnd
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+# define zError z_zError
+
+# define alloc_func z_alloc_func
+# define free_func z_free_func
+# define in_func z_in_func
+# define out_func z_out_func
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if defined(__OS400__)
+# define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+# define NO_vsnprintf
+# ifdef FAR
+# undef FAR
+# endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(deflateBound,"DEBND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(compressBound,"CMBND")
+# pragma map(inflate_table,"INTABL")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/src/lib/zlib/zconf.in.h b/src/lib/zlib/zconf.in.h
new file mode 100644
index 00000000000..03a9431c8be
--- /dev/null
+++ b/src/lib/zlib/zconf.in.h
@@ -0,0 +1,332 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ */
+#ifdef Z_PREFIX
+# define deflateInit_ z_deflateInit_
+# define deflate z_deflate
+# define deflateEnd z_deflateEnd
+# define inflateInit_ z_inflateInit_
+# define inflate z_inflate
+# define inflateEnd z_inflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateCopy z_deflateCopy
+# define deflateReset z_deflateReset
+# define deflateParams z_deflateParams
+# define deflateBound z_deflateBound
+# define deflatePrime z_deflatePrime
+# define inflateInit2_ z_inflateInit2_
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateCopy z_inflateCopy
+# define inflateReset z_inflateReset
+# define inflateBack z_inflateBack
+# define inflateBackEnd z_inflateBackEnd
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# define uncompress z_uncompress
+# define adler32 z_adler32
+# define crc32 z_crc32
+# define get_crc_table z_get_crc_table
+# define zError z_zError
+
+# define alloc_func z_alloc_func
+# define free_func z_free_func
+# define in_func z_in_func
+# define out_func z_out_func
+# define Byte z_Byte
+# define uInt z_uInt
+# define uLong z_uLong
+# define Bytef z_Bytef
+# define charf z_charf
+# define intf z_intf
+# define uIntf z_uIntf
+# define uLongf z_uLongf
+# define voidpf z_voidpf
+# define voidp z_voidp
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */
+# include <sys/types.h> /* for off_t */
+# include <unistd.h> /* for SEEK_* and off_t */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# define z_off_t off_t
+#endif
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if defined(__OS400__)
+# define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+# define NO_vsnprintf
+# ifdef FAR
+# undef FAR
+# endif
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+# pragma map(deflateInit_,"DEIN")
+# pragma map(deflateInit2_,"DEIN2")
+# pragma map(deflateEnd,"DEEND")
+# pragma map(deflateBound,"DEBND")
+# pragma map(inflateInit_,"ININ")
+# pragma map(inflateInit2_,"ININ2")
+# pragma map(inflateEnd,"INEND")
+# pragma map(inflateSync,"INSY")
+# pragma map(inflateSetDictionary,"INSEDI")
+# pragma map(compressBound,"CMBND")
+# pragma map(inflate_table,"INTABL")
+# pragma map(inflate_fast,"INFA")
+# pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/src/lib/zlib/zlib.h b/src/lib/zlib/zlib.h
new file mode 100644
index 00000000000..022817927ce
--- /dev/null
+++ b/src/lib/zlib/zlib.h
@@ -0,0 +1,1357 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.3, July 18th, 2005
+
+ Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.3"
+#define ZLIB_VERNUM 0x1230
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed
+ data. This version of the library supports only one compression method
+ (deflation) but other algorithms will be added later and will have the same
+ stream interface.
+
+ Compression can be done in a single step if the buffers are large
+ enough (for example if an input file is mmap'ed), or can be done by
+ repeated calls of the compression function. In the latter case, the
+ application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never
+ crash even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has
+ dropped to zero. It must update next_out and avail_out when avail_out
+ has dropped to zero. The application must initialize zalloc, zfree and
+ opaque before calling the init function. All other fields are set by the
+ compression library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this
+ if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS,
+ pointers returned by zalloc for objects of exactly 65536 bytes *must*
+ have their offset normalized to zero. The default allocation function
+ provided by this library ensures this (see zutil.c). To reduce memory
+ requirements and avoid any allocation of 64K objects, at the expense of
+ compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or
+ progress reports. After compression, total_in holds the total size of
+ the uncompressed data and may be saved for use in the decompressor
+ (particularly if the decompressor wants to decompress everything in
+ a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative
+ * values are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is
+ not compatible with the zlib.h header file used by the application.
+ This check is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller.
+ If zalloc and zfree are set to Z_NULL, deflateInit updates them to
+ use default allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at
+ all (the input data is simply copied a block at a time).
+ Z_DEFAULT_COMPRESSION requests a default compromise between speed and
+ compression (currently equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if level is not a valid compression level,
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION).
+ msg is set to null if there is no error message. deflateInit does not
+ perform any compression: this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce some
+ output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications).
+ Some output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating avail_in or avail_out accordingly; avail_out
+ should never be zero before the call. The application can consume the
+ compressed output when it wants, for example when the output buffer is full
+ (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK
+ and with zero avail_out, it must be called again after making room in the
+ output buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumualte before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In particular
+ avail_in is zero after the call if enough output space has been provided
+ before the call.) Flushing may degrade compression for some compression
+ algorithms and so it should be used only when necessary.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there
+ was enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the
+ stream are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least
+ the value returned by deflateBound (see below). If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect
+ the compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case,
+ msg may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the exact
+ value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller. msg is set to null if there is no error
+ message. inflateInit does not perform any decompression apart from reading
+ the zlib header if present: this will be done by inflate(). (So next_in and
+ avail_in may be modified, but next_out and avail_out are unchanged.)
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing
+ will resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there
+ is no more input data or no more space in the output buffer (see below
+ about the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming
+ more output, and updating the next_* and avail_* values accordingly.
+ The application can consume the uncompressed output when it wants, for
+ example when the output buffer is full (avail_out == 0), or after each
+ call of inflate(). If inflate returns Z_OK and with zero avail_out, it
+ must be called again after making room in the output buffer because there
+ might be more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH,
+ Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate() stop
+ if and when it gets to the next deflate block boundary. When decoding the
+ zlib or gzip format, this will cause inflate() to return immediately after
+ the header and before the first block. When doing a raw inflate, inflate()
+ will go ahead and process the first block, and will return when it gets to
+ the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64
+ if inflate() is currently decoding the last block in the deflate stream,
+ plus 128 if inflate() returned immediately after decoding an end-of-block
+ code or decoding the complete header up to just before the first byte of the
+ deflate stream. The end-of-block will not be indicated until all of the
+ uncompressed data from that block has been written to strm->next_out. The
+ number of unused bits may in general be greater than seven, except when
+ bit 7 of data_type is set, in which case the number of unused bits will be
+ less than eight.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step
+ (a single call of inflate), the parameter flush should be set to
+ Z_FINISH. In this case all pending input is processed and all pending
+ output is flushed; avail_out must be large enough to hold all the
+ uncompressed data. (The size of the uncompressed data may have been saved
+ by the compressor for this purpose.) The next operation on this stream must
+ be inflateEnd to deallocate the decompression state. The use of Z_FINISH
+ is never required, but can be used to inform inflate that a faster approach
+ may be used for the single inflate() call.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the only effect of the flush parameter in this implementation
+ is on the return value of inflate(), as noted below, or when it returns early
+ because Z_BLOCK is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the adler32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the adler32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() will decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically. Any information
+ contained in the gzip header is not retained, so applications that need that
+ information should instead use raw inflate, see inflateInit2() below, or
+ inflateBack() and perform their own processing of the gzip header and
+ trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may then
+ call inflateSync() to look for a good compression block if a partial recovery
+ of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any
+ pending output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by
+ the caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero),
+ no header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but
+ is slow and reduces compression ratio; memLevel=9 uses maximum memory
+ for optimal speed. The default value is 8. See zconf.h for total memory
+ usage as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as
+ Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy
+ parameter only affects the compression ratio but not the correctness of the
+ compressed output even if it is not set appropriately. Z_FIXED prevents the
+ use of dynamic Huffman codes, allowing for a simpler decoder for special
+ applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid
+ method). msg is set to null if there is no error message. deflateInit2 does
+ not perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any
+ call of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size in
+ deflate or deflate2. Thus the strings most likely to be useful should be
+ put at the end of the dictionary, not at the front. In addition, the
+ current implementation of deflate will use at most the window size minus
+ 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and
+ can consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state.
+ The stream will keep the same compression level and any other attributes
+ that may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different
+ strategy. If the compression level is changed, the input available so far
+ is compressed with the old level (and may be flushed); the new level will
+ take effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to
+ be compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR
+ if strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit()
+ or deflateInit2(). This would be used to allocate an output buffer
+ for deflation in a single pass, and so would be called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the
+ bits leftover from a previous deflate stream when appending to it. As such,
+ this function can only be used for raw deflate, and must be used before the
+ first deflate() call after a deflateInit2() or deflateReset(). bits must be
+ less than or equal to 16, and that many of the least significant bits of
+ value will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is
+ a crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg
+ is set to null if there is no error message. inflateInit2 does not perform
+ any decompression apart from reading the zlib header if present: this will
+ be done by inflate(). (So next_in and avail_in may be modified, but next_out
+ and avail_out are unchanged.)
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called
+ immediately after inflateInit2() or inflateReset() and before any call of
+ inflate() to set the dictionary. The application must insure that the
+ dictionary that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (such as NULL dictionary) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been found,
+ or Z_STREAM_ERROR if the stream structure was inconsistent. In the success
+ case, the application may save the current current value of total_in which
+ indicates where valid compressed data was found. In the error case, the
+ application may repeatedly call inflateSync, providing more input each time,
+ until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state.
+ The stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being NULL).
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK can be used to
+ force inflate() to return immediately after header processing is complete
+ and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When
+ any of extra, name, or comment are not Z_NULL and the respective field is
+ not present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the paramaters are invalid, Z_MEM_ERROR if the internal state could not
+ be allocated, or Z_VERSION_ERROR if the version of the library does not
+ match the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is more efficient than inflate() for
+ file i/o applications in that it avoids copying between the output and the
+ sliding window by simply making the window itself the output buffer. This
+ function trusts the application to not change the output buffer passed by
+ the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free
+ the allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects
+ only the raw deflate stream to decompress. This is different from the
+ normal behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format
+ error in the deflate stream (in which case strm->msg is set to indicate the
+ nature of the error), or Z_STREAM_ERROR if the stream was not properly
+ initialized. In the case of Z_BUF_ERROR, an input or output error can be
+ distinguished using strm->next_in which will be Z_NULL only if in() returned
+ an error. If strm->next is not Z_NULL, then the Z_BUF_ERROR was due to
+ out() returning non-zero. (in() will always be called before out(), so
+ strm->next_in is assured to be defined if out() returns non-zero.) Note
+ that inflateBack() cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the
+ basic stream-oriented functions. To simplify the interface, some
+ default options are assumed (compression level and memory usage,
+ standard memory allocation functions). The source code of these
+ utility functions can easily be modified if you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be at least the value returned
+ by compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+ This function can be used to compress a whole file at once if the
+ input file is mmap'ed.
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before
+ a compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total
+ size of the destination buffer, which must be large enough to hold the
+ entire uncompressed data. (The size of the uncompressed data must have
+ been saved previously by the compressor and transmitted to the decompressor
+ by some mechanism outside the scope of this compression library.)
+ Upon exit, destLen is the actual size of the compressed buffer.
+ This function can be used to decompress a whole file at once if the
+ input file is mmap'ed.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+typedef voidp gzFile;
+
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+/*
+ Opens a gzip (.gz) file for reading or writing. The mode parameter
+ is as in fopen ("rb" or "wb") but can also include a compression level
+ ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for
+ Huffman only compression as in "wb1h", or 'R' for run-length encoding
+ as in "wb1R". (See the description of deflateInit2 for more information
+ about the strategy parameter.)
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened or if there was
+ insufficient memory to allocate the (de)compression state; errno
+ can be checked to distinguish the two cases (if errno is zero, the
+ zlib error is Z_MEM_ERROR). */
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen() associates a gzFile with the file descriptor fd. File
+ descriptors are obtained from calls like open, dup, creat, pipe or
+ fileno (in the file has been previously opened with fopen).
+ The mode parameter is as in gzopen.
+ The next call of gzclose on the returned gzFile will also close the
+ file descriptor fd, just like fclose(fdopen(fd), mode) closes the file
+ descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode).
+ gzdopen returns NULL if there was insufficient memory to allocate
+ the (de)compression state.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file.
+ If the input file was not in gzip format, gzread copies the given number
+ of bytes into the buffer.
+ gzread returns the number of uncompressed bytes actually read (0 for
+ end of file, -1 for error). */
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes actually written
+ (0 in case of error).
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the args to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written (0 in case of error). The number of
+ uncompressed bytes written is limited to 4095. The caller should assure that
+ this limit is not exceeded. If it is exceeded, then gzprintf() will return
+ return an error (0) with nothing written. In this case, there may also be a
+ buffer overflow with unpredictable consequences, which is possible only if
+ zlib was compiled with the insecure functions sprintf() or vsprintf()
+ because the secure snprintf() or vsnprintf() functions were not available.
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or
+ a newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. The string is then terminated with a null
+ character.
+ gzgets returns buf, or Z_NULL in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file.
+ gzputc returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte
+ or -1 in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read again later.
+ Only one character of push-back is allowed. gzungetc() returns the
+ character pushed, or -1 on failure. gzungetc() will fail if a
+ character has been pushed but not read yet, or if c is -1. The pushed
+ character will be discarded if the stream is repositioned with gzseek()
+ or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter
+ flush is as in the deflate() function. The return value is the zlib
+ error number (see function gzerror below). gzflush returns Z_OK if
+ the flush parameter is Z_FINISH and all output could be flushed.
+ gzflush should be called only when strictly necessary because it can
+ degrade compression.
+*/
+
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+/*
+ Sets the starting position for the next gzread or gzwrite on the
+ given compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+/*
+ Returns the starting position for the next gzread or gzwrite on the
+ given compressed file. This position represents a number of bytes in the
+ uncompressed data stream.
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns 1 when EOF has previously been detected reading the given
+ input stream, otherwise zero.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns 1 if file is being read directly without decompression, otherwise
+ zero.
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file
+ and deallocates all the (de)compression state. The return value is the zlib
+ error number (see function gzerror below).
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the
+ given compressed file. errnum is set to zlib error number. If an
+ error occurred in the file system and not in the compression library,
+ errnum is set to Z_ERRNO and the application may consult errno
+ to get the exact error code.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the
+ compression library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is NULL, this function returns
+ the required initial value for the checksum.
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster. Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+/*
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is NULL, this function returns the required initial
+ value for the for the crc. Pre- and post-conditioning (one's complement) is
+ performed within this function so it shouldn't be done by the application.
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+/*
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;}; /* hack for buggy compilers */
+#endif
+
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp z));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */
diff --git a/src/lib/zlib/zutil.c b/src/lib/zlib/zutil.c
new file mode 100644
index 00000000000..d55f5948a37
--- /dev/null
+++ b/src/lib/zlib/zutil.c
@@ -0,0 +1,318 @@
+/* zutil.c -- target dependent utility functions for the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#ifndef NO_DUMMY_DECL
+struct internal_state {int dummy;}; /* for buggy compilers */
+#endif
+
+const char * const z_errmsg[10] = {
+"need dictionary", /* Z_NEED_DICT 2 */
+"stream end", /* Z_STREAM_END 1 */
+"", /* Z_OK 0 */
+"file error", /* Z_ERRNO (-1) */
+"stream error", /* Z_STREAM_ERROR (-2) */
+"data error", /* Z_DATA_ERROR (-3) */
+"insufficient memory", /* Z_MEM_ERROR (-4) */
+"buffer error", /* Z_BUF_ERROR (-5) */
+"incompatible version",/* Z_VERSION_ERROR (-6) */
+""};
+
+
+const char * ZEXPORT zlibVersion()
+{
+ return ZLIB_VERSION;
+}
+
+uLong ZEXPORT zlibCompileFlags()
+{
+ uLong flags;
+
+ flags = 0;
+ switch (sizeof(uInt)) {
+ case 2: break;
+ case 4: flags += 1; break;
+ case 8: flags += 2; break;
+ default: flags += 3;
+ }
+ switch (sizeof(uLong)) {
+ case 2: break;
+ case 4: flags += 1 << 2; break;
+ case 8: flags += 2 << 2; break;
+ default: flags += 3 << 2;
+ }
+ switch (sizeof(voidpf)) {
+ case 2: break;
+ case 4: flags += 1 << 4; break;
+ case 8: flags += 2 << 4; break;
+ default: flags += 3 << 4;
+ }
+ switch (sizeof(z_off_t)) {
+ case 2: break;
+ case 4: flags += 1 << 6; break;
+ case 8: flags += 2 << 6; break;
+ default: flags += 3 << 6;
+ }
+#ifdef DEBUG
+ flags += 1 << 8;
+#endif
+#if defined(ASMV) || defined(ASMINF)
+ flags += 1 << 9;
+#endif
+#ifdef ZLIB_WINAPI
+ flags += 1 << 10;
+#endif
+#ifdef BUILDFIXED
+ flags += 1 << 12;
+#endif
+#ifdef DYNAMIC_CRC_TABLE
+ flags += 1 << 13;
+#endif
+#ifdef NO_GZCOMPRESS
+ flags += 1L << 16;
+#endif
+#ifdef NO_GZIP
+ flags += 1L << 17;
+#endif
+#ifdef PKZIP_BUG_WORKAROUND
+ flags += 1L << 20;
+#endif
+#ifdef FASTEST
+ flags += 1L << 21;
+#endif
+#ifdef STDC
+# ifdef NO_vsnprintf
+ flags += 1L << 25;
+# ifdef HAS_vsprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_vsnprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#else
+ flags += 1L << 24;
+# ifdef NO_snprintf
+ flags += 1L << 25;
+# ifdef HAS_sprintf_void
+ flags += 1L << 26;
+# endif
+# else
+# ifdef HAS_snprintf_void
+ flags += 1L << 26;
+# endif
+# endif
+#endif
+ return flags;
+}
+
+#ifdef DEBUG
+
+# ifndef verbose
+# define verbose 0
+# endif
+int z_verbose = verbose;
+
+void z_error (m)
+ char *m;
+{
+ fprintf(stderr, "%s\n", m);
+ exit(1);
+}
+#endif
+
+/* exported to allow conversion of error code to string for compress() and
+ * uncompress()
+ */
+const char * ZEXPORT zError(err)
+ int err;
+{
+ return ERR_MSG(err);
+}
+
+#if defined(_WIN32_WCE)
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used.
+ */
+ int errno = 0;
+#endif
+
+#ifndef HAVE_MEMCPY
+
+void zmemcpy(dest, source, len)
+ Bytef* dest;
+ const Bytef* source;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = *source++; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+
+int zmemcmp(s1, s2, len)
+ const Bytef* s1;
+ const Bytef* s2;
+ uInt len;
+{
+ uInt j;
+
+ for (j = 0; j < len; j++) {
+ if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1;
+ }
+ return 0;
+}
+
+void zmemzero(dest, len)
+ Bytef* dest;
+ uInt len;
+{
+ if (len == 0) return;
+ do {
+ *dest++ = 0; /* ??? to be unrolled */
+ } while (--len != 0);
+}
+#endif
+
+
+#ifdef SYS16BIT
+
+#ifdef __TURBOC__
+/* Turbo C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+/* Turbo C malloc() does not allow dynamic allocation of 64K bytes
+ * and farmalloc(64K) returns a pointer with an offset of 8, so we
+ * must fix the pointer. Warning: the pointer must be put back to its
+ * original form in order to free it, use zcfree().
+ */
+
+#define MAX_PTR 10
+/* 10*64K = 640K */
+
+local int next_ptr = 0;
+
+typedef struct ptr_table_s {
+ voidpf org_ptr;
+ voidpf new_ptr;
+} ptr_table;
+
+local ptr_table table[MAX_PTR];
+/* This table is used to remember the original form of pointers
+ * to large buffers (64K). Such pointers are normalized with a zero offset.
+ * Since MSDOS is not a preemptive multitasking OS, this table is not
+ * protected from concurrent access. This hack doesn't work anyway on
+ * a protected system like OS/2. Use Microsoft C instead.
+ */
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ voidpf buf = opaque; /* just to make some compilers happy */
+ ulg bsize = (ulg)items*size;
+
+ /* If we allocate less than 65520 bytes, we assume that farmalloc
+ * will return a usable pointer which doesn't have to be normalized.
+ */
+ if (bsize < 65520L) {
+ buf = farmalloc(bsize);
+ if (*(ush*)&buf != 0) return buf;
+ } else {
+ buf = farmalloc(bsize + 16L);
+ }
+ if (buf == NULL || next_ptr >= MAX_PTR) return NULL;
+ table[next_ptr].org_ptr = buf;
+
+ /* Normalize the pointer to seg:0 */
+ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4;
+ *(ush*)&buf = 0;
+ table[next_ptr++].new_ptr = buf;
+ return buf;
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ int n;
+ if (*(ush*)&ptr != 0) { /* object < 64K */
+ farfree(ptr);
+ return;
+ }
+ /* Find the original pointer */
+ for (n = 0; n < next_ptr; n++) {
+ if (ptr != table[n].new_ptr) continue;
+
+ farfree(table[n].org_ptr);
+ while (++n < next_ptr) {
+ table[n-1] = table[n];
+ }
+ next_ptr--;
+ return;
+ }
+ ptr = opaque; /* just to make some compilers happy */
+ Assert(0, "zcfree: ptr not found");
+}
+
+#endif /* __TURBOC__ */
+
+
+#ifdef M_I86
+/* Microsoft C in 16-bit mode */
+
+# define MY_ZCALLOC
+
+#if (!defined(_MSC_VER) || (_MSC_VER <= 600))
+# define _halloc halloc
+# define _hfree hfree
+#endif
+
+voidpf zcalloc (voidpf opaque, unsigned items, unsigned size)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ return _halloc((long)items, size);
+}
+
+void zcfree (voidpf opaque, voidpf ptr)
+{
+ if (opaque) opaque = 0; /* to make compiler happy */
+ _hfree(ptr);
+}
+
+#endif /* M_I86 */
+
+#endif /* SYS16BIT */
+
+
+#ifndef MY_ZCALLOC /* Any system without a special alloc function */
+
+#ifndef STDC
+extern voidp malloc OF((uInt size));
+extern voidp calloc OF((uInt items, uInt size));
+extern void free OF((voidpf ptr));
+#endif
+
+voidpf zcalloc (opaque, items, size)
+ voidpf opaque;
+ unsigned items;
+ unsigned size;
+{
+ if (opaque) items += size - size; /* make compiler happy */
+ return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) :
+ (voidpf)calloc(items, size);
+}
+
+void zcfree (opaque, ptr)
+ voidpf opaque;
+ voidpf ptr;
+{
+ free(ptr);
+ if (opaque) return; /* make compiler happy */
+}
+
+#endif /* MY_ZCALLOC */
diff --git a/src/lib/zlib/zutil.h b/src/lib/zlib/zutil.h
new file mode 100644
index 00000000000..b7d5eff81b6
--- /dev/null
+++ b/src/lib/zlib/zutil.h
@@ -0,0 +1,269 @@
+/* zutil.h -- internal interface and configuration of the compression library
+ * Copyright (C) 1995-2005 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZUTIL_H
+#define ZUTIL_H
+
+#define ZLIB_INTERNAL
+#include "zlib.h"
+
+#ifdef STDC
+# ifndef _WIN32_WCE
+# include <stddef.h>
+# endif
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+# ifdef _WIN32_WCE
+ /* The Microsoft C Run-Time Library for Windows CE doesn't have
+ * errno. We define it as a global variable to simplify porting.
+ * Its value is always 0 and should not be used. We rename it to
+ * avoid conflict with other libraries that use the same workaround.
+ */
+# define errno z_errno
+# endif
+ extern int errno;
+#else
+# ifndef _WIN32_WCE
+# include <errno.h>
+# endif
+#endif
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+typedef unsigned char uch;
+typedef uch FAR uchf;
+typedef unsigned short ush;
+typedef ush FAR ushf;
+typedef unsigned long ulg;
+
+extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
+/* (size given to avoid silly warnings with Visual C++) */
+
+#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)]
+
+#define ERR_RETURN(strm,err) \
+ return (strm->msg = (char*)ERR_MSG(err), (err))
+/* To be used only when the state is known to be valid */
+
+ /* common constants */
+
+#ifndef DEF_WBITS
+# define DEF_WBITS MAX_WBITS
+#endif
+/* default windowBits for decompression. MAX_WBITS is for compression only */
+
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+/* default memLevel */
+
+#define STORED_BLOCK 0
+#define STATIC_TREES 1
+#define DYN_TREES 2
+/* The three kinds of block type */
+
+#define MIN_MATCH 3
+#define MAX_MATCH 258
+/* The minimum and maximum match lengths */
+
+#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */
+
+ /* target dependencies */
+
+#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32))
+# define OS_CODE 0x00
+# if defined(__TURBOC__) || defined(__BORLANDC__)
+# if(__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__))
+ /* Allow compilation with ANSI keywords only enabled */
+ void _Cdecl farfree( void *block );
+ void *_Cdecl farmalloc( unsigned long nbytes );
+# else
+# include <alloc.h>
+# endif
+# else /* MSC or DJGPP */
+# include <malloc.h>
+# endif
+#endif
+
+#ifdef AMIGA
+# define OS_CODE 0x01
+#endif
+
+#if defined(VAXC) || defined(VMS)
+# define OS_CODE 0x02
+# define F_OPEN(name, mode) \
+ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512")
+#endif
+
+#if defined(ATARI) || defined(atarist)
+# define OS_CODE 0x05
+#endif
+
+#ifdef OS2
+# define OS_CODE 0x06
+# ifdef M_I86
+ #include <malloc.h>
+# endif
+#endif
+
+#if defined(MACOS) || defined(TARGET_OS_MAC)
+# define OS_CODE 0x07
+# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os
+# include <unix.h> /* for fdopen */
+# else
+# ifndef fdopen
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# endif
+# endif
+#endif
+
+#ifdef TOPS20
+# define OS_CODE 0x0a
+#endif
+
+#ifdef WIN32
+# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */
+# define OS_CODE 0x0b
+# endif
+#endif
+
+#ifdef __50SERIES /* Prime/PRIMOS */
+# define OS_CODE 0x0f
+#endif
+
+#if defined(_BEOS_) || defined(RISCOS)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+#endif
+
+#if (defined(_MSC_VER) && (_MSC_VER > 600))
+# if defined(_WIN32_WCE)
+# define fdopen(fd,mode) NULL /* No fdopen() */
+# ifndef _PTRDIFF_T_DEFINED
+ typedef int ptrdiff_t;
+# define _PTRDIFF_T_DEFINED
+# endif
+# else
+# define fdopen(fd,type) _fdopen(fd,type)
+# endif
+#endif
+
+ /* common defaults */
+
+#ifndef OS_CODE
+# define OS_CODE 0x03 /* assume Unix */
+#endif
+
+#ifndef F_OPEN
+# define F_OPEN(name, mode) fopen((name), (mode))
+#endif
+
+ /* functions */
+
+#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#if defined(__CYGWIN__)
+# ifndef HAVE_VSNPRINTF
+# define HAVE_VSNPRINTF
+# endif
+#endif
+#ifndef HAVE_VSNPRINTF
+# ifdef MSDOS
+ /* vsnprintf may exist on some MS-DOS compilers (DJGPP?),
+ but for now we just assume it doesn't. */
+# define NO_vsnprintf
+# endif
+# ifdef __TURBOC__
+# define NO_vsnprintf
+# endif
+# ifdef WIN32
+ /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */
+# if !defined(vsnprintf) && !defined(NO_vsnprintf)
+# define vsnprintf _vsnprintf
+# endif
+# endif
+# ifdef __SASC
+# define NO_vsnprintf
+# endif
+#endif
+#ifdef VMS
+# define NO_vsnprintf
+#endif
+
+#if defined(pyr)
+# define NO_MEMCPY
+#endif
+#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__)
+ /* Use our own functions for small and medium model with MSC <= 5.0.
+ * You may have to use the same strategy for Borland C (untested).
+ * The __SC__ check is for Symantec.
+ */
+# define NO_MEMCPY
+#endif
+#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY)
+# define HAVE_MEMCPY
+#endif
+#ifdef HAVE_MEMCPY
+# ifdef SMALL_MEDIUM /* MSDOS small or medium model */
+# define zmemcpy _fmemcpy
+# define zmemcmp _fmemcmp
+# define zmemzero(dest, len) _fmemset(dest, 0, len)
+# else
+# define zmemcpy memcpy
+# define zmemcmp memcmp
+# define zmemzero(dest, len) memset(dest, 0, len)
+# endif
+#else
+ extern void zmemcpy OF((Bytef* dest, const Bytef* source, uInt len));
+ extern int zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len));
+ extern void zmemzero OF((Bytef* dest, uInt len));
+#endif
+
+/* Diagnostic functions */
+#ifdef DEBUG
+# include <stdio.h>
+ extern int z_verbose;
+ extern void z_error OF((char *m));
+# define Assert(cond,msg) {if(!(cond)) z_error(msg);}
+# define Trace(x) {if (z_verbose>=0) fprintf x ;}
+# define Tracev(x) {if (z_verbose>0) fprintf x ;}
+# define Tracevv(x) {if (z_verbose>1) fprintf x ;}
+# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;}
+# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;}
+#else
+# define Assert(cond,msg)
+# define Trace(x)
+# define Tracev(x)
+# define Tracevv(x)
+# define Tracec(c,x)
+# define Tracecv(c,x)
+#endif
+
+
+voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size));
+void zcfree OF((voidpf opaque, voidpf ptr));
+
+#define ZALLOC(strm, items, size) \
+ (*((strm)->zalloc))((strm)->opaque, (items), (size))
+#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr))
+#define TRY_FREE(s, p) {if (p) ZFREE(s, p);}
+
+#endif /* ZUTIL_H */