diff options
Diffstat (limited to 'trunk/qtools')
93 files changed, 58003 insertions, 0 deletions
diff --git a/trunk/qtools/Doxyfile b/trunk/qtools/Doxyfile new file mode 100644 index 0000000..16b681e --- /dev/null +++ b/trunk/qtools/Doxyfile @@ -0,0 +1,237 @@ +# Doxyfile 1.5.4 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = Doxygen +PROJECT_NUMBER = +OUTPUT_DIRECTORY = ../qtools_docs +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = $(PWD)/ +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text " +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = . +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.h \ + *.cpp \ + *.doc +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 4 +IGNORE_PREFIX = Q +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_DOCSET = YES +HTML_DYNAMIC_SECTIONS = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = ../qtools_docs/qtools.tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = NO +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = YES +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/trunk/qtools/LICENSE.GPL b/trunk/qtools/LICENSE.GPL new file mode 100644 index 0000000..935a2a0 --- /dev/null +++ b/trunk/qtools/LICENSE.GPL @@ -0,0 +1,349 @@ + + The Qt GUI Toolkit is Copyright (C) 1994-2000 Trolltech AS. + + You may use, distribute and copy the Qt GUI Toolkit under the terms of + GNU General Public License version 2, which is display below. + +------------------------------------------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) 19yy <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +------------------------------------------------------------------------- diff --git a/trunk/qtools/LICENSE.QPL b/trunk/qtools/LICENSE.QPL new file mode 100644 index 0000000..ecdad6e --- /dev/null +++ b/trunk/qtools/LICENSE.QPL @@ -0,0 +1,103 @@ + THE Q PUBLIC LICENSE + version 1.0 + + Copyright (C) 1999-2000 Trolltech AS, Norway. + Everyone is permitted to copy and + distribute this license document. + +The intent of this license is to establish freedom to share and change the +software regulated by this license under the open source model. + +This license applies to any software containing a notice placed by the +copyright holder saying that it may be distributed under the terms of +the Q Public License version 1.0. Such software is herein referred to as +the Software. This license covers modification and distribution of the +Software, use of third-party application programs based on the Software, +and development of free software which uses the Software. + + Granted Rights + +1. You are granted the non-exclusive rights set forth in this license + provided you agree to and comply with any and all conditions in this + license. Whole or partial distribution of the Software, or software + items that link with the Software, in any form signifies acceptance of + this license. + +2. You may copy and distribute the Software in unmodified form provided + that the entire package, including - but not restricted to - copyright, + trademark notices and disclaimers, as released by the initial developer + of the Software, is distributed. + +3. You may make modifications to the Software and distribute your + modifications, in a form that is separate from the Software, such as + patches. The following restrictions apply to modifications: + + a. Modifications must not alter or remove any copyright notices in + the Software. + + b. When modifications to the Software are released under this + license, a non-exclusive royalty-free right is granted to the + initial developer of the Software to distribute your modification + in future versions of the Software provided such versions remain + available under these terms in addition to any other license(s) of + the initial developer. + +4. You may distribute machine-executable forms of the Software or + machine-executable forms of modified versions of the Software, provided + that you meet these restrictions: + + a. You must include this license document in the distribution. + + b. You must ensure that all recipients of the machine-executable forms + are also able to receive the complete machine-readable source code + to the distributed Software, including all modifications, without + any charge beyond the costs of data transfer, and place prominent + notices in the distribution explaining this. + + c. You must ensure that all modifications included in the + machine-executable forms are available under the terms of this + license. + +5. You may use the original or modified versions of the Software to + compile, link and run application programs legally developed by you + or by others. + +6. You may develop application programs, reusable components and other + software items that link with the original or modified versions of the + Software. These items, when distributed, are subject to the following + requirements: + + a. You must ensure that all recipients of machine-executable forms of + these items are also able to receive and use the complete + machine-readable source code to the items without any charge + beyond the costs of data transfer. + + b. You must explicitly license all recipients of your items to use + and re-distribute original and modified versions of the items in + both machine-executable and source code forms. The recipients must + be able to do so without any charges whatsoever, and they must be + able to re-distribute to anyone they choose. + + + c. If the items are not available to the general public, and the + initial developer of the Software requests a copy of the items, + then you must supply one. + + Limitations of Liability + +In no event shall the initial developers or copyright holders be liable +for any damages whatsoever, including - but not restricted to - lost +revenue or profits or other direct, indirect, special, incidental or +consequential damages, even if they have been advised of the possibility +of such damages, except to the extent invariable law, if any, provides +otherwise. + + No Warranty + +The Software and this license document are provided AS IS with NO WARRANTY +OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE. + Choice of Law + +This license is governed by the Laws of Norway. Disputes shall be settled +by Oslo City Court. diff --git a/trunk/qtools/Makefile.in b/trunk/qtools/Makefile.in new file mode 100644 index 0000000..78710fd --- /dev/null +++ b/trunk/qtools/Makefile.in @@ -0,0 +1,30 @@ +# +# +# +# Copyright (C) 1997-2000 by Dimitri van Heesch. +# +# Permission to use, copy, modify, and distribute this software and its +# documentation under the terms of the GNU General Public License is hereby +# granted. No representations are made about the suitability of this software +# for any purpose. It is provided "as is" without express or implied warranty. +# See the GNU General Public License for more details. +# +# Documents produced by Doxygen are derivative works derived from the +# input used in their production; they are not affected by this license. +# + +all: Makefile.qtools Makefile + $(MAKE) -f Makefile.qtools $@ + +Makefile.qtools: qtools.pro + $(ENV) $(PERL) $(TMAKE) qtools.pro >Makefile.qtools + +tmake: + $(ENV) $(PERL) $(TMAKE) qtools.pro >Makefile.qtools + +clean: Makefile.qtools + $(MAKE) -f Makefile.qtools clean + +distclean: clean + +FORCE: diff --git a/trunk/qtools/README b/trunk/qtools/README new file mode 100644 index 0000000..1e7fc8d --- /dev/null +++ b/trunk/qtools/README @@ -0,0 +1,4 @@ +This directory contains a small subset of Troll-Tech's Qt library +The subset is enough to build the doxygen executable, but lacks many of +the features found in the Qt library. See http://www.trolltech.com +for the full package. diff --git a/trunk/qtools/qarray.doc b/trunk/qtools/qarray.doc new file mode 100644 index 0000000..6914dbc --- /dev/null +++ b/trunk/qtools/qarray.doc @@ -0,0 +1,486 @@ +/**************************************************************************** +** +** +** QArray class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QArray documentation + *****************************************************************************/ + +/*! + \class QArray qarray.h + \brief The QArray class is a template class that provides arrays of simple types. + + \ingroup tools + + QArray is implemented as a template class. Define a template + instance QArray\<X\> to create an array that contains X items. + + QArray stores the array elements directly in the array. It can only + deal with simple types, i.e. C++ types, structs and classes that have + no constructors, destructors or virtual functions. QArray uses + bitwise operations to copy and compare array elements. + + The QVector collection class is also a kind of array. Like most + \link collection.html collection classes\endlink, it has pointers to the + contained items. + + QArray uses explicit \link shclass.html sharing\endlink with a reference + count. If more than one array share common data, and one array is + modified, all arrays will be modified. + + The benefit of sharing is that a program does not need to duplicate + data when it is not required, which results in less memory usage and + less copying of data. + + Example: + \code + #include <qarray.h> + #include <stdio.h> + + QArray<int> fib( int num ) // returns fibonacci array + { + ASSERT( num > 2 ); + QArray<int> f( num ); // array of ints + + f[0] = f[1] = 1; // initialize first two numbers + for ( int i=2; i<num; i++ ) + f[i] = f[i-1] + f[i-2]; + + return f; + } + + void main() + { + QArray<int> a = fib( 6 ); // get 6 first fibonaccis + int i; + + for ( i=0; i<a.size(); i++ ) // print them + prinf( "%d: %d\n", i, a[i] ); + + printf( "1 is found %d time(s)\n", a.contains(1) ); + printf( "5 is found at index %d\n", a.find(5) ); + } + \endcode + + Program output: + \code + 0: 1 + 1: 1 + 2: 2 + 3: 3 + 4: 5 + 5: 8 + 1 is found 2 times + 5 is found at index 4 + \endcode + + Note about using QArray for manipulating structs or classes: + Compilers will often pad the size of structs of odd sizes up to the + nearest word boundary. This will then be the size QArray will use + for its bitwise element comparisons. Since the remaining bytes will + typically be uninitialized, this can cause find() etc. to fail to + find the element. Example: + + \code + struct MyStruct + { + short i; // 2 bytes + char c; // 1 byte + }; // sizeof(MyStruct) may be padded to 4 bytes + + QArray<MyStruct> a(1); + a[0].i = 5; + a[0].c = 't'; + + MyStruct x; + x.i = '5'; + x.c = 't'; + int i = a.find( x ); // May return -1 if the pad bytes differ + \endcode + + To workaround this, make sure that you use a struct where sizeof() + returns the same as the sum of the sizes of the members, either by + changing the types of the struct members or by adding dummy members. + + \sa \link shclass.html Shared Classes\endlink +*/ + + +/*! + \fn QArray::QArray() + Constructs a null array. + \sa isNull() +*/ + +/*! + \fn QArray::QArray( int size ) + Constructs an array with room for \e size elements. + Makes a null array if \e size == 0. + + Note that the elements are not initialized. + + \sa resize(), isNull() +*/ + +/*! + \fn QArray::QArray( const QArray<type> &a ) + Constructs a shallow copy of \e a. + \sa assign() +*/ + +/*! + \fn QArray::QArray( int, int ) + Constructs an array <em>without allocating</em> array space. + The arguments should be (0, 0). Use at own risk. +*/ + +/*! + \fn QArray::~QArray() + Dereferences the array data and deletes it if this was the last + reference. +*/ + +/*! + \fn QArray<type> &QArray::operator=( const QArray<type> &a ) + Assigns a shallow copy of \e a to this array and returns a reference + to this array. + + Equivalent to assign( a ). +*/ + +/*! + \fn type *QArray::data() const + Returns a pointer to the actual array data. + + The array is a null array if data() == 0 (null pointer). + + \sa isNull() +*/ + +/*! + \fn uint QArray::nrefs() const + Returns the reference count for the shared array data. This reference count + is always greater than zero. +*/ + +/*! + \fn uint QArray::size() const + Returns the size of the array (max number of elements). + + The array is a null array if size() == 0. + + \sa isNull(), resize() +*/ + +/*! + \fn uint QArray::count() const + Returns the same as size(). + + \sa size() +*/ + +/*! + \fn bool QArray::isEmpty() const + Returns TRUE if the array is empty, i.e. size() == 0, otherwise FALSE. + + isEmpty() is equivalent with isNull() for QArray. Note that this is not + the case for QCString::isEmpty(). +*/ + +/*! + \fn bool QArray::isNull() const + Returns TRUE if the array is null, otherwise FALSE. + + A null array has size() == 0 and data() == 0. +*/ + +/*! + \fn bool QArray::resize( uint size ) + Resizes (expands or shrinks) the array to \e size elements. The array + becomes a null array if \e size == 0. + + Returns TRUE if successful, or FALSE if the memory cannot be allocated. + + New elements will not be initialized. + + \sa size() +*/ + +/*! + \fn bool QArray::truncate( uint pos ) + Truncates the array at position \e pos. + + Returns TRUE if successful, or FALSE if the memory cannot be allocated. + + Equivalent to resize(\e pos). + + \sa resize() +*/ + +/*! + \fn bool QArray::fill( const type &v, int size ) + Fills the array with the value \e v. If \e size is specified as different + from -1, then the array will be resized before filled. + + Returns TRUE if successful, or FALSE if the memory cannot be allocated + (only when \e size != -1). + + \sa resize() +*/ + +/*! + \fn void QArray::detach() + Detaches this array from shared array data, i.e. makes a private, deep + copy of the data. + + Copying will only be performed if the + \link nrefs() reference count\endlink is greater than one. + + \sa copy() +*/ + +/*! + \fn QArray<type> QArray::copy() const + Returns a deep copy of this array. + \sa detach(), duplicate() +*/ + +/*! + \fn QArray<type> &QArray::assign( const QArray<type> &a ) + Shallow copy. Dereferences the current array and references the data + contained in \e a instead. Returns a reference to this array. + \sa operator=() +*/ + +/*! + \fn QArray<type> &QArray::assign( const type *data, uint size ) + Shallow copy. Dereferences the current array and references the + array data \e data, which contains \e size elements. + Returns a reference to this array. + + Do not delete \e data later, QArray takes care of that. +*/ + +/*! + \fn QArray<type> &QArray::duplicate( const QArray<type> &a ) + Deep copy. Dereferences the current array and obtains a copy of the data + contained in \e a instead. Returns a reference to this array. + \sa copy() +*/ + +/*! + \fn QArray<type> &QArray::duplicate( const type *data, uint size ) + Deep copy. Dereferences the current array and obtains a copy of the + array data \e data instead. Returns a reference to this array. + \sa copy() +*/ + +/*! + \fn QArray<type> &QArray::setRawData( const type *data, uint size ) + + Sets raw data and returns a reference to the array. + + Dereferences the current array and sets the new array data to \e data and + the new array size to \e size. Do not attempt to resize or re-assign the + array data when raw data has been set. + Call resetRawData(d,len) to reset the array. + + Setting raw data is useful because it sets QArray data without allocating + memory or copying data. + + Example I (intended use): + \code + static char bindata[] = { 231, 1, 44, ... }; + QByteArray a; + a.setRawData( bindata, sizeof(bindata) ); // a points to bindata + QDataStream s( a, IO_ReadOnly ); // open on a's data + s >> <something>; // read raw bindata + a.resetRawData( bindata, sizeof(bindata) ); // finished + \endcode + + Example II (you don't want to do this): + \code + static char bindata[] = { 231, 1, 44, ... }; + QByteArray a, b; + a.setRawData( bindata, sizeof(bindata) ); // a points to bindata + a.resize( 8 ); // will crash + b = a; // will crash + a[2] = 123; // might crash + // forget to resetRawData - will crash + \endcode + + \warning If you do not call resetRawData(), QArray will attempt to + deallocate or reallocate the raw data, which might not be too good. + Be careful. + + \sa resetRawData() +*/ + +/*! + \fn void QArray::resetRawData( const type *data, uint size ) + Resets raw data that was set using setRawData(). + + The arguments must be the data and length that were passed to + setRawData(). This is for consistency checking. + + \sa setRawData() +*/ + +/*! + \fn int QArray::find( const type &v, uint index ) const + Finds the first occurrence of \e v, starting at position \e index. + + Returns the position of \e v, or -1 if \e v could not be found. + + \sa contains() +*/ + +/*! + \fn int QArray::contains( const type &v ) const + Returns the number of times \e v occurs in the array. + \sa find() +*/ + +/*! + \fn void QArray::sort() + Sorts the array elements in ascending order, using bitwise + comparison (memcmp()). + + \sa bsearch() +*/ + +/*! + \fn int QArray::bsearch( const type &v ) const + In a sorted array, finds the first occurrence of \e v using binary + search. For a sorted array, this is generally much faster than + find(), which does a linear search. + + Returns the position of \e v, or -1 if \e v could not be found. + + \sa sort(), find() +*/ + +/*! + \fn type &QArray::operator[]( int index ) const + Returns a reference to the element at position \e index in the array. + + This can be used to both read and set an element. Equivalent to at(). + + \sa at() +*/ + +/*! + \fn type &QArray::at( uint index ) const + Returns a reference to the element at position \e index in the array. + + This can be used to both read and set an element. + + \sa operator[]() +*/ + +/*! + \fn QArray::operator const type *() const + Cast operator. Returns a pointer to the array. + \sa data() +*/ + +/*! + \fn bool QArray::operator==( const QArray<type> &a ) const + Returns TRUE if this array is equal to \e a, otherwise FALSE. + + The two arrays are bitwise compared. + + \sa operator!=() +*/ + +/*! + \fn bool QArray::operator!=( const QArray<type> &a ) const + Returns TRUE if this array is different from \e a, otherwise FALSE. + + The two arrays are bitwise compared. + + \sa operator==() +*/ + +/*! + \fn Iterator QArray::begin() + Returns an iterator pointing at the beginning of this array. + This iterator can be used as the iterators of QValueList and QMap + for example. In fact it does not only behave like a usual pointer: + It is a pointer. +*/ + +/*! + \fn Iterator QArray::end() + Returns an iterator pointing behind the last element of this array. + This iterator can be used as the iterators of QValueList and QMap + for example. In fact it does not only behave like a usual pointer: + It is a pointer. +*/ + +/*! + \fn ConstIterator QArray::begin() const + Returns a const iterator pointing at the beginning of this array. + This iterator can be used as the iterators of QValueList and QMap + for example. In fact it does not only behave like a usual pointer: + It is a pointer. +*/ + +/*! + \fn ConstIterator QArray::end() const + Returns a const iterator pointing behind the last element of this array. + This iterator can be used as the iterators of QValueList and QMap + for example. In fact it does not only behave like a usual pointer: + It is a pointer. +*/ + + +/***************************************************************************** + QByteArray documentation + *****************************************************************************/ + +/*! + \class QByteArray qcstring.h + \brief The QByteArray class provides an array of bytes. + + \inherit QArray + + \ingroup tools + + The QByteArray class provides an explicitly shared array of + bytes. It is useful for manipulating memory areas with custom + data. QByteArray is implemented as QArray<char>. See the QArray + documentation for further information. +*/ diff --git a/trunk/qtools/qarray.h b/trunk/qtools/qarray.h new file mode 100644 index 0000000..90dcbb7 --- /dev/null +++ b/trunk/qtools/qarray.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** +** Definition of QArray template/macro class +** +** Created : 930906 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QARRAY_H +#define QARRAY_H + +#ifndef QT_H +#include "qgarray.h" +#endif // QT_H + + +template<class type> class Q_EXPORT QArray : public QGArray +{ +public: + typedef type* Iterator; + typedef const type* ConstIterator; + typedef type ValueType; + +protected: + QArray( int, int ) : QGArray( 0, 0 ) {} + +public: + QArray() {} + QArray( int size ) : QGArray(size*sizeof(type)) {} + QArray( const QArray<type> &a ) : QGArray(a) {} + ~QArray() {} + QArray<type> &operator=(const QArray<type> &a) + { return (QArray<type>&)QGArray::assign(a); } + type *data() const { return (type *)QGArray::data(); } + uint nrefs() const { return QGArray::nrefs(); } + uint size() const { return QGArray::size()/sizeof(type); } + uint count() const { return size(); } + bool isEmpty() const { return QGArray::size() == 0; } + bool isNull() const { return QGArray::data() == 0; } + bool resize( uint size ) { return QGArray::resize(size*sizeof(type)); } + bool truncate( uint pos ) { return QGArray::resize(pos*sizeof(type)); } + bool fill( const type &d, int size = -1 ) + { return QGArray::fill((char*)&d,size,sizeof(type) ); } + void detach() { QGArray::detach(); } + QArray<type> copy() const + { QArray<type> tmp; return tmp.duplicate(*this); } + QArray<type>& assign( const QArray<type>& a ) + { return (QArray<type>&)QGArray::assign(a); } + QArray<type>& assign( const type *a, uint n ) + { return (QArray<type>&)QGArray::assign((char*)a,n*sizeof(type)); } + QArray<type>& duplicate( const QArray<type>& a ) + { return (QArray<type>&)QGArray::duplicate(a); } + QArray<type>& duplicate( const type *a, uint n ) + { return (QArray<type>&)QGArray::duplicate((char*)a,n*sizeof(type)); } + QArray<type>& setRawData( const type *a, uint n ) + { return (QArray<type>&)QGArray::setRawData((char*)a, + n*sizeof(type)); } + void resetRawData( const type *a, uint n ) + { QGArray::resetRawData((char*)a,n*sizeof(type)); } + int find( const type &d, uint i=0 ) const + { return QGArray::find((char*)&d,i,sizeof(type)); } + int contains( const type &d ) const + { return QGArray::contains((char*)&d,sizeof(type)); } + void sort() { QGArray::sort(sizeof(type)); } + int bsearch( const type &d ) const + { return QGArray::bsearch((const char*)&d,sizeof(type)); } + type& operator[]( int i ) const + { return (type &)(*(type *)QGArray::at(i*sizeof(type))); } + type& at( uint i ) const + { return (type &)(*(type *)QGArray::at(i*sizeof(type))); } + operator const type*() const { return (const type *)QGArray::data(); } + bool operator==( const QArray<type> &a ) const { return isEqual(a); } + bool operator!=( const QArray<type> &a ) const { return !isEqual(a); } + Iterator begin() { return data(); } + Iterator end() { return data() + size(); } + ConstIterator begin() const { return data(); } + ConstIterator end() const { return data() + size(); } +}; + + +#endif // QARRAY_H diff --git a/trunk/qtools/qasciidict.h b/trunk/qtools/qasciidict.h new file mode 100644 index 0000000..29fcf2f --- /dev/null +++ b/trunk/qtools/qasciidict.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** +** Definition of QAsciiDict template class +** +** Created : 920821 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QASCIIDICT_H +#define QASCIIDICT_H + +#ifndef QT_H +#include "qgdict.h" +#endif // QT_H + + +template<class type> class Q_EXPORT QAsciiDict : public QGDict +{ +public: + QAsciiDict(int size=17, bool caseSensitive=TRUE, bool copyKeys=TRUE ) + : QGDict(size,AsciiKey,caseSensitive,copyKeys) {} + QAsciiDict( const QAsciiDict<type> &d ) : QGDict(d) {} + ~QAsciiDict() { clear(); } + QAsciiDict<type> &operator=(const QAsciiDict<type> &d) + { return (QAsciiDict<type>&)QGDict::operator=(d); } + uint count() const { return QGDict::count(); } + uint size() const { return QGDict::size(); } + bool isEmpty() const { return QGDict::count() == 0; } + + void insert( const char *k, const type *d ) + { QGDict::look_ascii(k,(Item)d,1); } + void replace( const char *k, const type *d ) + { QGDict::look_ascii(k,(Item)d,2); } + bool remove( const char *k ) { return QGDict::remove_ascii(k); } + type *take( const char *k ) { return (type *)QGDict::take_ascii(k); } + type *find( const char *k ) const + { return (type *)((QGDict*)this)->QGDict::look_ascii(k,0,0); } + type *operator[]( const char *k ) const + { return (type *)((QGDict*)this)->QGDict::look_ascii(k,0,0); } + + void clear() { QGDict::clear(); } + void resize( uint n ) { QGDict::resize(n); } + void statistics() const { QGDict::statistics(); } +private: + void deleteItem( Item d ); +}; + +#if defined(Q_DELETING_VOID_UNDEFINED) +template<> inline void QAsciiDict<void>::deleteItem( Item ) +{ +} +#endif + +template<class type> inline void QAsciiDict<type>::deleteItem( QCollection::Item d ) +{ + if ( del_item ) delete (type *)d; +} + + +template<class type> class Q_EXPORT QAsciiDictIterator : public QGDictIterator +{ +public: + QAsciiDictIterator(const QAsciiDict<type> &d) + : QGDictIterator((QGDict &)d) {} + ~QAsciiDictIterator() {} + uint count() const { return dict->count(); } + bool isEmpty() const { return dict->count() == 0; } + type *toFirst() { return (type *)QGDictIterator::toFirst(); } + operator type *() const { return (type *)QGDictIterator::get(); } + type *current() const { return (type *)QGDictIterator::get(); } + const char *currentKey() const { return QGDictIterator::getKeyAscii(); } + type *operator()() { return (type *)QGDictIterator::operator()(); } + type *operator++() { return (type *)QGDictIterator::operator++(); } + type *operator+=(uint j) { return (type *)QGDictIterator::operator+=(j);} +}; + + +#endif // QASCIIDICT_H diff --git a/trunk/qtools/qbuffer.cpp b/trunk/qtools/qbuffer.cpp new file mode 100644 index 0000000..beed0ba --- /dev/null +++ b/trunk/qtools/qbuffer.cpp @@ -0,0 +1,465 @@ +/**************************************************************************** +** +** +** Implementation of QBuffer class +** +** Created : 930812 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qbuffer.h" +#include <stdlib.h> + +// REVISED: paul +/*! + \class QBuffer qbuffer.h + \brief The QBuffer class is an I/O device that operates on a QByteArray + + \ingroup io + + QBuffer allows reading and writing a memory buffer. It is normally + used together with a QTextStream or a QDataStream. QBuffer has an + associated QByteArray which holds the buffer data. The size() of the + buffer is automatically adjusted as data is written. + + The constructor \c QBuffer(QByteArray) creates a QBuffer with an + existing byte array. The byte array can also be set with setBuffer(). + Writing to the QBuffer will modify the original byte array, since + QByteArray is \link shclass.html explicitly shared.\endlink + + Use open() to open the buffer before use, and to set the mode + (read-only,write-only, etc.). close() closes the buffer. The buffer + must be closed before reopening or calling setBuffer(). + + The common way to use QBuffer is through \l QDataStream or \l QTextStream + which have constructors that take a QBuffer parameter. For + convenience, there are also QDataStream and QTextStream constructors + that take a QByteArray parameter. These constructors create and open + an internal QBuffer. + + Note that QTextStream can also operate on a QString (a Unicode + string); a QBuffer cannot. + + You can also use QBuffer directly through the standard QIODevice + functions readBlock(), writeBlock() readLine(), at(), getch(), putch() and + ungetch(). + + \sa QFile, QDataStream, QTextStream, QByteArray, \link shclass.html Shared Classes\endlink +*/ + + +/*! + Constructs an empty buffer. +*/ + +QBuffer::QBuffer() +{ + setFlags( IO_Direct ); + a_inc = 16; // initial increment + a_len = 0; + ioIndex = 0; +} + + +/*! + Constructs a buffer that operates on \a buf. + If you open the buffer in write mode (\c IO_WriteOnly or + \c IO_ReadWrite) and write something into the buffer, \a buf + will be modified. + + + Example: + \code + QCString str = "abc"; + QBuffer b( str ); + b.open( IO_WriteOnly ); + b.at( 3 ); // position at \0 + b.writeBlock( "def", 4 ); // write including \0 + b.close(); + // Now, str == "abcdef" + \endcode + + + \sa setBuffer() +*/ + +QBuffer::QBuffer( QByteArray buf ) : a(buf) +{ + setFlags( IO_Direct ); + a_len = a.size(); + a_inc = (a_len > 512) ? 512 : a_len; // initial increment + if ( a_inc < 16 ) + a_inc = 16; + ioIndex = 0; +} + +/*! + Destructs the buffer. +*/ + +QBuffer::~QBuffer() +{ +} + + +/*! + Replaces the buffer's contents with \a buf. + + This may not be done when isOpen() is TRUE. + + Note that if you open the buffer in write mode (\c IO_WriteOnly or + IO_ReadWrite) and write something into the buffer, \a buf is also + modified because QByteArray is an explicitly shared class. + + \sa buffer(), open(), close() +*/ + +bool QBuffer::setBuffer( QByteArray buf ) +{ + if ( isOpen() ) { +#if defined(CHECK_STATE) + qWarning( "QBuffer::setBuffer: Buffer is open"); +#endif + return FALSE; + } + a = buf; + a_len = a.size(); + a_inc = (a_len > 512) ? 512 : a_len; // initial increment + if ( a_inc < 16 ) + a_inc = 16; + ioIndex = 0; + return TRUE; +} + +/*! + \fn QByteArray QBuffer::buffer() const + + Returns this buffer's byte array. + + \sa setBuffer() +*/ + +/*! + \reimp + Opens the buffer in the mode \a m. Returns TRUE if successful, + otherwise FALSE. The buffer must be opened before use. + + The mode parameter \a m must be a combination of the following flags. + <ul> + <li>\c IO_ReadOnly opens a buffer in read-only mode. + <li>\c IO_WriteOnly opens a buffer in write-only mode. + <li>\c IO_ReadWrite opens a buffer in read/write mode. + <li>\c IO_Append sets the buffer index to the end of the buffer. + <li>\c IO_Truncate truncates the buffer. + </ul> + + \sa close(), isOpen() +*/ + +bool QBuffer::open( int m ) +{ + if ( isOpen() ) { // buffer already open +#if defined(CHECK_STATE) + qWarning( "QBuffer::open: Buffer already open" ); +#endif + return FALSE; + } + setMode( m ); + if ( m & IO_Truncate ) { // truncate buffer + a.resize( 0 ); + a_len = 0; + } + if ( m & IO_Append ) { // append to end of buffer + ioIndex = a.size(); + } else { + ioIndex = 0; + } + a_inc = 16; + setState( IO_Open ); + setStatus( 0 ); + return TRUE; +} + +/*! + \reimp + Closes an open buffer. + \sa open() +*/ + +void QBuffer::close() +{ + if ( isOpen() ) { + setFlags( IO_Direct ); + ioIndex = 0; + a_inc = 16; + } +} + +/*! + \reimp + The flush function does nothing for a QBuffer. +*/ + +void QBuffer::flush() +{ + return; +} + + +/*! + \fn int QBuffer::at() const + \reimp +*/ + +/*! + \fn uint QBuffer::size() const + \reimp +*/ + +/*! + \reimp +*/ + +bool QBuffer::at( int pos ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { + qWarning( "QBuffer::at: Buffer is not open" ); + return FALSE; + } +#endif + if ( (uint)pos > a_len ) { +#if defined(CHECK_RANGE) + qWarning( "QBuffer::at: Index %d out of range", pos ); +#endif + return FALSE; + } + ioIndex = pos; + return TRUE; +} + + +/*! + \reimp +*/ + +int QBuffer::readBlock( char *p, uint len ) +{ +#if defined(CHECK_STATE) + CHECK_PTR( p ); + if ( !isOpen() ) { // buffer not open + qWarning( "QBuffer::readBlock: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QBuffer::readBlock: Read operation not permitted" ); + return -1; + } +#endif + if ( (uint)ioIndex + len > a.size() ) { // overflow + if ( (uint)ioIndex >= a.size() ) { + setStatus( IO_ReadError ); + return -1; + } else { + len = a.size() - (uint)ioIndex; + } + } + memcpy( p, a.data()+ioIndex, len ); + ioIndex += len; + return len; +} + +/*! + \reimp + + Writes \a len bytes from \a p into the buffer at the current index, + overwriting any characters there and extending the buffer if necessary. + Returns the number of bytes actually written. + + Returns -1 if a serious error occurred. + + \sa readBlock() +*/ + +int QBuffer::writeBlock( const char *p, uint len ) +{ +#if defined(CHECK_NULL) + if ( p == 0 && len != 0 ) + qWarning( "QBuffer::writeBlock: Null pointer error" ); +#endif +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QBuffer::writeBlock: Buffer not open" ); + return -1; + } + if ( !isWritable() ) { // writing not permitted + qWarning( "QBuffer::writeBlock: Write operation not permitted" ); + return -1; + } +#endif + if ( (uint)ioIndex + len >= a_len ) { // overflow + uint new_len = a_len + a_inc*(((uint)ioIndex+len-a_len)/a_inc+1); + if ( !a.resize( new_len ) ) { // could not resize +#if defined(CHECK_NULL) + qWarning( "QBuffer::writeBlock: Memory allocation error" ); +#endif + setStatus( IO_ResourceError ); + return -1; + } + a_inc *= 2; // double increment + a_len = new_len; + a.shd->len = (uint)ioIndex + len; + } + memcpy( a.data()+ioIndex, p, len ); + ioIndex += len; + if ( a.shd->len < (uint)ioIndex ) + a.shd->len = (uint)ioIndex; // fake (not alloc'd) length + return len; +} + + +/*! + \reimp +*/ + +int QBuffer::readLine( char *p, uint maxlen ) +{ +#if defined(CHECK_STATE) + CHECK_PTR( p ); + if ( !isOpen() ) { // buffer not open + qWarning( "QBuffer::readLine: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QBuffer::readLine: Read operation not permitted" ); + return -1; + } +#endif + if ( maxlen == 0 ) + return 0; + uint start = (uint)ioIndex; + char *d = a.data() + ioIndex; + maxlen--; // make room for 0-terminator + if ( a.size() - (uint)ioIndex < maxlen ) + maxlen = a.size() - (uint)ioIndex; + while ( maxlen-- ) { + if ( (*p++ = *d++) == '\n' ) + break; + } + *p = '\0'; + ioIndex = d - a.data(); + return (uint)ioIndex - start; +} + + +/*! + \reimp +*/ + +int QBuffer::getch() +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QBuffer::getch: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QBuffer::getch: Read operation not permitted" ); + return -1; + } +#endif + if ( (uint)ioIndex+1 > a.size() ) { // overflow + setStatus( IO_ReadError ); + return -1; + } + return uchar(*(a.data()+ioIndex++)); +} + +/*! + \reimp + Writes the character \a ch into the buffer, overwriting + the character at the current index, extending the buffer + if necessary. + + Returns \a ch, or -1 if some error occurred. + + \sa getch(), ungetch() +*/ + +int QBuffer::putch( int ch ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QBuffer::putch: Buffer not open" ); + return -1; + } + if ( !isWritable() ) { // writing not permitted + qWarning( "QBuffer::putch: Write operation not permitted" ); + return -1; + } +#endif + if ( (uint)ioIndex + 1 >= a_len ) { // overflow + char buf[1]; + buf[0] = (char)ch; + if ( writeBlock(buf,1) != 1 ) + return -1; // write error + } else { + *(a.data() + ioIndex++) = (char)ch; + if ( a.shd->len < (uint)ioIndex ) + a.shd->len = (uint)ioIndex; + } + return ch; +} + +/*! + \reimp +*/ + +int QBuffer::ungetch( int ch ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QBuffer::ungetch: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QBuffer::ungetch: Read operation not permitted" ); + return -1; + } +#endif + if ( ch != -1 ) { + if ( ioIndex ) + ioIndex--; + else + ch = -1; + } + return ch; +} diff --git a/trunk/qtools/qbuffer.h b/trunk/qtools/qbuffer.h new file mode 100644 index 0000000..9dcd286 --- /dev/null +++ b/trunk/qtools/qbuffer.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** +** Definition of QBuffer class +** +** Created : 930812 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QBUFFER_H +#define QBUFFER_H + +#ifndef QT_H +#include "qiodevice.h" +#include "qstring.h" +#endif // QT_H + + +class Q_EXPORT QBuffer : public QIODevice +{ +public: + QBuffer(); + QBuffer( QByteArray ); + ~QBuffer(); + + QByteArray buffer() const; + bool setBuffer( QByteArray ); + + bool open( int ); + void close(); + void flush(); + + uint size() const; + int at() const; + bool at( int ); + + int readBlock( char *p, uint ); + int writeBlock( const char *p, uint ); + int readLine( char *p, uint ); + + int getch(); + int putch( int ); + int ungetch( int ); + +protected: + QByteArray a; + +private: + uint a_len; + uint a_inc; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QBuffer( const QBuffer & ); + QBuffer &operator=( const QBuffer & ); +#endif +}; + + +inline QByteArray QBuffer::buffer() const +{ return a; } + +inline uint QBuffer::size() const +{ return a.size(); } + +inline int QBuffer::at() const +{ return ioIndex; } + + +#endif // QBUFFER_H diff --git a/trunk/qtools/qcache.h b/trunk/qtools/qcache.h new file mode 100644 index 0000000..f15345e --- /dev/null +++ b/trunk/qtools/qcache.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** +** Definition of QCache template class +** +** Created : 950209 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QCACHE_H +#define QCACHE_H + +#ifndef QT_H +#include "qgcache.h" +#endif // QT_H + +#define USE_ASCII_STRING + +#ifndef USE_ASCII_STRING + +template<class type> class Q_EXPORT QCache : public QGCache +{ +public: + QCache( const QCache<type> &c ) : QGCache(c) {} + QCache( int maxCost=100, int size=17, bool caseSensitive=TRUE ) + : QGCache( maxCost, size, StringKey, caseSensitive, FALSE ) {} + ~QCache() { clear(); } + QCache<type> &operator=( const QCache<type> &c ) + { return (QCache<type>&)QGCache::operator=(c); } + int maxCost() const { return QGCache::maxCost(); } + int totalCost() const { return QGCache::totalCost(); } + void setMaxCost( int m ) { QGCache::setMaxCost(m); } + uint count() const { return QGCache::count(); } + uint size() const { return QGCache::size(); } + bool isEmpty() const { return QGCache::count() == 0; } + void clear() { QGCache::clear(); } + bool insert( const QString &k, const type *d, int c=1, int p=0 ) + { return QGCache::insert_string(k,(Item)d,c,p);} + bool remove( const QString &k ) + { return QGCache::remove_string(k); } + type *take( const QString &k ) + { return (type *)QGCache::take_string(k); } + type *find( const QString &k, bool ref=TRUE ) const + { return (type *)QGCache::find_string(k,ref);} + type *operator[]( const QString &k ) const + { return (type *)QGCache::find_string(k);} + void statistics() const { QGCache::statistics(); } +private: + void deleteItem( Item d ) { if ( del_item ) delete (type *)d; } +}; + +#else + + +template<class type> class Q_EXPORT QCache : public QGCache +{ +public: + QCache( const QCache<type> &c ) : QGCache(c) {} + QCache( int maxCost=100, int size=17, bool caseSensitive=TRUE ) + : QGCache( maxCost, size, AsciiKey, caseSensitive, TRUE ) {} + ~QCache() { clear(); } + QCache<type> &operator=( const QCache<type> &c ) + { return (QCache<type>&)QGCache::operator=(c); } + int maxCost() const { return QGCache::maxCost(); } + int totalCost() const { return QGCache::totalCost(); } + void setMaxCost( int m ) { QGCache::setMaxCost(m); } + uint count() const { return QGCache::count(); } + uint size() const { return QGCache::size(); } + bool isEmpty() const { return QGCache::count() == 0; } + void clear() { QGCache::clear(); } + bool insert( const char *k, const type *d, int c=1, int p=0 ) + { return QGCache::insert_other(k,(Item)d,c,p);} + bool remove( const char *k ) + { return QGCache::remove_other(k); } + type *take( const char *k ) + { return (type *)QGCache::take_other(k); } + type *find( const char *k, bool ref=TRUE ) const + { return (type *)QGCache::find_other(k,ref);} + type *operator[]( const char *k ) const + { return (type *)QGCache::find_other(k);} + void statistics() const { QGCache::statistics(); } +private: + void deleteItem( Item d ) { if ( del_item ) delete (type *)d; } +}; + + +#endif + + + +template<class type> class Q_EXPORT QCacheIterator : public QGCacheIterator +{ +public: + QCacheIterator( const QCache<type> &c ):QGCacheIterator((QGCache &)c) {} + QCacheIterator( const QCacheIterator<type> &ci) + : QGCacheIterator( (QGCacheIterator &)ci ) {} + QCacheIterator<type> &operator=(const QCacheIterator<type>&ci) + { return ( QCacheIterator<type>&)QGCacheIterator::operator=( ci ); } + uint count() const { return QGCacheIterator::count(); } + bool isEmpty() const { return QGCacheIterator::count() == 0; } + bool atFirst() const { return QGCacheIterator::atFirst(); } + bool atLast() const { return QGCacheIterator::atLast(); } + type *toFirst() { return (type *)QGCacheIterator::toFirst(); } + type *toLast() { return (type *)QGCacheIterator::toLast(); } + operator type *() const { return (type *)QGCacheIterator::get(); } + type *current() const { return (type *)QGCacheIterator::get(); } +#ifndef USE_ASCII_STRING + QString currentKey() const{ return QGCacheIterator::getKeyString(); } +#else + const char *currentKey() const{ return QGCacheIterator::getKeyAscii(); } +#endif + type *operator()() { return (type *)QGCacheIterator::operator()();} + type *operator++() { return (type *)QGCacheIterator::operator++(); } + type *operator+=(uint j) { return (type *)QGCacheIterator::operator+=(j);} + type *operator--() { return (type *)QGCacheIterator::operator--(); } + type *operator-=(uint j) { return (type *)QGCacheIterator::operator-=(j);} +}; + + +#endif // QCACHE_H diff --git a/trunk/qtools/qcollection.cpp b/trunk/qtools/qcollection.cpp new file mode 100644 index 0000000..e70b64b --- /dev/null +++ b/trunk/qtools/qcollection.cpp @@ -0,0 +1,182 @@ +/**************************************************************************** +** +** +** Implementation of base class for all collection classes +** +** Created : 920820 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qcollection.h" + +// NOT REVISED +/*! + \class QCollection qcollection.h + \brief The QCollection class is the base class of all Qt collections. + + \ingroup collection + \ingroup tools + + The QCollection class is an abstract base class for the Qt \link + collection.html collection classes\endlink QDict, QList etc. via QGDict, + QGList etc. + + A QCollection knows only about the number of objects in the + collection and the deletion strategy (see setAutoDelete()). + + A collection is implemented using the \c Item (generic collection + item) type, which is a \c void*. The template classes that create + the real collections cast the \c Item to the required type. + + \sa \link collection.html Collection Classes\endlink +*/ + + +/*! \enum QCollection::Item + + This type is the generic "item" in a QCollection. +*/ + + +/*! + \fn QCollection::QCollection() + + Constructs a collection. The constructor is protected because + QCollection is an abstract class. +*/ + +/*! + \fn QCollection::QCollection( const QCollection & source ) + + Constructs a copy of \a source with autoDelete() set to FALSE. The + constructor is protected because QCollection is an abstract class. + + Note that if \a source has autoDelete turned on, copying it is a + good way to get memory leaks, reading freed memory, or both. +*/ + +/*! + \fn QCollection::~QCollection() + Destroys the collection. The destructor is protected because QCollection + is an abstract class. +*/ + + +/*! + \fn bool QCollection::autoDelete() const + Returns the setting of the auto-delete option (default is FALSE). + \sa setAutoDelete() +*/ + +/*! + \fn void QCollection::setAutoDelete( bool enable ) + + Sets the auto-delete option of the collection. + + Enabling auto-delete (\e enable is TRUE) will delete objects that + are removed from the collection. This can be useful if the + collection has the only reference to the objects. (Note that the + object can still be copied using the copy constructor - copying such + objects is a good way to get memory leaks, reading freed memory or + both.) + + Disabling auto-delete (\e enable is FALSE) will \e not delete objects + that are removed from the collection. This is useful if the objects + are part of many collections. + + The default setting is FALSE. + + \sa autoDelete() +*/ + + +/*! + \fn virtual uint QCollection::count() const + Returns the number of objects in the collection. +*/ + +/*! + \fn virtual void QCollection::clear() + Removes all objects from the collection. The objects will be deleted + if auto-delete has been enabled. + \sa setAutoDelete() +*/ + + +/*! + Virtual function that creates a copy of an object that is about to + be inserted into the collection. + + The default implementation returns the \e d pointer, i.e. no copy + is made. + + This function is seldom reimplemented in the collection template + classes. It is not common practice to make a copy of something + that is being inserted. + + \sa deleteItem() +*/ + +QCollection::Item QCollection::newItem( Item d ) +{ + return d; // just return reference +} + +/*! + Virtual function that deletes an item that is about to be removed from + the collection. + + The default implementation deletes \e d pointer if and only if + auto-delete has been enabled. + + This function is always reimplemented in the collection template + classes. + + \warning If you reimplement this function you must also reimplement + the destructor and call the virtual function clear() from your + destructor. This is due to the way virtual functions and + destructors work in C++: virtual functions in derived classes cannot + be called from a destructor. If you do not do this your + deleteItem() function will not be called when the container is + destructed. + + \sa newItem(), setAutoDelete() +*/ + +void QCollection::deleteItem( Item d ) +{ + if ( del_item ) +#if defined(Q_DELETING_VOID_UNDEFINED) + delete (char *)d; // default operation +#else + delete d; // default operation +#endif +} diff --git a/trunk/qtools/qcollection.h b/trunk/qtools/qcollection.h new file mode 100644 index 0000000..a169b7c --- /dev/null +++ b/trunk/qtools/qcollection.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** +** Definition of base class for all collection classes +** +** Created : 920629 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QCOLLECTION_H +#define QCOLLECTION_H + +#ifndef QT_H +#include "qglobal.h" +#endif // QT_H + + +class QGVector; +class QGList; +class QGDict; + + +class Q_EXPORT QCollection // inherited by all collections +{ +public: + bool autoDelete() const { return del_item; } + void setAutoDelete( bool enable ) { del_item = enable; } + + virtual uint count() const = 0; + virtual void clear() = 0; // delete all objects + + typedef void *Item; // generic collection item + +protected: + QCollection() { del_item = FALSE; } // no deletion of objects + QCollection(const QCollection &) { del_item = FALSE; } + virtual ~QCollection() {} + + bool del_item; // default FALSE + + virtual Item newItem( Item ); // create object + virtual void deleteItem( Item ); // delete object +}; + + +#endif // QCOLLECTION_H diff --git a/trunk/qtools/qconfig.h b/trunk/qtools/qconfig.h new file mode 100644 index 0000000..7a880f9 --- /dev/null +++ b/trunk/qtools/qconfig.h @@ -0,0 +1 @@ +// Everything diff --git a/trunk/qtools/qcstring.cpp b/trunk/qtools/qcstring.cpp new file mode 100644 index 0000000..c3aad40 --- /dev/null +++ b/trunk/qtools/qcstring.cpp @@ -0,0 +1,794 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2004 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + +#include "qcstring.h" +#include "qgstring.h" + +#include <qstring.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <ctype.h> +#include <qregexp.h> +#include <qdatastream.h> + + +QCString::QCString(int size) +{ + if (size>0) + { + m_data = (char *)malloc(size); + if (m_data) + { + if (size>1) memset(m_data,' ',size-1); + m_data[size-1]='\0'; + } + } + else + { + m_data=0; + } +} + +QCString::QCString( const QCString &s ) +{ + duplicate(s); +} + +QCString::QCString( const char *str ) +{ + duplicate(str); +} + +QCString::QCString( const char *str, uint maxlen ) +{ + uint l; + if (str && ( l = QMIN(qstrlen(str),maxlen) )) + { + m_data=(char *)malloc(l+1); + strncpy(m_data,str,l+1); + m_data[l]='\0'; + } + else + { + m_data=0; + } +} + +QCString::~QCString() +{ + if (m_data) free(m_data); + m_data=0; +} + +QCString &QCString::assign( const char *str ) +{ + if (m_data) free(m_data); + duplicate(str); + return *this; +} + +bool QCString::resize( uint newlen ) +{ + if (newlen==0) + { + if (m_data) { free(m_data); m_data=0; } + return TRUE; + } + if (m_data==0) // newlen>0 + { + m_data = (char *)malloc(newlen); + } + else + { + m_data = (char *)realloc(m_data,newlen); + } + if (m_data==0) return FALSE; + m_data[newlen-1]='\0'; + return TRUE; +} + +bool QCString::fill( char c, int len ) +{ + uint l=length(); + if (len<0) len=l; + if ((uint)len!=l) + { + if (m_data) free(m_data); + if (len>0) + { + m_data=(char *)malloc(len+1); + if (m_data==0) return FALSE; + m_data[len]='\0'; + } + else + { + m_data=0; + } + } + if (len>0) + { + uint i; + for (i=0;i<(uint)len;i++) m_data[i]=c; + } + return TRUE; +} + +QCString &QCString::sprintf( const char *format, ... ) +{ + va_list ap; + va_start( ap, format ); + uint l = length(); + const uint minlen=256; + if (l<minlen) + { + if (m_data) + m_data = (char *)realloc(m_data,minlen); + else + m_data = (char *)malloc(minlen); + } + vsprintf( m_data, format, ap ); + resize( qstrlen(m_data) + 1 ); // truncate + va_end( ap ); + return *this; +} + + +int QCString::find( char c, int index, bool cs ) const +{ + uint len = length(); + if ( m_data==0 || (uint)index>len ) // index outside string + return -1; + register const char *d; + if ( cs ) // case sensitive + { + d = strchr( m_data+index, c ); + } + else + { + d = m_data+index; + c = tolower( (uchar) c ); + while ( *d && tolower((uchar) *d) != c ) + d++; + if ( !*d && c ) // not found + d = 0; + } + return d ? (int)(d - m_data) : -1; +} + +int QCString::find( const char *str, int index, bool cs ) const +{ + uint l = length(); + if ( m_data==0 || (uint)index > l ) // index outside string + return -1; + if ( !str ) // no search string + return -1; + if ( !*str ) // zero-length search string + return index; + register const char *d; + if ( cs ) // case sensitive + { + d = strstr( m_data+index, str ); + } + else // case insensitive + { + d = m_data+index; + int len = qstrlen( str ); + while ( *d ) + { + if ( qstrnicmp(d, str, len) == 0 ) + break; + d++; + } + if ( !*d ) // not found + d = 0; + } + return d ? (int)(d - m_data) : -1; +} + +int QCString::find( const QRegExp &rx, int index ) const +{ + QString d = QString::fromLatin1( m_data ); + return d.find( rx, index ); +} + +int QCString::findRev( char c, int index, bool cs) const +{ + const char *b = m_data; + const char *d; + uint len = length(); + if ( b == 0 ) return -1; // empty string + if ( index < 0 ) // neg index ==> start from end + { + if ( len == 0 ) return -1; + if ( cs ) + { + d = strrchr( b, c ); + return d ? (int)(d - b) : -1; + } + index = len; + } + else if ( (uint)index > len ) // bad index + { + return -1; + } + d = b+index; + if ( cs ) // case sensitive + { + while ( d >= b && *d != c ) + d--; + } + else // case insensitive + { + c = tolower( (uchar) c ); + while ( d >= b && tolower((uchar) *d) != c ) + d--; + } + return d >= b ? (int)(d - b) : -1; +} + +int QCString::findRev( const char *str, int index, bool cs) const +{ + int slen = qstrlen(str); + uint len = length(); + if ( index < 0 ) // neg index ==> start from end + index = len-slen; + else if ( (uint)index > len ) // bad index + return -1; + else if ( (uint)(index + slen) > len ) // str would be too long + index = len - slen; + if ( index < 0 ) + return -1; + + register char *d = m_data + index; + if ( cs ) // case sensitive + { + for ( int i=index; i>=0; i-- ) + if ( qstrncmp(d--,str,slen)==0 ) + return i; + } + else // case insensitive + { + for ( int i=index; i>=0; i-- ) + if ( qstrnicmp(d--,str,slen)==0 ) + return i; + } + return -1; + +} + +int QCString::findRev( const QRegExp &rx, int index ) const +{ + QString d = QString::fromLatin1( m_data ); + return d.findRev( rx, index ); +} + +int QCString::contains( char c, bool cs ) const +{ + int count = 0; + char *d = m_data; + if ( !d ) + return 0; + if ( cs ) // case sensitive + { + while ( *d ) + if ( *d++ == c ) + count++; + } + else // case insensitive + { + c = tolower( (uchar) c ); + while ( *d ) { + if ( tolower((uchar) *d) == c ) + count++; + d++; + } + } + return count; +} + +int QCString::contains( const char *str, bool cs ) const +{ + int count = 0; + char *d = data(); + if ( !d ) + return 0; + int len = qstrlen( str ); + while ( *d ) // counts overlapping strings + { + if ( cs ) + { + if ( qstrncmp( d, str, len ) == 0 ) + count++; + } + else + { + if ( qstrnicmp(d, str, len) == 0 ) + count++; + } + d++; + } + return count; +} + +int QCString::contains( const QRegExp &rx ) const +{ + QString d = QString::fromLatin1( m_data ); + return d.contains( rx ); +} + +QCString QCString::left( uint len ) const +{ + if ( isEmpty() ) + { + return QCString(); + } + else if ( len >= length() ) + { + return *this; + } + else + { + QCString s( len+1 ); + strncpy( s.data(), m_data, len ); + *(s.data()+len) = '\0'; + return s; + } +} + +QCString QCString::right( uint len ) const +{ + if ( isEmpty() ) + { + return QCString(); + } + else + { + uint l = length(); + if ( len > l ) len = l; + char *p = m_data + (l - len); + return QCString( p ); + } +} + +QCString QCString::mid( uint index, uint len) const +{ + uint slen = length(); + if ( len == 0xffffffff ) len = slen-index; + if ( isEmpty() || index >= slen ) + { + return QCString(); + } + else + { + register char *p = data()+index; + QCString s( len+1 ); + strncpy( s.data(), p, len ); + *(s.data()+len) = '\0'; + return s; + } +} + +QCString QCString::lower() const +{ + QCString s( m_data ); + register char *p = s.data(); + if ( p ) + { + while ( *p ) + { + *p = tolower((uchar) *p); + p++; + } + } + return s; +} + +QCString QCString::upper() const +{ + QCString s( m_data ); + register char *p = s.data(); + if ( p ) { + while ( *p ) { + *p = toupper((uchar)*p); + p++; + } + } + return s; +} + +QCString QCString::stripWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + + register char *s = m_data; + int reslen = length(); + if ( !isspace((uchar) s[0]) && !isspace((uchar) s[reslen-1]) ) + return *this; // returns a copy + + QCString result(s); + s = result.data(); + int start = 0; + int end = reslen - 1; + while ( isspace((uchar) s[start]) ) // skip white space from start + start++; + if ( s[start] == '\0' ) + { // only white space + return QCString(); + } + while ( end && isspace((uchar) s[end]) ) // skip white space from end + end--; + end -= start - 1; + memmove( result.data(), &s[start], end ); + result.resize( end + 1 ); + return result; +} + +QCString QCString::simplifyWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + + QCString result( length()+1 ); + char *from = data(); + char *to = result.data(); + char *first = to; + while ( TRUE ) + { + while ( *from && isspace((uchar) *from) ) + from++; + while ( *from && !isspace((uchar)*from) ) + *to++ = *from++; + if ( *from ) + *to++ = 0x20; // ' ' + else + break; + } + if ( to > first && *(to-1) == 0x20 ) + to--; + *to = '\0'; + result.resize( (int)((long)to - (long)result.data()) + 1 ); + return result; +} + +QCString &QCString::insert( uint index, const char *s ) +{ + int len = s ? qstrlen(s) : 0; + if ( len == 0 ) + return *this; + uint olen = length(); + int nlen = olen + len; + if ( index >= olen ) // insert after end of string + { + m_data = (char *)realloc(m_data,nlen+index-olen+1); + if ( m_data ) + { + memset( m_data+olen, ' ', index-olen ); + memcpy( m_data+index, s, len+1 ); + } + } + else if ( (m_data = (char *)realloc(m_data,nlen+1)) ) // normal insert + { + memmove( m_data+index+len, m_data+index, olen-index+1 ); + memcpy( m_data+index, s, len ); + } + return *this; +} + +QCString &QCString::insert( uint index, char c ) // insert char +{ + char buf[2]; + buf[0] = c; + buf[1] = '\0'; + return insert( index, buf ); +} + +QCString& QCString::operator+=( const char *str ) +{ + if ( !str ) return *this; // nothing to append + uint len1 = length(); + uint len2 = qstrlen(str); + char *newData = (char *)realloc( m_data, len1 + len2 + 1 ); + if (newData) + { + m_data = newData; + memcpy( m_data + len1, str, len2 + 1 ); + } + return *this; +} + +QCString &QCString::operator+=( char c ) +{ + uint len = length(); + char *newData = (char *)realloc( m_data, length()+2 ); + if (newData) + { + m_data = newData; + m_data[len] = c; + m_data[len+1] = '\0'; + } + return *this; +} + +QCString &QCString::remove( uint index, uint len ) +{ + uint olen = length(); + if ( index + len >= olen ) // range problems + { + if ( index < olen ) // index ok + { + resize( index+1 ); + } + } + else if ( len != 0 ) + { + memmove( m_data+index, m_data+index+len, olen-index-len+1 ); + resize( olen-len+1 ); + } + return *this; +} + +QCString &QCString::replace( uint index, uint len, const char *s ) +{ + remove( index, len ); + insert( index, s ); + return *this; +} + +QCString &QCString::replace( const QRegExp &rx, const char *str ) +{ + QString d = QString::fromLatin1( m_data ); + QString r = QString::fromLatin1( str ); + d.replace( rx, r ); + operator=( d.ascii() ); + return *this; +} + +long QCString::toLong( bool *ok ) const +{ + QString s(m_data); + return s.toLong(ok); +} + +ulong QCString::toULong( bool *ok ) const +{ + QString s(m_data); + return s.toULong(ok); +} + +short QCString::toShort( bool *ok ) const +{ + QString s(m_data); + return s.toShort(ok); +} + +ushort QCString::toUShort( bool *ok ) const +{ + QString s(m_data); + return s.toUShort(ok); +} + +int QCString::toInt( bool *ok ) const +{ + QString s(m_data); + return s.toInt(ok); +} + +uint QCString::toUInt( bool *ok ) const +{ + QString s(m_data); + return s.toUInt(ok); +} + +QCString &QCString::setNum( long n ) +{ + char buf[20]; + register char *p = &buf[19]; + bool neg; + if ( n < 0 ) + { + neg = TRUE; + n = -n; + } + else + { + neg = FALSE; + } + *p = '\0'; + do + { + *--p = ((int)(n%10)) + '0'; + n /= 10; + } while ( n ); + if ( neg ) *--p = '-'; + operator=( p ); + return *this; +} + +QCString &QCString::setNum( ulong n ) +{ + char buf[20]; + register char *p = &buf[19]; + *p = '\0'; + do + { + *--p = ((int)(n%10)) + '0'; + n /= 10; + } while ( n ); + operator=( p ); + return *this; +} + +void QCString::msg_index( uint index ) +{ +#if defined(CHECK_RANGE) + qWarning( "QCString::at: Absolute index %d out of range", index ); +#else + Q_UNUSED( index ) +#endif +} + +bool QCString::stripPrefix(const char *prefix) +{ + if (prefix==0) return FALSE; + uint plen = qstrlen(prefix); + if (m_data && qstrncmp(prefix,m_data,plen)==0) // prefix matches + { + uint len = qstrlen(m_data); + uint newlen = len-plen+1; + qmemmove(m_data,m_data+plen,newlen); + resize(newlen); + return TRUE; + } + return FALSE; +} + +//--------------------------------------------------------------------------- + +void *qmemmove( void *dst, const void *src, uint len ) +{ + register char *d; + register char *s; + if ( dst > src ) { + d = (char *)dst + len - 1; + s = (char *)src + len - 1; + while ( len-- ) + *d-- = *s--; + } else if ( dst < src ) { + d = (char *)dst; + s = (char *)src; + while ( len-- ) + *d++ = *s++; + } + return dst; +} + +char *qstrdup( const char *str ) +{ + if ( !str ) + return 0; + char *dst = new char[strlen(str)+1]; + CHECK_PTR( dst ); + return strcpy( dst, str ); +} + +char *qstrncpy( char *dst, const char *src, uint len ) +{ + if ( !src ) + return 0; + strncpy( dst, src, len ); + if ( len > 0 ) + dst[len-1] = '\0'; + return dst; +} + +int qstricmp( const char *str1, const char *str2 ) +{ + register const uchar *s1 = (const uchar *)str1; + register const uchar *s2 = (const uchar *)str2; + int res; + uchar c; + if ( !s1 || !s2 ) + return s1 == s2 ? 0 : (int)((long)s2 - (long)s1); + for ( ; !(res = (c=tolower(*s1)) - tolower(*s2)); s1++, s2++ ) + if ( !c ) // strings are equal + break; + return res; +} + +int qstrnicmp( const char *str1, const char *str2, uint len ) +{ + register const uchar *s1 = (const uchar *)str1; + register const uchar *s2 = (const uchar *)str2; + int res; + uchar c; + if ( !s1 || !s2 ) + return (int)((long)s2 - (long)s1); + for ( ; len--; s1++, s2++ ) { + if ( (res = (c=tolower(*s1)) - tolower(*s2)) ) + return res; + if ( !c ) // strings are equal + break; + } + return 0; +} + +#ifndef QT_NO_DATASTREAM + +QDataStream &operator<<( QDataStream &s, const QByteArray &a ) +{ + return s.writeBytes( a.data(), a.size() ); +} + +QDataStream &operator>>( QDataStream &s, QByteArray &a ) +{ + Q_UINT32 len; + s >> len; // read size of array + if ( len == 0 || s.eof() ) { // end of file reached + a.resize( 0 ); + return s; + } + if ( !a.resize( (uint)len ) ) { // resize array +#if defined(CHECK_NULL) + qWarning( "QDataStream: Not enough memory to read QByteArray" ); +#endif + len = 0; + } + if ( len > 0 ) // not null array + s.readRawBytes( a.data(), (uint)len ); + return s; +} + +QDataStream &operator<<( QDataStream &s, const QCString &str ) +{ + return s.writeBytes( str.data(), str.size() ); +} + +QDataStream &operator>>( QDataStream &s, QCString &str ) +{ + Q_UINT32 len; + s >> len; // read size of string + if ( len == 0 || s.eof() ) { // end of file reached + str.resize( 0 ); + return s; + } + if ( !str.resize( (uint)len )) {// resize string +#if defined(CHECK_NULL) + qWarning( "QDataStream: Not enough memory to read QCString" ); +#endif + len = 0; + } + if ( len > 0 ) // not null array + s.readRawBytes( str.data(), (uint)len ); + return s; +} + +#endif //QT_NO_DATASTREAM + +inline QCString operator+( const QCString &s1, const QGString &s2 ) +{ + QCString tmp(s1); + tmp += s2.data(); + return tmp; +} + +inline QCString operator+( const QGString &s1, const QCString &s2 ) +{ + QCString tmp(s1.data()); + tmp += s2; + return tmp; +} + diff --git a/trunk/qtools/qcstring.h b/trunk/qtools/qcstring.h new file mode 100644 index 0000000..ef1189a --- /dev/null +++ b/trunk/qtools/qcstring.h @@ -0,0 +1,453 @@ +/**************************************************************************** +** +** +** Definition of the extended char array operations, +** and QByteArray and QCString classes +** +** Created : 920609 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QCSTRING_H +#define QCSTRING_H + +#ifndef QT_H +#include "qarray.h" +#endif // QT_H + +#include <stdlib.h> +#include <string.h> + +#if defined(_OS_SUN_) && defined(_CC_GNU_) +#include <strings.h> +#endif + + +class QGString; + +/***************************************************************************** + Fixes and workarounds for some platforms + *****************************************************************************/ + +#if defined(_OS_HPUX_) +// HP-UX has badly defined strstr() etc. +// ### fix in 3.0: change hack_* to qt_hack_* +// by the way HP-UX is probably right, the standard has evolved and +// we'll have to adapt to it +inline char *hack_strstr( const char *s1, const char *s2 ) +{ return (char *)strstr(s1, s2); } +inline char *hack_strchr( const char *s, int c ) +{ return (char *)strchr(s, c); } +inline char *hack_strrchr( const char *s, int c ) +{ return (char *)strrchr(s, c); } +#define strstr(s1,s2) hack_strstr((s1),(s2)) +#define strchr(s,c) hack_strchr((s),(c)) +#define strrchr(s,c) hack_strrchr((s),(c)) +#endif + + +/***************************************************************************** + Safe and portable C string functions; extensions to standard string.h + *****************************************************************************/ + +Q_EXPORT void *qmemmove( void *dst, const void *src, uint len ); + +#if defined(_OS_SUN_) || defined(_CC_OC_) +#define memmove(s1,s2,n) qmemmove((s1),(s2),(n)) +#endif + +Q_EXPORT char *qstrdup( const char * ); + +Q_EXPORT inline uint cstrlen( const char *str ) +{ return strlen(str); } + +Q_EXPORT inline uint qstrlen( const char *str ) +{ return str ? strlen(str) : 0; } + +Q_EXPORT inline char *cstrcpy( char *dst, const char *src ) +{ return strcpy(dst,src); } + +Q_EXPORT inline char *qstrcpy( char *dst, const char *src ) +{ return src ? strcpy(dst, src) : 0; } + +Q_EXPORT char *qstrncpy( char *dst, const char *src, uint len ); + +Q_EXPORT inline int cstrcmp( const char *str1, const char *str2 ) +{ return strcmp(str1,str2); } + +Q_EXPORT inline int qstrcmp( const char *str1, const char *str2 ) +{ return (str1 && str2) ? strcmp(str1,str2) : (int)((long)str2 - (long)str1); } + +Q_EXPORT inline int cstrncmp( const char *str1, const char *str2, uint len ) +{ return strncmp(str1,str2,len); } + +Q_EXPORT inline int qstrncmp( const char *str1, const char *str2, uint len ) +{ return (str1 && str2) ? strncmp(str1,str2,len) : + (int)((long)str2 - (long)str1); } + +Q_EXPORT int qstricmp( const char *, const char * ); + +Q_EXPORT int qstrnicmp( const char *, const char *, uint len ); + +// ### TODO for 3.0: these and the cstr* functions should be used if +// !defined(QT_CLEAN_NAMESPACE) +// We want to keep source compatibility for 2.x +// ### TODO for 4.0: completely remove these and the cstr* functions + +#if !defined(QT_GENUINE_STR) + +#undef strlen +#define strlen qstrlen + +#undef strcpy +#define strcpy qstrcpy + +#undef strcmp +#define strcmp qstrcmp + +#undef strncmp +#define strncmp qstrncmp + +#undef stricmp +#define stricmp qstricmp + +#undef strnicmp +#define strnicmp qstrnicmp + +#endif + +// qChecksum: Internet checksum + +Q_EXPORT Q_UINT16 qChecksum( const char *s, uint len ); + +/***************************************************************************** + QByteArray class + *****************************************************************************/ + +#if defined(Q_TEMPLATEDLL) +template class Q_EXPORT QArray<char>; +#endif +typedef QArray<char> QByteArray; + + +/***************************************************************************** + QByteArray stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator<<( QDataStream &, const QByteArray & ); +Q_EXPORT QDataStream &operator>>( QDataStream &, QByteArray & ); +#endif + +class QRegExp; + +/** This is an alternative implementation of QCString. It provides basically + * the same functions but uses less memory for administration. This class + * is just a wrapper around a plain C string requiring only 4 bytes "overhead". + * QCString features sharing of data and stores the string length, but + * requires 4 + 12 bytes for this (even for the empty string). As doxygen + * uses a LOT of string during a run it saves a lot of memory to use a + * more memory efficient implementation at the cost of relatively low + * runtime overhead. + */ +class QCString +{ +public: + QCString() : m_data(0) {} // make null string + QCString( const QCString &s ); + QCString( int size ); + QCString( const char *str ); + QCString( const char *str, uint maxlen ); + ~QCString(); + + QCString &operator=( const QCString &s );// deep copy + QCString &operator=( const char *str ); // deep copy + + bool isNull() const; + bool isEmpty() const; + uint length() const; + uint size() const { return m_data ? length()+1 : 0; } + char * data() const { return m_data; } + bool resize( uint newlen ); + bool truncate( uint pos ); + bool fill( char c, int len = -1 ); + + QCString copy() const; + + QCString &sprintf( const char *format, ... ); + + int find( char c, int index=0, bool cs=TRUE ) const; + int find( const char *str, int index=0, bool cs=TRUE ) const; + int find( const QRegExp &, int index=0 ) const; + int findRev( char c, int index=-1, bool cs=TRUE) const; + int findRev( const char *str, int index=-1, bool cs=TRUE) const; + int findRev( const QRegExp &, int index=-1 ) const; + int contains( char c, bool cs=TRUE ) const; + int contains( const char *str, bool cs=TRUE ) const; + int contains( const QRegExp & ) const; + bool stripPrefix(const char *prefix); + + QCString left( uint len ) const; + QCString right( uint len ) const; + QCString mid( uint index, uint len=0xffffffff) const; + + QCString lower() const; + QCString upper() const; + + QCString stripWhiteSpace() const; + QCString simplifyWhiteSpace() const; + + QCString &assign( const char *str ); + QCString &insert( uint index, const char * ); + QCString &insert( uint index, char ); + QCString &append( const char *s ); + QCString &prepend( const char *s ); + QCString &remove( uint index, uint len ); + QCString &replace( uint index, uint len, const char * ); + QCString &replace( const QRegExp &, const char * ); + + short toShort( bool *ok=0 ) const; + ushort toUShort( bool *ok=0 ) const; + int toInt( bool *ok=0 ) const; + uint toUInt( bool *ok=0 ) const; + long toLong( bool *ok=0 ) const; + ulong toULong( bool *ok=0 ) const; + + QCString &setNum( short ); + QCString &setNum( ushort ); + QCString &setNum( int ); + QCString &setNum( uint ); + QCString &setNum( long ); + QCString &setNum( ulong ); + QCString &setNum( float, char f='g', int prec=6 ); + QCString &setNum( double, char f='g', int prec=6 ); + + operator const char *() const; + QCString &operator+=( const char *str ); + QCString &operator+=( char c ); + char &at( uint index ) const; + char &operator[]( int i ) const { return at(i); } + + private: + static void msg_index( uint ); + void duplicate( const QCString &s ); + void duplicate( const char *str); + QCString &duplicate( const char *str, int); + + char * m_data; +}; + +inline char &QCString::at( uint index ) const +{ + return m_data[index]; +} + +inline void QCString::duplicate( const QCString &s ) +{ + if (!s.isEmpty()) + { + uint l = strlen(s.data()); + m_data = (char *)malloc(l+1); + if (m_data) memcpy(m_data,s.data(),l+1); + } + else + m_data=0; +} + +inline void QCString::duplicate( const char *str) +{ + if (str && str[0]!='\0') + { + uint l = strlen(str); + m_data = (char *)malloc(l+1); + if (m_data) memcpy(m_data,str,l+1); + } + else + m_data=0; +} + +inline QCString &QCString::duplicate( const char *str, int) +{ + if (m_data==str) return *this; + if (m_data) free(m_data); + duplicate(str); + return *this; +} + +/***************************************************************************** + QCString stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator<<( QDataStream &, const QCString & ); +Q_EXPORT QDataStream &operator>>( QDataStream &, QCString & ); +#endif + +/***************************************************************************** + QCString inline functions + *****************************************************************************/ + +inline QCString &QCString::operator=( const QCString &s ) +{ return (QCString&)assign( s ); } + +inline QCString &QCString::operator=( const char *str ) +{ return (QCString&)duplicate( str, qstrlen(str)+1 ); } + +inline bool QCString::isNull() const +{ return data() == 0; } + +inline bool QCString::isEmpty() const +{ return data() == 0 || *data() == '\0'; } + +inline uint QCString::length() const +{ return qstrlen( data() ); } + +inline bool QCString::truncate( uint pos ) +{ return resize(pos+1); } + +inline QCString QCString::copy() const +{ return QCString( data() ); } + +inline QCString &QCString::prepend( const char *s ) +{ return insert(0,s); } + +inline QCString &QCString::append( const char *s ) +{ return operator+=(s); } + +inline QCString &QCString::setNum( short n ) +{ return setNum((long)n); } + +inline QCString &QCString::setNum( ushort n ) +{ return setNum((ulong)n); } + +inline QCString &QCString::setNum( int n ) +{ return setNum((long)n); } + +inline QCString &QCString::setNum( uint n ) +{ return setNum((ulong)n); } + +inline QCString &QCString::setNum( float n, char f, int prec ) +{ return setNum((double)n,f,prec); } + +inline QCString::operator const char *() const +{ return (const char *)data(); } + + +/***************************************************************************** + QCString non-member operators + *****************************************************************************/ + +Q_EXPORT inline bool operator==( const QCString &s1, const QCString &s2 ) +{ return qstrcmp(s1.data(),s2.data()) == 0; } + +Q_EXPORT inline bool operator==( const QCString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) == 0; } + +Q_EXPORT inline bool operator==( const char *s1, const QCString &s2 ) +{ return qstrcmp(s1,s2.data()) == 0; } + +Q_EXPORT inline bool operator!=( const QCString &s1, const QCString &s2 ) +{ return qstrcmp(s1.data(),s2.data()) != 0; } + +Q_EXPORT inline bool operator!=( const QCString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) != 0; } + +Q_EXPORT inline bool operator!=( const char *s1, const QCString &s2 ) +{ return qstrcmp(s1,s2.data()) != 0; } + +Q_EXPORT inline bool operator<( const QCString &s1, const QCString& s2 ) +{ return qstrcmp(s1.data(),s2.data()) < 0; } + +Q_EXPORT inline bool operator<( const QCString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) < 0; } + +Q_EXPORT inline bool operator<( const char *s1, const QCString &s2 ) +{ return qstrcmp(s1,s2.data()) < 0; } + +Q_EXPORT inline bool operator<=( const QCString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) <= 0; } + +Q_EXPORT inline bool operator<=( const char *s1, const QCString &s2 ) +{ return qstrcmp(s1,s2.data()) <= 0; } + +Q_EXPORT inline bool operator>( const QCString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) > 0; } + +Q_EXPORT inline bool operator>( const char *s1, const QCString &s2 ) +{ return qstrcmp(s1,s2.data()) > 0; } + +Q_EXPORT inline bool operator>=( const QCString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) >= 0; } + +Q_EXPORT inline bool operator>=( const char *s1, const QCString &s2 ) +{ return qstrcmp(s1,s2.data()) >= 0; } + +Q_EXPORT inline QCString operator+( const QCString &s1, const QCString &s2 ) +{ + QCString tmp(s1); + tmp += s2; + return tmp; +} + + +inline QCString operator+( const QCString &s1, const QGString &s2 ); +inline QCString operator+( const QGString &s1, const QCString &s2 ); + + +Q_EXPORT inline QCString operator+( const QCString &s1, const char *s2 ) +{ + QCString tmp(s1); + tmp += s2; + return tmp; +} + +Q_EXPORT inline QCString operator+( const char *s1, const QCString &s2 ) +{ + QCString tmp(s1); + tmp += s2; + return tmp; +} + +Q_EXPORT inline QCString operator+( const QCString &s1, char c2 ) +{ + QCString tmp( s1.data() ); + tmp += c2; + return tmp; +} + +Q_EXPORT inline QCString operator+( char c1, const QCString &s2 ) +{ + QCString tmp; + tmp += c1; + tmp += s2; + return tmp; +} + + +#endif // QCSTRING_H diff --git a/trunk/qtools/qdatastream.cpp b/trunk/qtools/qdatastream.cpp new file mode 100644 index 0000000..7f63cbf --- /dev/null +++ b/trunk/qtools/qdatastream.cpp @@ -0,0 +1,951 @@ +/**************************************************************************** +** +** +** Implementation of QDataStream class +** +** Created : 930831 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qdatastream.h" + +#ifndef QT_NO_DATASTREAM +#include "qbuffer.h" +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> + +// REVISED: warwick +/*! + \class QDataStream qdatastream.h + + \brief The QDataStream class provides serialization of + binary data to a QIODevice. + + \ingroup io + + A data stream is a binary stream of encoded information which is 100% + independent of the host computer operation system, CPU or byte order. A + stream that is written by a PC under DOS/Windows can be read by a + Sun SPARC running Solaris. + + The QDataStream class implements serialization of primitive types, like + \c char, \c short, \c int, \c char* etc. Serialization of more complex + data is accomplished by breaking up the data into primitive units. + + The programmer can select which byte order to use when serializing data. + The default setting is big endian (MSB first). Changing it to little + endian breaks the portability (unless the reader also changes to little + endian). We recommend keeping this setting unless you have + special requirements. + + A data stream cooperates closely with a QIODevice. A QIODevice + represents an input/output medium one can read data from and write data + to. The QFile class is an example of an IO device. + + Example (write data to a stream): + \code + QFile f( "file.dta" ); + f.open( IO_WriteOnly ); // open file for writing + QDataStream s( &f ); // serialize using f + s << "the answer is"; // serialize string + s << (Q_INT32)42; // serialize integer + \endcode + + Example (read data from a stream): + \code + QFile f( "file.dta" ); + f.open( IO_ReadOnly ); // open file for reading + QDataStream s( &f ); // serialize using f + char *str; + Q_INT32 a; + s >> str >> a; // "the answer is" and 42 + delete str; // delete string + \endcode + + In the last example, if you read into a QString instead of a \c char* + you do not have to delete it. + + Normally, each item written to the stream is written in a fixed binary + format. + For example, a \c char* is written as a 32-bit integer equal to the + length of the string including the NUL byte, followed by all the + characters of the string including the NUL byte. Similarly when + reading a string, 4 bytes are read to create the 32-bit length value, + then that many characters for the string including the NUL. For a complete + description of all Qt types supporting data streaming see \link + datastreamformat.html Format of the QDataStream operators \endlink . + + If you want a "parsing" input stream, see QTextStream. If you just want the + data to be human-readable to aid in debugging, you can set the data + stream into printable data mode with setPrintableData(). The data is + then written slower, in a human readable bloated form that is sufficient + for debugging. + + If you are producing a new binary data format, such as a file format + for documents created by your application, you could use a QDataStream + to write the data in a portable format. Typically, you would write + a brief header containing a magic string and a version number to give + yourself room for future expansion. For example: + + \code + // Open the file. + QFile f( "file.xxx" ); + f.open( IO_WriteOnly ); + QDataStream s( &f ); + + // Write a header with a "magic number" and a version + s << 0xa0b0c0d0; + s << 123; + + // Write the data + s << [lots of interesting data] + \endcode + + Then read it in with: + + \code + // Open the file. + QFile f( "file.xxx" ); + f.open( IO_ReadOnly ); + QDataStream s( &f ); + + // Read and check the header + Q_UINT32 magic; + s >> magic; + if ( magic != 0xa0b0c0d0 ) + return XXX_BAD_FILE_FORMAT; + + // Read the version + Q_INT32 version; + s >> version; + if ( version < 100 ) + return XXX_BAD_FILE_TOO_OLD; + if ( version > 123 ) + return XXX_BAD_FILE_TOO_NEW; + if ( version <= 110 ) + s.setVersion(1); + + // Read the data + s >> [lots of interesting data]; + if ( version > 120 ) + s >> [data new in XXX version 1.2]; + s >> [other interesting data]; + \endcode + + \sa QTextStream QVariant +*/ + + +/***************************************************************************** + QDataStream member functions + *****************************************************************************/ + +#if defined(CHECK_STATE) +#undef CHECK_STREAM_PRECOND +#define CHECK_STREAM_PRECOND if ( !dev ) { \ + qWarning( "QDataStream: No device" ); \ + return *this; } +#else +#define CHECK_STREAM_PRECOND +#endif + +static int systemWordSize = 0; +static bool systemBigEndian; + +static const int DefaultStreamVersion = 3; +// 3 is default in Qt 2.1 +// 2 is the Qt 2.0.x format +// 1 is the Qt 1.x format + +/*! + Constructs a data stream that has no IO device. + + \sa setDevice() +*/ + +QDataStream::QDataStream() +{ + if ( systemWordSize == 0 ) // get system features + qSysInfo( &systemWordSize, &systemBigEndian ); + dev = 0; // no device set + owndev = FALSE; + byteorder = BigEndian; // default byte order + printable = FALSE; + ver = DefaultStreamVersion; + noswap = systemBigEndian; +} + +/*! + Constructs a data stream that uses the IO device \a d. + + \sa setDevice(), device() +*/ + +QDataStream::QDataStream( QIODevice *d ) +{ + if ( systemWordSize == 0 ) // get system features + qSysInfo( &systemWordSize, &systemBigEndian ); + dev = d; // set device + owndev = FALSE; + byteorder = BigEndian; // default byte order + printable = FALSE; + ver = DefaultStreamVersion; + noswap = systemBigEndian; +} + +/*! + Constructs a data stream that operates on a byte array through an + internal QBuffer device. + + Example: + \code + static char bindata[] = { 231, 1, 44, ... }; + QByteArray a; + a.setRawData( bindata, sizeof(bindata) ); // a points to bindata + QDataStream s( a, IO_ReadOnly ); // open on a's data + s >> [something]; // read raw bindata + a.resetRawData( bindata, sizeof(bindata) ); // finished + \endcode + + The QArray::setRawData() function is not for the inexperienced. +*/ + +QDataStream::QDataStream( QByteArray a, int mode ) +{ + if ( systemWordSize == 0 ) // get system features + qSysInfo( &systemWordSize, &systemBigEndian ); + dev = new QBuffer( a ); // create device + ((QBuffer *)dev)->open( mode ); // open device + owndev = TRUE; + byteorder = BigEndian; // default byte order + printable = FALSE; + ver = DefaultStreamVersion; + noswap = systemBigEndian; +} + +/*! + Destructs the data stream. + + The destructor will not affect the current IO device, unless it + is an internal IO device processing a QByteArray passed in the constructor. +*/ + +QDataStream::~QDataStream() +{ + if ( owndev ) + delete dev; +} + + +/*! + \fn QIODevice *QDataStream::device() const + Returns the IO device currently set. + \sa setDevice(), unsetDevice() +*/ + +/*! + void QDataStream::setDevice(QIODevice *d ) + Sets the IO device to \a d. + \sa device(), unsetDevice() +*/ + +void QDataStream::setDevice(QIODevice *d ) +{ + if ( owndev ) { + delete dev; + owndev = FALSE; + } + dev = d; +} + +/*! + Unsets the IO device. This is the same as calling setDevice( 0 ). + \sa device(), setDevice() +*/ + +void QDataStream::unsetDevice() +{ + setDevice( 0 ); +} + + +/*! + \fn bool QDataStream::atEnd() const + Returns TRUE if the IO device has reached the end position (end of + stream or file) or if there is no IO device set. + + Returns FALSE if the current position of the read/write head of the IO + device is somewhere before the end position. + + \sa QIODevice::atEnd() +*/ + +/*!\fn bool QDataStream::eof() const + + \obsolete + + Returns TRUE if the IO device has reached the end position (end of + stream or file) or if there is no IO device set. + + Returns FALSE if the current position of the read/write head of the IO + device is somewhere before the end position. + + \sa QIODevice::atEnd() +*/ + +/*! + \fn int QDataStream::byteOrder() const + Returns the current byte order setting - either \c BigEndian or + \c LittleEndian. + + \sa setByteOrder() +*/ + +/*! + Sets the serialization byte order to \a bo. + + The \a bo parameter can be \c QDataStream::BigEndian or + \c QDataStream::LittleEndian. + + The default setting is big endian. We recommend leaving this setting unless + you have special requirements. + + \sa byteOrder() +*/ + +void QDataStream::setByteOrder( int bo ) +{ + byteorder = bo; + if ( systemBigEndian ) + noswap = byteorder == BigEndian; + else + noswap = byteorder == LittleEndian; +} + + +/*! + \fn bool QDataStream::isPrintableData() const + Returns TRUE if the printable data flag has been set. + \sa setPrintableData() +*/ + +/*! + \fn void QDataStream::setPrintableData( bool enable ) + Sets or clears the printable data flag. + + If this flag is set, the write functions will generate output that + consists of printable characters (7 bit ASCII). + + We recommend enabling printable data only for debugging purposes + (it is slower and creates larger output). +*/ + + +/*! + \fn int QDataStream::version() const + Returns the version number of the data serialization format. + In Qt 2.1, this number is by default 3. + \sa setVersion() +*/ + +/*! + \fn void QDataStream::setVersion( int v ) + Sets the version number of the data serialization format. + + In order to accomodate for new functionality, the datastream + serialization format of some Qt classes has changed in some versions of + Qt. If you want to read data that was created by an earlier version of + Qt, or write data that can be read by a program that was compiled with + an earlier version of Qt, use this function to modify the serialization + format of QDataStream. + + For Qt 1.x compatibility, use \a v == 1. + + For Qt 2.0.x compatibility, use \a v == 2 (Not required for reading in + Qt 2.1). + + \sa version() +*/ + +/***************************************************************************** + QDataStream read functions + *****************************************************************************/ + + +static Q_INT32 read_int_ascii( QDataStream *s ) +{ + register int n = 0; + char buf[40]; + while ( TRUE ) { + buf[n] = s->device()->getch(); + if ( buf[n] == '\n' || n > 38 ) // $-terminator + break; + n++; + } + buf[n] = '\0'; + return atol( buf ); +} + + +/*! + \fn QDataStream &QDataStream::operator>>( Q_UINT8 &i ) + Reads an unsigned byte from the stream and returns a reference to + the stream. +*/ + +/*! + Reads a signed byte from the stream. +*/ + +QDataStream &QDataStream::operator>>( Q_INT8 &i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + i = (Q_INT8)dev->getch(); + if ( i == '\\' ) { // read octal code + char buf[4]; + dev->readBlock( buf, 3 ); + i = (buf[2] & 0x07)+((buf[1] & 0x07) << 3)+((buf[0] & 0x07) << 6); + } + } else { // data or text + i = (Q_INT8)dev->getch(); + } + return *this; +} + + +/*! + \fn QDataStream &QDataStream::operator>>( Q_UINT16 &i ) + Reads an unsigned 16-bit integer from the stream and returns a reference to + the stream. +*/ + +/*! + Reads a signed 16-bit integer from the stream and returns a reference to + the stream. +*/ + +QDataStream &QDataStream::operator>>( Q_INT16 &i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + i = (Q_INT16)read_int_ascii( this ); + } else if ( noswap ) { // no conversion needed + dev->readBlock( (char *)&i, sizeof(Q_INT16) ); + } else { // swap bytes + register uchar *p = (uchar *)(&i); + char b[2]; + dev->readBlock( b, 2 ); + *p++ = b[1]; + *p = b[0]; + } + return *this; +} + + +/*! + \fn QDataStream &QDataStream::operator>>( Q_UINT32 &i ) + Reads an unsigned 32-bit integer from the stream and returns a reference to + the stream. +*/ + +/*! + Reads a signed 32-bit integer from the stream and returns a reference to + the stream. +*/ + +QDataStream &QDataStream::operator>>( Q_INT32 &i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + i = read_int_ascii( this ); + } else if ( noswap ) { // no conversion needed + dev->readBlock( (char *)&i, sizeof(Q_INT32) ); + } else { // swap bytes + register uchar *p = (uchar *)(&i); + char b[4]; + dev->readBlock( b, 4 ); + *p++ = b[3]; + *p++ = b[2]; + *p++ = b[1]; + *p = b[0]; + } + return *this; +} + +/*! + \fn QDataStream &QDataStream::operator>>( Q_UINT64 &i ) + Reads an unsigned 64-bit integer from the stream and returns a reference to + the stream, or uses the Q_UINT32 operator if 64 bit is not available. +*/ + +/*! + Reads a signed 64-bit integer from the stream and returns a reference to + the stream, or uses the Q_UINT32 operator if 64 bit is not available. +*/ + +QDataStream &QDataStream::operator>>( Q_INT64 &i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + i = read_int_ascii( this ); + } else if ( noswap ) { // no conversion needed + dev->readBlock( (char *)&i, sizeof(Q_INT64) ); + } else { // swap bytes + register uchar *p = (uchar *)(&i); + char b[sizeof(Q_INT64)]; + dev->readBlock( b, sizeof(Q_INT64) ); + if ( sizeof(Q_INT64) == 8 ) { + *p++ = b[7]; + *p++ = b[6]; + *p++ = b[5]; + *p++ = b[4]; + } + *p++ = b[3]; + *p++ = b[2]; + *p++ = b[1]; + *p = b[0]; + } + return *this; +} + +static double read_double_ascii( QDataStream *s ) +{ + register int n = 0; + char buf[80]; + while ( TRUE ) { + buf[n] = s->device()->getch(); + if ( buf[n] == '\n' || n > 78 ) // $-terminator + break; + n++; + } + buf[n] = '\0'; + return atof( buf ); +} + + +/*! + Reads a 32-bit floating point number from the stream using the standard + IEEE754 format. Returns a reference to the stream. +*/ + +QDataStream &QDataStream::operator>>( float &f ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + f = (float)read_double_ascii( this ); + } else if ( noswap ) { // no conversion needed + dev->readBlock( (char *)&f, sizeof(float) ); + } else { // swap bytes + register uchar *p = (uchar *)(&f); + char b[4]; + dev->readBlock( b, 4 ); + *p++ = b[3]; + *p++ = b[2]; + *p++ = b[1]; + *p = b[0]; + } + return *this; +} + + +/*! + Reads a 64-bit floating point number from the stream using the standard + IEEE754 format. Returns a reference to the stream. +*/ + +QDataStream &QDataStream::operator>>( double &f ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + f = read_double_ascii( this ); + } else if ( noswap ) { // no conversion needed + dev->readBlock( (char *)&f, sizeof(double) ); + } else { // swap bytes + register uchar *p = (uchar *)(&f); + char b[8]; + dev->readBlock( b, 8 ); + *p++ = b[7]; + *p++ = b[6]; + *p++ = b[5]; + *p++ = b[4]; + *p++ = b[3]; + *p++ = b[2]; + *p++ = b[1]; + *p = b[0]; + } + return *this; +} + + +/*! + Reads the '\0'-terminated string \a s from the stream and returns + a reference to the stream. + + Space for the string is allocated using \c new - the caller must + eventually call delete[] on the value. +*/ + +QDataStream &QDataStream::operator>>( char *&s ) +{ + uint len = 0; + return readBytes( s, len ); +} + + +/*! + Reads the buffer \a s from the stream and returns a reference to the + stream. + + The buffer \a s is allocated using \c new. Destroy it with the \c delete[] + operator. If the length is zero or \a s cannot be allocated, \a s is + set to 0. + + The \a l parameter will be set to the length of the buffer. + + The serialization format is an Q_UINT32 length specifier first, then the + data (\a l bytes). + + \sa readRawBytes(), writeBytes() +*/ + +QDataStream &QDataStream::readBytes( char *&s, uint &l ) +{ + CHECK_STREAM_PRECOND + Q_UINT32 len; + *this >> len; // first read length spec + l = (uint)len; + if ( len == 0 || eof() ) { + s = 0; + return *this; + } else { + s = new char[len]; // create char array + CHECK_PTR( s ); + if ( !s ) // no memory + return *this; + return readRawBytes( s, (uint)len ); + } +} + + +/*! + Reads \a len bytes from the stream into \a s and returns a reference to + the stream. + + The buffer \a s must be preallocated. + + \sa readBytes(), QIODevice::readBlock(), writeRawBytes() +*/ + +QDataStream &QDataStream::readRawBytes( char *s, uint len ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + register Q_INT8 *p = (Q_INT8*)s; + while ( len-- ) + *this >> *p++; + } else { // read data char array + dev->readBlock( s, len ); + } + return *this; +} + + +/***************************************************************************** + QDataStream write functions + *****************************************************************************/ + + +/*! + \fn QDataStream &QDataStream::operator<<( Q_UINT8 i ) + Writes an unsigned byte to the stream and returns a reference to + the stream. +*/ + +/*! + Writes a signed byte to the stream. +*/ + +QDataStream &QDataStream::operator<<( Q_INT8 i ) +{ + CHECK_STREAM_PRECOND + if ( printable && (i == '\\' || !isprint(i)) ) { + char buf[6]; // write octal code + buf[0] = '\\'; + buf[1] = '0' + ((i >> 6) & 0x07); + buf[2] = '0' + ((i >> 3) & 0x07); + buf[3] = '0' + (i & 0x07); + buf[4] = '\0'; + dev->writeBlock( buf, 4 ); + } else { + dev->putch( i ); + } + return *this; +} + + +/*! + \fn QDataStream &QDataStream::operator<<( Q_UINT16 i ) + Writes an unsigned 16-bit integer to the stream and returns a reference + to the stream. +*/ + +/*! + Writes a signed 16-bit integer to the stream and returns a reference to + the stream. +*/ + +QDataStream &QDataStream::operator<<( Q_INT16 i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + char buf[16]; + sprintf( buf, "%d\n", i ); + dev->writeBlock( buf, strlen(buf) ); + } else if ( noswap ) { // no conversion needed + dev->writeBlock( (char *)&i, sizeof(Q_INT16) ); + } else { // swap bytes + register uchar *p = (uchar *)(&i); + char b[2]; + b[1] = *p++; + b[0] = *p; + dev->writeBlock( b, 2 ); + } + return *this; +} + + +/*! + \fn QDataStream &QDataStream::operator<<( Q_UINT32 i ) + Writes an unsigned 32-bit integer to the stream and returns a reference to + the stream. +*/ + +/*! + Writes a signed 32-bit integer to the stream and returns a reference to + the stream. +*/ + +QDataStream &QDataStream::operator<<( Q_INT32 i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + char buf[16]; + sprintf( buf, "%d\n", i ); + dev->writeBlock( buf, strlen(buf) ); + } else if ( noswap ) { // no conversion needed + dev->writeBlock( (char *)&i, sizeof(Q_INT32) ); + } else { // swap bytes + register uchar *p = (uchar *)(&i); + char b[4]; + b[3] = *p++; + b[2] = *p++; + b[1] = *p++; + b[0] = *p; + dev->writeBlock( b, 4 ); + } + return *this; +} + +/*! + \fn QDataStream &QDataStream::operator<<( Q_UINT64 i ) + Writes an unsigned 64-bit integer to the stream and returns a reference to + the stream, or uses the Q_UINT32-operator if 64 bit is not available. +*/ + +/*! + Writes a signed 64-bit integer to the stream and returns a reference to + the stream, or calls the Q_INT32-operator if 64 bit is not available. +*/ + +QDataStream &QDataStream::operator<<( Q_INT64 i ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + char buf[20]; + sprintf( buf, "%ld\n", i ); + dev->writeBlock( buf, strlen(buf) ); + } else if ( noswap ) { // no conversion needed + dev->writeBlock( (char *)&i, sizeof(Q_INT64) ); + } else { // swap bytes + register uchar *p = (uchar *)(&i); + char b[sizeof(Q_INT64)]; + if ( sizeof(Q_INT64) == 8 ) { + b[7] = *p++; + b[6] = *p++; + b[5] = *p++; + b[4] = *p++; + } + b[3] = *p++; + b[2] = *p++; + b[1] = *p++; + b[0] = *p; + dev->writeBlock( b, sizeof(Q_INT64) ); + } + return *this; +} + +/*! + \fn QDataStream &QDataStream::operator<<( uint i ) + Writes an unsigned integer to the stream as a 32-bit unsigned integer + (Q_UINT32). + Returns a reference to the stream. +*/ + +/*! + \fn QDataStream &QDataStream::operator<<( int i ) + Writes a signed integer to the stream as a 32-bit signed integer (Q_INT32). + Returns a reference to the stream. +*/ + + +/*! + Writes a 32-bit floating point number to the stream using the standard + IEEE754 format. Returns a reference to the stream. +*/ + +QDataStream &QDataStream::operator<<( float f ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + char buf[32]; + sprintf( buf, "%g\n", (double)f ); + dev->writeBlock( buf, strlen(buf) ); + } else { + float g = f; // fixes float-on-stack problem + if ( noswap ) { // no conversion needed + dev->writeBlock( (char *)&g, sizeof(float) ); + } else { // swap bytes + register uchar *p = (uchar *)(&g); + char b[4]; + b[3] = *p++; + b[2] = *p++; + b[1] = *p++; + b[0] = *p; + dev->writeBlock( b, 4 ); + } + } + return *this; +} + + +/*! + Writes a 64-bit floating point number to the stream using the standard + IEEE754 format. Returns a reference to the stream. +*/ + +QDataStream &QDataStream::operator<<( double f ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // printable data + char buf[32]; + sprintf( buf, "%g\n", f ); + dev->writeBlock( buf, strlen(buf) ); + } else if ( noswap ) { // no conversion needed + dev->writeBlock( (char *)&f, sizeof(double) ); + } else { // swap bytes + register uchar *p = (uchar *)(&f); + char b[8]; + b[7] = *p++; + b[6] = *p++; + b[5] = *p++; + b[4] = *p++; + b[3] = *p++; + b[2] = *p++; + b[1] = *p++; + b[0] = *p; + dev->writeBlock( b, 8 ); + } + return *this; +} + + +/*! + Writes the '\0'-terminated string \a s to the stream and returns + a reference to the stream. + + The string is serialized using writeBytes(). +*/ + +QDataStream &QDataStream::operator<<( const char *s ) +{ + if ( !s ) { + *this << (Q_UINT32)0; + return *this; + } + uint len = qstrlen( s ) + 1; // also write null terminator + *this << (Q_UINT32)len; // write length specifier + return writeRawBytes( s, len ); +} + + +/*! + Writes the length specifier \a len and the buffer \a s to the stream and + returns a reference to the stream. + + The \a len is serialized as an Q_UINT32, followed by \a len bytes from + \a s. + + \sa writeRawBytes(), readBytes() +*/ + +QDataStream &QDataStream::writeBytes(const char *s, uint len) +{ + CHECK_STREAM_PRECOND + *this << (Q_UINT32)len; // write length specifier + if ( len ) + writeRawBytes( s, len ); + return *this; +} + + +/*! + Writes \a len bytes from \a s to the stream and returns a reference to the + stream. + + \sa writeBytes(), QIODevice::writeBlock(), readRawBytes() +*/ + +QDataStream &QDataStream::writeRawBytes( const char *s, uint len ) +{ + CHECK_STREAM_PRECOND + if ( printable ) { // write printable + register char *p = (char *)s; + while ( len-- ) + *this << *p++; + } else { // write data char array + dev->writeBlock( s, len ); + } + return *this; +} + +#endif // QT_NO_DATASTREAM diff --git a/trunk/qtools/qdatastream.h b/trunk/qtools/qdatastream.h new file mode 100644 index 0000000..3d18062 --- /dev/null +++ b/trunk/qtools/qdatastream.h @@ -0,0 +1,173 @@ +/**************************************************************************** +** +** +** Definition of QDataStream class +** +** Created : 930831 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QDATASTREAM_H +#define QDATASTREAM_H + +#ifndef QT_H +#include "qiodevice.h" +#include "qstring.h" +#endif // QT_H + +#ifndef QT_NO_DATASTREAM +class Q_EXPORT QDataStream // data stream class +{ +public: + QDataStream(); + QDataStream( QIODevice * ); + QDataStream( QByteArray, int mode ); + virtual ~QDataStream(); + + QIODevice *device() const; + void setDevice( QIODevice * ); + void unsetDevice(); + + bool atEnd() const; + bool eof() const; + + enum ByteOrder { BigEndian, LittleEndian }; + int byteOrder() const; + void setByteOrder( int ); + + bool isPrintableData() const; + void setPrintableData( bool ); + + int version() const; + void setVersion( int ); + + QDataStream &operator>>( Q_INT8 &i ); + QDataStream &operator>>( Q_UINT8 &i ); + QDataStream &operator>>( Q_INT16 &i ); + QDataStream &operator>>( Q_UINT16 &i ); + QDataStream &operator>>( Q_INT32 &i ); + QDataStream &operator>>( Q_UINT32 &i ); + QDataStream &operator>>( Q_INT64 &i ); + QDataStream &operator>>( Q_UINT64 &i ); + + QDataStream &operator>>( float &f ); + QDataStream &operator>>( double &f ); + QDataStream &operator>>( char *&str ); + + QDataStream &operator<<( Q_INT8 i ); + QDataStream &operator<<( Q_UINT8 i ); + QDataStream &operator<<( Q_INT16 i ); + QDataStream &operator<<( Q_UINT16 i ); + QDataStream &operator<<( Q_INT32 i ); + QDataStream &operator<<( Q_UINT32 i ); + QDataStream &operator<<( Q_INT64 i ); + QDataStream &operator<<( Q_UINT64 i ); + QDataStream &operator<<( float f ); + QDataStream &operator<<( double f ); + QDataStream &operator<<( const char *str ); + + QDataStream &readBytes( char *&, uint &len ); + QDataStream &readRawBytes( char *, uint len ); + + QDataStream &writeBytes( const char *, uint len ); + QDataStream &writeRawBytes( const char *, uint len ); + +private: + QIODevice *dev; + bool owndev; + int byteorder; + bool printable; + bool noswap; + int ver; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QDataStream( const QDataStream & ); + QDataStream &operator=( const QDataStream & ); +#endif +}; + + +/***************************************************************************** + QDataStream inline functions + *****************************************************************************/ + +inline QIODevice *QDataStream::device() const +{ return dev; } + +inline bool QDataStream::atEnd() const +{ return dev ? dev->atEnd() : TRUE; } + +inline bool QDataStream::eof() const +{ return atEnd(); } + +inline int QDataStream::byteOrder() const +{ return byteorder; } + +inline bool QDataStream::isPrintableData() const +{ return printable; } + +inline void QDataStream::setPrintableData( bool p ) +{ printable = p; } + +inline int QDataStream::version() const +{ return ver; } + +inline void QDataStream::setVersion( int v ) +{ ver = v; } + +inline QDataStream &QDataStream::operator>>( Q_UINT8 &i ) +{ return *this >> (Q_INT8&)i; } + +inline QDataStream &QDataStream::operator>>( Q_UINT16 &i ) +{ return *this >> (Q_INT16&)i; } + +inline QDataStream &QDataStream::operator>>( Q_UINT32 &i ) +{ return *this >> (Q_INT32&)i; } + +inline QDataStream &QDataStream::operator>>( Q_UINT64 &i ) +{ return *this >> (Q_INT64&)i; } + +inline QDataStream &QDataStream::operator<<( Q_UINT8 i ) +{ return *this << (Q_INT8)i; } + +inline QDataStream &QDataStream::operator<<( Q_UINT16 i ) +{ return *this << (Q_INT16)i; } + +inline QDataStream &QDataStream::operator<<( Q_UINT32 i ) +{ return *this << (Q_INT32)i; } + +inline QDataStream &QDataStream::operator<<( Q_UINT64 i ) +{ return *this << (Q_INT64)i; } + + +#endif // QT_NO_DATASTREAM +#endif // QDATASTREAM_H diff --git a/trunk/qtools/qdatetime.cpp b/trunk/qtools/qdatetime.cpp new file mode 100644 index 0000000..cecb855 --- /dev/null +++ b/trunk/qtools/qdatetime.cpp @@ -0,0 +1,1434 @@ +/**************************************************************************** +** +** +** Implementation of date and time classes +** +** Created : 940124 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#define gettimeofday __hide_gettimeofday +#include "qdatetime.h" +#include "qdatastream.h" +#include <stdio.h> +#include <time.h> +#if defined(_OS_WIN32_) +#if defined(_CC_BOOL_DEF_) +#undef bool +#include <windows.h> +#define bool int +#else +#include <windows.h> +#endif +#elif defined(_OS_MSDOS_) +#include <dos.h> +#elif defined(_OS_OS2_) +#include <os2.h> +#elif defined(_OS_UNIX_) +#include <sys/time.h> +#include <unistd.h> +#undef gettimeofday +extern "C" int gettimeofday( struct timeval *, struct timezone * ); +#endif + +static const uint FIRST_DAY = 2361222; // Julian day for 1752/09/14 +static const int FIRST_YEAR = 1752; // ### wrong for many countries +static const uint SECS_PER_DAY = 86400; +static const uint MSECS_PER_DAY = 86400000; +static const uint SECS_PER_HOUR = 3600; +static const uint MSECS_PER_HOUR= 3600000; +static const uint SECS_PER_MIN = 60; +static const uint MSECS_PER_MIN = 60000; + +static const short monthDays[] ={0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +// ##### Localize. + +const char * const QDate::monthNames[] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +const char * const QDate::weekdayNames[] ={ + "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; + + +/***************************************************************************** + QDate member functions + *****************************************************************************/ + +// REVISED: aavit + +/*! + \class QDate qdatetime.h + \brief The QDate class provides date functions. + + \ingroup time + + A QDate object contains a calendar date, i.e. year, month, and day + numbers in the modern western (Gregorian) calendar. It can read the + current date from the system clock. It provides functions for + comparing dates and for manipulating a date by adding a number of + days. + + A QDate object is typically created either by giving the year, month + and day numbers explicitly, or by using the static function + currentDate(), which makes a QDate object which contains the + system's clock date. An explicit date can also be set using + setYMD(). + + The year(), month(), and day() functions provide access to the year, + month, and day numbers. Also, dayOfWeek() and dayOfYear() functions + are provided. The same information is provided in textual format by + the toString(), dayName(), and monthName() functions. + + QDate provides a full set of operators to compare two QDate + objects. A date is considered smaller than another if it is earlier + than the other. + + The date a given number of days later than a given date can be found + using the addDays() function. Correspondingly, the number of days + between two dates can be found using the daysTo() function. + + The daysInMonth() and daysInYear() functions tell how many days + there are in this date's month and year, respectively. The + isLeapYear() function tells whether this date is in a leap year. + + Note that QDate may not be used for date calculations for dates in + the remote past, i.e. prior to the introduction of the Gregorian + calendar. This calendar was adopted by England Sep. 14. 1752 (hence + this is the earliest valid QDate), and subsequently by most other + western countries, until 1923. + + The end of time is reached around 8000AD, by which time we expect Qt + to be obsolete. + + \sa QTime, QDateTime +*/ + + +/*! + \fn QDate::QDate() + Constructs a null date. Null dates are invalid. + + \sa isNull(), isValid() +*/ + + +/*! + Constructs a date with the year \a y, month \a m and day \a d. + + \a y must be in the range 1752-ca. 8000, \a m must be in the range + 1-12, and \a d must be in the range 1-31. Exception: if \a y is in + the range 0-99, it is interpreted as 1900-1999. + + \sa isValid() +*/ + +QDate::QDate( int y, int m, int d ) +{ + jd = 0; + setYMD( y, m, d ); +} + + +/*! + \fn bool QDate::isNull() const + + Returns TRUE if the date is null. A null date is invalid. + + \sa isValid() +*/ + + +/*! + Returns TRUE if this date is valid. + + \sa isNull() +*/ + +bool QDate::isValid() const +{ + return jd >= FIRST_DAY; +} + + +/*! + Returns the year (>= 1752) of this date. + + \sa month(), day() +*/ + +int QDate::year() const +{ + int y, m, d; + jul2greg( jd, y, m, d ); + return y; +} + +/*! + Returns the month (January=1 .. December=12) of this date. + + \sa year(), day() +*/ + +int QDate::month() const +{ + int y, m, d; + jul2greg( jd, y, m, d ); + return m; +} + +/*! + Returns the day of the month (1..31) of this date. + + \sa year(), month(), dayOfWeek() +*/ + +int QDate::day() const +{ + int y, m, d; + jul2greg( jd, y, m, d ); + return d; +} + +/*! + Returns the weekday (Monday=1 .. Sunday=7) for this date. + + \sa day(), dayOfYear() +*/ + +int QDate::dayOfWeek() const +{ + return (((jd+1) % 7) + 6)%7 + 1; +} + +/*! + Returns the day of the year (1..365) for this date. + + \sa day(), dayOfWeek() +*/ + +int QDate::dayOfYear() const +{ + return jd - greg2jul(year(), 1, 1) + 1; +} + +/*! + Returns the number of days in the month (28..31) for this date. + + \sa day(), daysInYear() +*/ + +int QDate::daysInMonth() const +{ + int y, m, d; + jul2greg( jd, y, m, d ); + if ( m == 2 && leapYear(y) ) + return 29; + else + return monthDays[m]; +} + +/*! + Returns the number of days in the year (365 or 366) for this date. + + \sa day(), daysInMonth() +*/ + +int QDate::daysInYear() const +{ + int y, m, d; + jul2greg( jd, y, m, d ); + return leapYear(y) ? 366 : 365; +} + + +/*! + Returns the name of the \a month. + + Month 1 == "Jan", month 2 == "Feb" etc. + + \sa toString(), dayName() +*/ + +QString QDate::monthName( int month ) const +{ +#if defined(CHECK_RANGE) + if ( month < 1 || month > 12 ) { + qWarning( "QDate::monthName: Parameter out ouf range." ); + month = 1; + } +#endif + // ### Remove the fromLatin1 during localization + return QString::fromLatin1(monthNames[month-1]); +} + +/*! + Returns the name of the \a weekday. + + Weekday 1 == "Mon", day 2 == "Tue" etc. + + \sa toString(), monthName() +*/ + +QString QDate::dayName( int weekday ) const +{ +#if defined(CHECK_RANGE) + if ( weekday < 1 || weekday > 7 ) { + qWarning( "QDate::dayName: Parameter out of range." ); + weekday = 1; + } +#endif + // ### Remove the fromLatin1 during localization + return QString::fromLatin1(weekdayNames[weekday-1]); +} + + +/*! + Returns the date as a string. + + The string format is "Sat May 20 1995". This function uses the + dayName() and monthName() functions to generate the string. + + \sa dayName(), monthName() +*/ + +QString QDate::toString() const +{ + int y, m, d; + jul2greg( jd, y, m, d ); + QString buf = dayName(dayOfWeek()); + buf += ' '; + buf += monthName(m); + QString t; + t.sprintf( " %d %d", d, y); + buf += t; + return buf; +} + + +/*! + Sets the year \a y, month \a m and day \a d. + + \a y must be in the range 1752-ca. 8000, \a m must be in the range + 1-12, and \a d must be in the range 1-31. Exception: if \a y is in + the range 0-99, it is interpreted as 1900-1999. + + Returns TRUE if the date is valid, otherwise FALSE. +*/ + +bool QDate::setYMD( int y, int m, int d ) +{ + if ( !isValid(y,m,d) ) { +#if defined(CHECK_RANGE) + qWarning( "QDate::setYMD: Invalid date %04d/%02d/%02d", y, m, d ); +#endif + return FALSE; + } + jd = greg2jul( y, m, d ); +#if defined(DEBUG) + ASSERT( year() == (y > 99 ? y : 1900+y) && month() == m && day() == d ); +#endif + return TRUE; +} + +/*! + Returns a QDate object containing a date \a ndays later than the + date of this object (or earlier if \a ndays is negative). + + \sa daysTo() +*/ + +QDate QDate::addDays( int ndays ) const +{ + QDate d; + d.jd = jd + ndays; + return d; +} + +/*! + Returns the number of days from this date to \a d (which is negative + if \a d is earlier than this date). + + Example: + \code + QDate d1( 1995, 5, 17 ); // May 17th 1995 + QDate d2( 1995, 5, 20 ); // May 20th 1995 + d1.daysTo( d2 ); // returns 3 + d2.daysTo( d1 ); // returns -3 + \endcode + + \sa addDays() +*/ + +int QDate::daysTo( const QDate &d ) const +{ + return d.jd - jd; +} + + +/*! + \fn bool QDate::operator==( const QDate &d ) const + Returns TRUE if this date is equal to \a d, or FALSE if + they are different. +*/ + +/*! + \fn bool QDate::operator!=( const QDate &d ) const + Returns TRUE if this date is different from \a d, or FALSE if + they are equal. +*/ + +/*! + \fn bool QDate::operator<( const QDate &d ) const + Returns TRUE if this date is earlier than \a d, otherwise FALSE. +*/ + +/*! + \fn bool QDate::operator<=( const QDate &d ) const + Returns TRUE if this date is earlier than or equal to \a d, otherwise FALSE. +*/ + +/*! + \fn bool QDate::operator>( const QDate &d ) const + Returns TRUE if this date is later than \a d, otherwise FALSE. +*/ + +/*! + \fn bool QDate::operator>=( const QDate &d ) const + Returns TRUE if this date is later than or equal to \a d, otherwise FALSE. +*/ + + +/*! + Returns the current date, as reported by the system clock. + + \sa QTime::currentTime(), QDateTime::currentDateTime() +*/ + +QDate QDate::currentDate() +{ +#if defined(_OS_WIN32_) + + SYSTEMTIME t; + GetLocalTime( &t ); + QDate d; + d.jd = greg2jul( t.wYear, t.wMonth, t.wDay ); + return d; + +#else + + time_t ltime; + time( <ime ); + tm *t = localtime( <ime ); + QDate d; + d.jd = greg2jul( t->tm_year + 1900, t->tm_mon + 1, t->tm_mday ); + return d; + +#endif +} + +/*! + Returns TRUE if the specified date (year \a y, month \a m and day \a + d) is valid. + + Example: + \code + QDate::isValid( 2002, 5, 17 ); // TRUE; May 17th 2002 is OK. + QDate::isValid( 2002, 2, 30 ); // FALSE; Feb 30th does not exist + QDate::isValid( 2004, 2, 29 ); // TRUE; 2004 is a leap year + QDate::isValid( 1202, 6, 6 ); // FALSE; 1202 is pre-Gregorian + \endcode + + Note that a \a y value in the range 00-99 is interpreted as + 1900-1999. + + \sa isNull(), setYMD() +*/ + +bool QDate::isValid( int y, int m, int d ) +{ + if ( y >= 0 && y <= 99 ) + y += 1900; + else if ( y < FIRST_YEAR || (y == FIRST_YEAR && (m < 9 || + (m == 9 && d < 14))) ) + return FALSE; + return (d > 0 && m > 0 && m <= 12) && + (d <= monthDays[m] || (d == 29 && m == 2 && leapYear(y))); +} + +/*! + Returns TRUE if the specified year \a y is a leap year. +*/ + +bool QDate::leapYear( int y ) +{ + return y % 4 == 0 && y % 100 != 0 || y % 400 == 0; +} + +/*! + \internal + Converts a Gregorian date to a Julian day. + This algorithm is taken from Communications of the ACM, Vol 6, No 8. + \sa jul2greg() +*/ + +uint QDate::greg2jul( int y, int m, int d ) +{ + uint c, ya; + if ( y <= 99 ) + y += 1900; + if ( m > 2 ) { + m -= 3; + } else { + m += 9; + y--; + } + c = y; // NOTE: Sym C++ 6.0 bug + c /= 100; + ya = y - 100*c; + return 1721119 + d + (146097*c)/4 + (1461*ya)/4 + (153*m+2)/5; +} + +/*! + \internal + Converts a Julian day to a Gregorian date. + This algorithm is taken from Communications of the ACM, Vol 6, No 8. + \sa greg2jul() +*/ + +void QDate::jul2greg( uint jd, int &y, int &m, int &d ) +{ + uint x; + uint j = jd - 1721119; + y = (j*4 - 1)/146097; + j = j*4 - 146097*y - 1; + x = j/4; + j = (x*4 + 3) / 1461; + y = 100*y + j; + x = (x*4) + 3 - 1461*j; + x = (x + 4)/4; + m = (5*x - 3)/153; + x = 5*x - 3 - 153*m; + d = (x + 5)/5; + if ( m < 10 ) { + m += 3; + } else { + m -= 9; + y++; + } +} + + +/***************************************************************************** + QTime member functions + *****************************************************************************/ + +/*! + \class QTime qdatetime.h + + \brief The QTime class provides clock time functions. + + \ingroup time + + A QTime object contains a clock time, i.e. a number of hours, + minutes, seconds and milliseconds since midnight. It can read the + current time from the system clock, and measure a span of elapsed + time. It provides functions for comparing times and for manipulating + a time by adding a number of (milli)seconds. + + QTime operates with 24-hour clock format; it has no concept of + AM/PM. It operates with local time; it does not know anything about + time zones or daylight savings time. + + A QTime object is typically created either by giving the number of + hours, minutes, seconds, and milliseconds explicitly, or by using + the static function currentTime(), which makes a QTime object which + contains the system's clock time. Note that the accuracy depends on + the accuracy of the underlying operating system; not all systems + provide 1-millisecond accuracy. + + The hour(), minute(), second(), and msec() functions provide access + to the number of hours, minutes, seconds, and milliseconds of the + time. The same information is provided in textual format by the + toString() function. + + QTime provides a full set of operators to compare two QTime + objects. A time is considered smaller than another if it is earlier + than the other. + + The time a given number of seconds or milliseconds later than a + given time can be found using the addSecs() or addMSecs() + functions. Correspondingly, the number of (milli)seconds between two + times can be found using the secsTo() or msecsTo() functions. + + QTime can be used to measure a span of elapsed time using the + start(), restart(), and elapsed() functions. + + \sa QDate, QDateTime +*/ + +/*! + \fn QTime::QTime() + + Constructs the time 0 hours, minutes, seconds and milliseconds, + i.e. 00:00:00.000 (midnight). This is a valid time. + + \sa isValid() +*/ + +/*! + Constructs a time with hour \a h, minute \a m, seconds \a s and + milliseconds \a ms. + + \a h must be in the range 0-23, \a m and \a s must be in the range + 0-59, and \a ms must be in the range 0-999. + + \sa isValid() +*/ + +QTime::QTime( int h, int m, int s, int ms ) +{ + setHMS( h, m, s, ms ); +} + + +/*! + \fn bool QTime::isNull() const + Returns TRUE if the time is equal to 00:00:00.000. A null time is valid. + + \sa isValid() +*/ + +/*! + Returns TRUE if the time is valid, or FALSE if the time is invalid. + The time 23:30:55.746 is valid, while 24:12:30 is invalid. + + \sa isNull() +*/ + +bool QTime::isValid() const +{ + return ds < MSECS_PER_DAY; +} + + +/*! + Returns the hour part (0..23) of the time. +*/ + +int QTime::hour() const +{ + return ds / MSECS_PER_HOUR; +} + +/*! + Returns the minute part (0..59) of the time. +*/ + +int QTime::minute() const +{ + return (ds % MSECS_PER_HOUR)/MSECS_PER_MIN; +} + +/*! + Returns the second part (0..59) of the time. +*/ + +int QTime::second() const +{ + return (ds / 1000)%SECS_PER_MIN; +} + +/*! + Returns the millisecond part (0..999) of the time. +*/ + +int QTime::msec() const +{ + return ds % 1000; +} + + +/*! + Returns the time of this object in a textual format. Milliseconds + are not included. The string format is HH:MM:SS, e.g. 1 second + before midnight would be "23:59:59". +*/ + +QString QTime::toString() const +{ + QString buf; + buf.sprintf( "%.2d:%.2d:%.2d", hour(), minute(), second() ); + return buf; +} + + +/*! + Sets the time to hour \a h, minute \a m, seconds \a s and + milliseconds \a ms. + + \a h must be in the range 0-23, \a m and \a s must be in the range + 0-59, and \a ms must be in the range 0-999. Returns TRUE if the set + time is valid, otherwise FALSE. + + \sa isValid() +*/ + +bool QTime::setHMS( int h, int m, int s, int ms ) +{ + if ( !isValid(h,m,s,ms) ) { +#if defined(CHECK_RANGE) + qWarning( "QTime::setHMS Invalid time %02d:%02d:%02d.%03d", h, m, s, + ms ); +#endif + ds = MSECS_PER_DAY; // make this invalid + return FALSE; + } + ds = (h*SECS_PER_HOUR + m*SECS_PER_MIN + s)*1000 + ms; + return TRUE; +} + +/*! + Returns a QTime object containing a time \a nsecs seconds later than + the time of this object (or earlier if \a ms is negative). + + Note that the time will wrap if it passes midnight. + + Example: + \code + QTime n( 14, 0, 0 ); // n == 14:00:00 + QTime t; + t = n.addSecs( 70 ); // t == 14:01:10 + t = n.addSecs( -70 ); // t == 13:58:50 + t = n.addSecs( 10*60*60 + 5 ); // t == 00:00:05 + t = n.addSecs( -15*60*60 ); // t == 23:00:00 + \endcode + + \sa addMSecs(), secsTo(), QDateTime::addSecs() +*/ + +QTime QTime::addSecs( int nsecs ) const +{ + return addMSecs(nsecs*1000); +} + +/*! + Returns the number of seconds from this time to \a t (which is + negative if \a t is earlier than this time). + + Since QTime measures time within a day and there are 86400 seconds + in a day, the result is between -86400 and 86400. + + \sa addSecs() QDateTime::secsTo() +*/ + +int QTime::secsTo( const QTime &t ) const +{ + return ((int)t.ds - (int)ds)/1000; +} + +/*! + Returns a QTime object containing a time \a ms milliseconds later than + the time of this object (or earlier if \a ms is negative). + + Note that the time will wrap if it passes midnight. See addSecs() + for an example. + + \sa addSecs(), msecsTo() +*/ + +QTime QTime::addMSecs( int ms ) const +{ + QTime t; + if ( ms < 0 ) { + // % not well-defined for -ve, but / is. + int negdays = (MSECS_PER_DAY-ms) / MSECS_PER_DAY; + t.ds = ((int)ds + ms + negdays*MSECS_PER_DAY) + % MSECS_PER_DAY; + } else { + t.ds = ((int)ds + ms) % MSECS_PER_DAY; + } + return t; +} + +/*! + Returns the number of milliseconds from this time to \a t (which is + negative if \a t is earlier than this time). + + Since QTime measures time within a day and there are 86400000 + milliseconds in a day, the result is between -86400000 and 86400000. + + \sa secsTo() +*/ + +int QTime::msecsTo( const QTime &t ) const +{ + return (int)t.ds - (int)ds; +} + + +/*! + \fn bool QTime::operator==( const QTime &t ) const + + Returns TRUE if this time is equal to \a t, or FALSE if they are + different. +*/ + +/*! + \fn bool QTime::operator!=( const QTime &t ) const + + Returns TRUE if this time is different from \a t, or FALSE if they + are equal. +*/ + +/*! + \fn bool QTime::operator<( const QTime &t ) const + + Returns TRUE if this time is earlier than \a t, otherwise FALSE. +*/ + +/*! + \fn bool QTime::operator<=( const QTime &t ) const + + Returns TRUE if this time is earlier than or equal to \a t, + otherwise FALSE. +*/ + +/*! + \fn bool QTime::operator>( const QTime &t ) const + + Returns TRUE if this time is later than \a t, otherwise FALSE. +*/ + +/*! + \fn bool QTime::operator>=( const QTime &t ) const + + Returns TRUE if this time is later than or equal to \a t, otherwise + FALSE. +*/ + + + +/*! + Returns the current time, as reported by the system clock. + + Note that the accuracy depends on the accuracy of the underlying + operating system; not all systems provide 1-millisecond accuracy. +*/ + +QTime QTime::currentTime() +{ + QTime ct; + currentTime( &ct ); + return ct; +} + +/*! + \internal + + Fetches the current time and returns TRUE if the time is within one + minute after midnight, otherwise FALSE. The return value is used by + QDateTime::currentDateTime() to ensure that the date there is correct. +*/ + +bool QTime::currentTime( QTime *ct ) +{ + if ( !ct ) { +#if defined(CHECK_NULL) + qWarning( "QTime::currentTime(QTime *): Null pointer not allowed" ); +#endif + return FALSE; + } + +#if defined(_OS_WIN32_) + + SYSTEMTIME t; + GetLocalTime( &t ); + ct->ds = MSECS_PER_HOUR*t.wHour + MSECS_PER_MIN*t.wMinute + + 1000*t.wSecond + t.wMilliseconds; + return (t.wHour == 0 && t.wMinute == 0); + +#elif defined(_OS_OS2_) + + DATETIME t; + DosGetDateTime( &t ); + ct->ds = MSECS_PER_HOUR*t.hours + MSECS_PER_MIN*t.minutes + + 1000*t.seconds + 10*t.hundredths; + return (t.hours == 0 && t.minutes == 0); + +#elif defined(_OS_MSDOS_) + + _dostime_t t; + _dos_gettime( &t ); + ct->ds = MSECS_PER_HOUR*t.hour + MSECS_PER_MIN*t.minute + + t.second*1000 + t.hsecond*10; + return (t.hour== 0 && t.minute == 0); + +#elif defined(_OS_UNIX_) + + struct timeval tv; + gettimeofday( &tv, 0 ); + time_t ltime = tv.tv_sec; + tm *t = localtime( <ime ); + ct->ds = (uint)( MSECS_PER_HOUR*t->tm_hour + MSECS_PER_MIN*t->tm_min + + 1000*t->tm_sec + tv.tv_usec/1000 ); + return (t->tm_hour== 0 && t->tm_min == 0); + +#else + + time_t ltime; // no millisecond resolution!! + ::time( <ime ); + tm *t = localtime( <ime ); + ct->ds = MSECS_PER_HOUR*t->tm_hour + MSECS_PER_MIN*t->tm_min + + 1000*t->tm_sec; + return (t->tm_hour== 0 && t->tm_min == 0); +#endif +} + +/*! + Returns TRUE if the specified time is valid, otherwise FALSE. + + The time is valid if \a h is in the range 0-23, \a m and \a s are in + the range 0-59, and \a ms is in the range 0-999. + + Example: + \code + QTime::isValid(21, 10, 30); // returns TRUE + QTime::isValid(22, 5, 62); // returns FALSE + \endcode +*/ + +bool QTime::isValid( int h, int m, int s, int ms ) +{ + return (uint)h < 24 && (uint)m < 60 && (uint)s < 60 && (uint)ms < 1000; +} + + +/*! + Sets this time to the current time. This is practical for timing: + + \code + QTime t; + t.start(); // start clock + ... // some lengthy task + qDebug( "%d\n", t.elapsed() ); // prints # msecs elapsed + \endcode + + \sa restart(), elapsed(), currentTime() +*/ + +void QTime::start() +{ + *this = currentTime(); +} + +/*! + Sets this time to the current time, and returns the number of + milliseconds that have elapsed since the last time start() or + restart() was called. + + This function is guaranteed to be atomic, and is thus very handy for + repeated measurements: call start() to start the first measurement, + then restart() for each later measurement. + + Note that the counter wraps to zero 24 hours after the last call to + start() or restart(). + + \warning If the system's clock setting has been changed since the + last time start() or restart() was called, the result is undefined. + This can happen e.g. when daylight saving is turned on or off. + + \sa start(), elapsed(), currentTime() +*/ + +int QTime::restart() +{ + QTime t = currentTime(); + int n = msecsTo( t ); + if ( n < 0 ) // passed midnight + n += 86400*1000; + *this = t; + return n; +} + +/*! + Returns the number of milliseconds that have elapsed since the last + time start() or restart() was called. + + Note that the counter wraps to zero 24 hours after the last call to + start() or restart. + + Note that the accuracy depends on the accuracy of the underlying + operating system; not all systems provide 1-millisecond accuracy. + + \warning If the system's clock setting has been changed since the + last time start() or restart() was called, the result is undefined. + This can happen e.g. when daylight saving is turned on or off. + + \sa start(), restart() +*/ + +int QTime::elapsed() +{ + int n = msecsTo( currentTime() ); + if ( n < 0 ) // passed midnight + n += 86400*1000; + return n; +} + + +/***************************************************************************** + QDateTime member functions + *****************************************************************************/ + +/*! + \class QDateTime qdatetime.h + \brief The QDateTime class provides date and time functions. + + \ingroup time + + A QDateTime object contains a calendar date and a clock time (a + "datetime"). It is a combination of the QDate and QTime classes. It + can read the current datetime from the system clock. It provides + functions for comparing datetimes and for manipulating a datetime by + adding a number of seconds or days. + + A QDateTime object is typically created either by giving a date and + time explicitly, or by using the static function currentTime(), + which makes a QDateTime object which contains the system's clock + time. + + The date() and time() functions provide access to the date and time + parts of the datetime. The same information is provided in textual + format by the toString() function. + + QDateTime provides a full set of operators to compare two QDateTime + objects. A datetime is considered smaller than another if it is + earlier than the other. + + The datetime a given number of days or seconds later than a given + datetime can be found using the addDays() and addSecs() + functions. Correspondingly, the number of days or seconds between + two times can be found using the daysTo() or secsTo() functions. + + A datetime can also be set using the setTime_t() function, which + takes a POSIX-standard "number of seconds since 00:00:00 on January + 1, 1970" value. + + The limitations regarding range and resolution mentioned in the + QDate and QTime documentation apply for QDateTime also. + + \sa QDate, QTime +*/ + + +/*! + \fn QDateTime::QDateTime() + + Constructs a null datetime (i.e. null date and null time). A null + datetime is invalid, since the date is invalid. + + \sa isValid() +*/ + + +/*! + Constructs a datetime with date \a date and null time (00:00:00.000). +*/ + +QDateTime::QDateTime( const QDate &date ) + : d(date) +{ +} + +/*! + Constructs a datetime with date \a date and time \a time. +*/ + +QDateTime::QDateTime( const QDate &date, const QTime &time ) + : d(date), t(time) +{ +} + + +/*! + \fn bool QDateTime::isNull() const + + Returns TRUE if both the date and the time are null. A null date is invalid. + + \sa QDate::isNull(), QTime::isNull() +*/ + +/*! + \fn bool QDateTime::isValid() const + + Returns TRUE if both the date and the time are valid. + + \sa QDate::isValid(), QTime::isValid() +*/ + +/*! + \fn QDate QDateTime::date() const + + Returns the date part of this datetime. + + \sa setDate(), time() +*/ + +/*! + \fn QTime QDateTime::time() const + + Returns the time part of this datetime. + + \sa setTime(), date() +*/ + +/*! + \fn void QDateTime::setDate( const QDate &date ) + + Sets the date part of this datetime. + + \sa date(), setTime() +*/ + +/*! + \fn void QDateTime::setTime( const QTime &time ) + + Sets the time part of this datetime. + + \sa time(), setDate() +*/ + + +/*! + Sets the local date and time given the number of seconds that have passed + since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC). + On systems that do not support timezones this function will behave as if + local time were UTC. + + Note that Microsoft Windows supports only a limited range of values for + \a secsSince1Jan1970UTC. +*/ + +void QDateTime::setTime_t( uint secsSince1Jan1970UTC ) +{ + time_t tmp = (time_t) secsSince1Jan1970UTC; + tm *tM = localtime( &tmp ); + if ( !tM ) { + tM = gmtime( &tmp ); + if ( !tM ) { + d.jd = QDate::greg2jul( 1970, 1, 1 ); + t.ds = 0; + return; + } + } + d.jd = QDate::greg2jul( tM->tm_year + 1900, tM->tm_mon + 1, tM->tm_mday ); + t.ds = MSECS_PER_HOUR*tM->tm_hour + MSECS_PER_MIN*tM->tm_min + + 1000*tM->tm_sec; +} + + +/*! + Returns the datetime as a string. + + The string format is "Sat May 20 03:40:13 1998". + + This function uses QDate::dayName(), QDate::monthName(), and + QTime::toString() to generate the string. + +*/ + +QString QDateTime::toString() const +{ + QString buf = d.dayName(d.dayOfWeek()); + buf += ' '; + buf += d.monthName(d.month()); + buf += ' '; + buf += QString().setNum(d.day()); + buf += ' '; + buf += t.toString(); + buf += ' '; + buf += QString().setNum(d.year()); + return buf; +} + +/*! + Returns a QDateTime object containing a datetime \a ndays days later + than the datetime of this object (or earlier if \a ndays is + negative). + + \sa daysTo(), addSecs() +*/ + +QDateTime QDateTime::addDays( int ndays ) const +{ + return QDateTime( d.addDays(ndays), t ); +} + +/*! + Returns a QDateTime object containing a datetime \a nsecs seconds + later than the datetime of this object (or earlier if \a nsecs is + negative). + + \sa secsTo(), addDays() +*/ + +QDateTime QDateTime::addSecs( int nsecs ) const +{ + uint dd = d.jd; + int tt = t.ds; + int sign = 1; + if ( nsecs < 0 ) { + nsecs = -nsecs; + sign = -1; + } + if ( nsecs >= (int)SECS_PER_DAY ) { + dd += sign*(nsecs/SECS_PER_DAY); + nsecs %= SECS_PER_DAY; + } + tt += sign*nsecs*1000; + if ( tt < 0 ) { + tt = MSECS_PER_DAY - tt - 1; + dd -= tt / MSECS_PER_DAY; + tt = tt % MSECS_PER_DAY; + tt = MSECS_PER_DAY - tt - 1; + } else if ( tt >= (int)MSECS_PER_DAY ) { + dd += ( tt / MSECS_PER_DAY ); + tt = tt % MSECS_PER_DAY; + } + QDateTime ret; + ret.t.ds = tt; + ret.d.jd = dd; + return ret; +} + +/*! + Returns the number of days from this datetime to \a dt (which is + negative if \a dt is earlier than this datetime). + + \sa addDays(), secsTo() +*/ + +int QDateTime::daysTo( const QDateTime &dt ) const +{ + return d.daysTo( dt.d ); +} + +/*! + Returns the number of seconds from this datetime to \a dt (which is + negative if \a dt is earlier than this datetime). + + Example: + \code + QDateTime dt = QDateTime::currentDateTime(); + QDateTime x( QDate(dt.year(),12,24), QTime(17,00) ); + qDebug( "There are %d seconds to Christmas", dt.secsTo(x) ); + \endcode + + \sa addSecs(), daysTo(), QTime::secsTo() +*/ + +int QDateTime::secsTo( const QDateTime &dt ) const +{ + return t.secsTo(dt.t) + d.daysTo(dt.d)*SECS_PER_DAY; +} + + +/*! + Returns TRUE if this datetime is equal to \a dt, or FALSE if + they are different. + \sa operator!=() +*/ + +bool QDateTime::operator==( const QDateTime &dt ) const +{ + return t == dt.t && d == dt.d; +} + +/*! + Returns TRUE if this datetime is different from \a dt, or FALSE if + they are equal. + \sa operator==() +*/ + +bool QDateTime::operator!=( const QDateTime &dt ) const +{ + return t != dt.t || d != dt.d; +} + +/*! + Returns TRUE if this datetime is earlier than \a dt, otherwise FALSE. +*/ + +bool QDateTime::operator<( const QDateTime &dt ) const +{ + if ( d < dt.d ) + return TRUE; + return d == dt.d ? t < dt.t : FALSE; +} + +/*! + Returns TRUE if this datetime is earlier than or equal to \a dt, + otherwise FALSE. +*/ + +bool QDateTime::operator<=( const QDateTime &dt ) const +{ + if ( d < dt.d ) + return TRUE; + return d == dt.d ? t <= dt.t : FALSE; +} + +/*! + Returns TRUE if this datetime is later than \a dt, otherwise FALSE. +*/ + +bool QDateTime::operator>( const QDateTime &dt ) const +{ + if ( d > dt.d ) + return TRUE; + return d == dt.d ? t > dt.t : FALSE; +} + +/*! + Returns TRUE if this datetime is later than or equal to \a dt, + otherwise FALSE. +*/ + +bool QDateTime::operator>=( const QDateTime &dt ) const +{ + if ( d > dt.d ) + return TRUE; + return d == dt.d ? t >= dt.t : FALSE; +} + +/*! + Returns the current datetime, as reported by the system clock. + + \sa QDate::currentDate(), QTime::currentTime() +*/ + +QDateTime QDateTime::currentDateTime() +{ + QDate cd = QDate::currentDate(); + QTime ct; + if ( QTime::currentTime(&ct) ) // too close to midnight? + cd = QDate::currentDate(); // YES! time for some midnight + // voodoo, fetch date again + return QDateTime( cd, ct ); +} + + +/***************************************************************************** + Date/time stream functions + *****************************************************************************/ + +#ifndef QT_NO_DATASTREAM +/*! + \relates QDate + Writes the date to the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator<<( QDataStream &s, const QDate &d ) +{ + return s << (Q_UINT32)(d.jd); +} + +/*! + \relates QDate + Reads a date from the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator>>( QDataStream &s, QDate &d ) +{ + Q_UINT32 jd; + s >> jd; + d.jd = jd; + return s; +} + +/*! + \relates QTime + Writes a time to the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator<<( QDataStream &s, const QTime &t ) +{ + return s << (Q_UINT32)(t.ds); +} + +/*! + \relates QTime + Reads a time from the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator>>( QDataStream &s, QTime &t ) +{ + Q_UINT32 ds; + s >> ds; + t.ds = ds; + return s; +} + +/*! + \relates QDateTime + Writes a datetime to the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator<<( QDataStream &s, const QDateTime &dt ) +{ + return s << dt.d << dt.t; +} + +/*! + \relates QDateTime + Reads a datetime from the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator>>( QDataStream &s, QDateTime &dt ) +{ + s >> dt.d >> dt.t; + return s; +} +#endif //QT_NO_DATASTREAM diff --git a/trunk/qtools/qdatetime.h b/trunk/qtools/qdatetime.h new file mode 100644 index 0000000..2d5869c --- /dev/null +++ b/trunk/qtools/qdatetime.h @@ -0,0 +1,216 @@ +/**************************************************************************** +** +** +** Definition of date and time classes +** +** Created : 940124 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QDATETIME_H +#define QDATETIME_H + +#ifndef QT_H +#include "qstring.h" +#endif // QT_H + + +/***************************************************************************** + QDate class + *****************************************************************************/ + +class Q_EXPORT QDate +{ +public: + QDate() { jd=0; } // set null date + QDate( int y, int m, int d ); // set date + virtual ~QDate() {} + + bool isNull() const { return jd == 0; } + bool isValid() const; // valid date + + int year() const; // 1752.. + int month() const; // 1..12 + int day() const; // 1..31 + int dayOfWeek() const; // 1..7 (monday==1) + int dayOfYear() const; // 1..365 + int daysInMonth() const; // 28..31 + int daysInYear() const; // 365 or 366 + + virtual QString monthName( int month ) const; + virtual QString dayName( int weekday ) const; + + QString toString() const; + + bool setYMD( int y, int m, int d ); + + QDate addDays( int days ) const; + int daysTo( const QDate & ) const; + + bool operator==( const QDate &d ) const { return jd == d.jd; } + bool operator!=( const QDate &d ) const { return jd != d.jd; } + bool operator<( const QDate &d ) const { return jd < d.jd; } + bool operator<=( const QDate &d ) const { return jd <= d.jd; } + bool operator>( const QDate &d ) const { return jd > d.jd; } + bool operator>=( const QDate &d ) const { return jd >= d.jd; } + + static QDate currentDate(); + static bool isValid( int y, int m, int d ); + static bool leapYear( int year ); + +protected: + static uint greg2jul( int y, int m, int d ); + static void jul2greg( uint jd, int &y, int &m, int &d ); +private: + static const char * const monthNames[]; + static const char * const weekdayNames[]; + uint jd; + friend class QDateTime; +#ifndef QT_NO_DATASTREAM + friend Q_EXPORT QDataStream &operator<<( QDataStream &, const QDate & ); + friend Q_EXPORT QDataStream &operator>>( QDataStream &, QDate & ); +#endif +}; + + +/***************************************************************************** + QTime class + *****************************************************************************/ + +class Q_EXPORT QTime +{ +public: + QTime() { ds=0; } // set null time + QTime( int h, int m, int s=0, int ms=0 ); // set time + + bool isNull() const { return ds == 0; } + bool isValid() const; // valid time + + int hour() const; // 0..23 + int minute() const; // 0..59 + int second() const; // 0..59 + int msec() const; // 0..999 + + QString toString() const; + + bool setHMS( int h, int m, int s, int ms=0 ); + + QTime addSecs( int secs ) const; + int secsTo( const QTime & ) const; + QTime addMSecs( int ms ) const; + int msecsTo( const QTime & ) const; + + bool operator==( const QTime &d ) const { return ds == d.ds; } + bool operator!=( const QTime &d ) const { return ds != d.ds; } + bool operator<( const QTime &d ) const { return ds < d.ds; } + bool operator<=( const QTime &d ) const { return ds <= d.ds; } + bool operator>( const QTime &d ) const { return ds > d.ds; } + bool operator>=( const QTime &d ) const { return ds >= d.ds; } + + static QTime currentTime(); + static bool isValid( int h, int m, int s, int ms=0 ); + + void start(); + int restart(); + int elapsed(); + +private: + static bool currentTime( QTime * ); + + uint ds; + friend class QDateTime; +#ifndef QT_NO_DATASTREAM + friend Q_EXPORT QDataStream &operator<<( QDataStream &, const QTime & ); + friend Q_EXPORT QDataStream &operator>>( QDataStream &, QTime & ); +#endif +}; + + +/***************************************************************************** + QDateTime class + *****************************************************************************/ + +class Q_EXPORT QDateTime +{ +public: + QDateTime() {} // set null date and null time + QDateTime( const QDate & ); + QDateTime( const QDate &, const QTime & ); + + bool isNull() const { return d.isNull() && t.isNull(); } + bool isValid() const { return d.isValid() && t.isValid(); } + + QDate date() const { return d; } + QTime time() const { return t; } + void setDate( const QDate &date ) { d=date; } + void setTime( const QTime &time ) { t=time; } + void setTime_t( uint secsSince1Jan1970UTC ); + + QString toString() const; + + QDateTime addDays( int days ) const; + QDateTime addSecs( int secs ) const; + int daysTo( const QDateTime & ) const; + int secsTo( const QDateTime & ) const; + + bool operator==( const QDateTime &dt ) const; + bool operator!=( const QDateTime &dt ) const; + bool operator<( const QDateTime &dt ) const; + bool operator<=( const QDateTime &dt ) const; + bool operator>( const QDateTime &dt ) const; + bool operator>=( const QDateTime &dt ) const; + + static QDateTime currentDateTime(); + +private: + QDate d; + QTime t; +#ifndef QT_NO_DATASTREAM + friend Q_EXPORT QDataStream &operator<<( QDataStream &, const QDateTime &); + friend Q_EXPORT QDataStream &operator>>( QDataStream &, QDateTime & ); +#endif +}; + + +/***************************************************************************** + Date and time stream functions + *****************************************************************************/ + +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator<<( QDataStream &, const QDate & ); +Q_EXPORT QDataStream &operator>>( QDataStream &, QDate & ); +Q_EXPORT QDataStream &operator<<( QDataStream &, const QTime & ); +Q_EXPORT QDataStream &operator>>( QDataStream &, QTime & ); +Q_EXPORT QDataStream &operator<<( QDataStream &, const QDateTime & ); +Q_EXPORT QDataStream &operator>>( QDataStream &, QDateTime & ); +#endif // QT_NO_DATASTREAM + +#endif // QDATETIME_H diff --git a/trunk/qtools/qdict.doc b/trunk/qtools/qdict.doc new file mode 100644 index 0000000..d9f6ca5 --- /dev/null +++ b/trunk/qtools/qdict.doc @@ -0,0 +1,492 @@ +/**************************************************************************** +** +** +** QDict and QDictIterator class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QDict documentation + *****************************************************************************/ + +/*! + \class QDict qdict.h + \brief The QDict class is a template class that provides a dictionary based on \c QString keys. + + \ingroup collection + \ingroup tools + + QDict is implemented as a template class. Define a template instance + QDict\<X\> to create a dictionary that operates on pointers to X, or X*. + + A dictionary is a collection that associates an item with a key. + The key is used for inserting and looking up an item. QDict has + \l QString keys, which are Unicode strings. If you want to use + non-Unicode, plain 8-bit \c char* keys, use the QAsciiDict template. + A QDict has the same performace as a QAsciiDict. + + The dictionary has very fast insertion and lookup. + + Example: + \code + #include <qdict.h> + #include <stdio.h> + + void main() + { + // Creates a dictionary that maps QString ==> char* (case insensitive) + QDict<char> dict( 17, FALSE ); + + dict.insert( "France", "Paris" ); + dict.insert( "Russia", "Moscow" ); + dict.insert( "Norway", "Oslo" ); + + printf( "%s\n", dict["Norway"] ); + printf( "%s\n", dict["FRANCE"] ); + printf( "%s\n", dict["russia"] ); + + if ( !dict["Italy"] ) + printf( "Italy not defined\n" ); + } + \endcode + + Program output: + \code + Oslo + Paris + Moscow + Italy not defined + \endcode + + The dictionary in our example maps \c QString keys to \c char* items. + Note that the mapping is case insensitive (specified in the + \link QDict::QDict() constructor\endlink). + QDict implements the \link operator[] [] operator\endlink to lookup an item. + + QDict is implemented by QGDict as a hash array with a fixed number of + entries. Each array entry points to a singly linked list of buckets, in + which the dictionary items are stored. + + When an item is inserted with a key, the key is converted (hashed) to + an integer index into the hash array. The item is inserted before the + first bucket in the list of buckets. + + Looking up an item is normally very fast. The key is again hashed to an + array index. Then QDict scans the list of buckets and returns the item + found or null if the item was not found. You cannot insert null pointers + into a dictionary. + + The size of the hash array is very important. In order to get good + performance, you should use a suitably large \link primes.html prime + number\endlink. Suitable means equal to or larger than the maximum + expected number of dictionary items. + + Items with equal keys are allowed. When inserting two items with the + same key, only the last inserted item will be visible (last in, first out) + until it is removed. + + Example: + \code + #include <qdict.h> + #include <stdio.h> + + void main() + { + // Creates a dictionary that maps QString ==> char* (case sensitive) + QDict<char> dict; + + dict.insert( "Germany", "Berlin" ); + dict.insert( "Germany", "Bonn" ); + + printf( "%s\n", dict["Germany"] ); + dict.remove( "Germany" ); // Oct 3rd 1990 + printf( "%s\n", dict["Germany"] ); + } + \endcode + + Program output: + \code + Bonn + Berlin + \endcode + + The QDictIterator class can traverse the dictionary contents, but only + in an arbitrary order. Multiple iterators may independently traverse the + same dictionary. + + Calling setAutoDelete(TRUE) for a dictionary tells it to delete items + that are removed . The default is to not delete items when they are + removed. + + When inserting an item into a dictionary, only the pointer is copied, not + the item itself. This is called a shallow copy. It is possible to make the + dictionary copy all of the item's data (known as a deep copy) when an + item is inserted. insert() calls the virtual function + QCollection::newItem() for the item to be inserted. + Inherit a dictionary and reimplement it if you want deep copies. + + When removing a dictionary item, the virtual function + QCollection::deleteItem() is called. QDict's default implementation + is to delete the item if auto-deletion is enabled. + + \sa QDictIterator, QAsciiDict, QIntDict, QPtrDict, + \link collection.html Collection Classes\endlink +*/ + + +/*! + \fn QDict::QDict( int size, bool caseSensitive ) + Constructs a dictionary with the following properties: + \arg \e size is the size of the internal hash array. + \arg \e caseSensitive specifies whether to use case sensitive lookup or not. + + Setting \e size to a suitably large \link primes.html prime + number\endlink (equal to or greater than the expected number of entries) + makes the hash distribution better and hence the loopup faster. + + Setting \e caseSensitive to TRUE will treat "abc" and "Abc" as different + keys. Setting it to FALSE will make the dictionary ignore case. + Case insensitive comparison includes the whole Unicode alphabeth. +*/ + +/*! + \fn QDict::QDict( const QDict<type> &dict ) + Constructs a copy of \e dict. + + Each item in \e dict are inserted into this dictionary. + Only the pointers are copied (shallow copy). +*/ + +/*! + \fn QDict::~QDict() + Removes all items from the dictionary and destroys it. + All iterators that access this dictionary will be reset. + + \sa setAutoDelete() +*/ + +/*! + \fn QDict<type> &QDict::operator=(const QDict<type> &dict) + Assigns \e dict to this dictionary and returns a reference to this + dictionary. + + This dictionary is first cleared, then each item in \e dict is inserted + into this dictionary. + Only the pointers are copied (shallow copy), unless newItem() has been + reimplemented(). +*/ + +/*! + \fn uint QDict::count() const + Returns the number of items in the dictionary. + \sa isEmpty() +*/ + +/*! + \fn uint QDict::size() const + Returns the size of the internal hash array (as specified in the + constructor). + \sa count() +*/ + +/*! + \fn void QDict::resize( uint newsize ) + Changes the size of the hashtable the \a newsize. + The contents of the dictionary are preserved, + but all iterators on the dictionary become invalid. +*/ + +/*! + \fn bool QDict::isEmpty() const + Returns TRUE if the dictionary is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn void QDict::insert( const QString &key, const type *item ) + + Inserts the \e key with the \e item into the dictionary. + + The key does not have to be a unique dictionary key. If multiple items + are inserted with the same key, only the last item will be visible. + + Null items are not allowed. + + \sa replace() +*/ + +/*! + \fn void QDict::replace( const QString &key, const type *item ) + + Replaces an item which has a key equal to \e key with \e item. + + If the item does not already exist, it will be inserted. + + Null items are not allowed. + + Equivalent to: + \code + QDict<char> dict; + ... + if ( dict.find(key) ) + dict.remove( key ); + dict.insert( key, item ); + \endcode + + If there are two or more items with equal keys, then the last inserted + of these will be replaced. + + \sa insert() +*/ + +/*! + \fn bool QDict::remove( const QString &key ) + + Removes the item associated with \e key from the dictionary. + Returns TRUE if successful, or FALSE if the key does not exist in the + dictionary. + + If there are two or more items with equal keys, then the last inserted + of these will be removed. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All dictionary iterators that refer to the removed item will be set to + point to the next item in the dictionary traversing order. + + \sa take(), clear(), setAutoDelete() +*/ + +/*! + \fn type *QDict::take( const QString &key ) + + Takes the item associated with \e key out of the dictionary without + deleting it (even if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled). + + If there are two or more items with equal keys, then the last inserted + of these will be taken. + + Returns a pointer to the item taken out, or null if the key does not + exist in the dictionary. + + All dictionary iterators that refer to the taken item will be set to + point to the next item in the dictionary traversal order. + + \sa remove(), clear(), setAutoDelete() +*/ + +/*! + \fn void QDict::clear() + + Removes all items from the dictionary. + + The removed items are deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All dictionary iterators that operate on dictionary are reset. + + \sa remove(), take(), setAutoDelete() +*/ + +/*! + \fn type *QDict::find( const QString &key ) const + + Returns the item associated with \e key, or null if the key does not + exist in the dictionary. + + This function uses an internal hashing algorithm to optimize lookup. + + If there are two or more items with equal keys, then the last inserted + of these will be found. + + Equivalent to the [] operator. + + \sa operator[]() +*/ + +/*! + \fn type *QDict::operator[]( const QString &key ) const + + Returns the item associated with \e key, or null if the key does not + exist in the dictionary. + + This function uses an internal hashing algorithm to optimize lookup. + + If there are two or more items with equal keys, then the last inserted + of these will be found. + + Equivalent to the find() function. + + \sa find() +*/ + +/*! + \fn void QDict::statistics() const + Debugging-only function that prints out the dictionary distribution + using qDebug(). +*/ + + +/***************************************************************************** + QDictIterator documentation + *****************************************************************************/ + +/*! + \class QDictIterator qdict.h + \brief The QDictIterator class provides an iterator for QDict collections. + + \ingroup collection + \ingroup tools + + QDictIterator is implemented as a template class. + Define a template instance QDictIterator\<X\> to create a + dictionary iterator that operates on QDict\<X\> (dictionary of X*). + + Example: + \code + #include <qdict.h> + #include <stdio.h> + + void main() + { + // Creates a dictionary that maps QString ==> char* (case insensitive) + QDict<char> dict( 17, FALSE ); + + dict.insert( "France", "Paris" ); + dict.insert( "Russia", "Moscow" ); + dict.insert( "Norway", "Oslo" ); + + QDictIterator<char> it( dict ); // iterator for dict + + while ( it.current() ) { + printf( "%s -> %s\n", it.currentKey().latin1(), it.current() ); + ++it; + } + } + \endcode + + Program output: + \code + Russia -> Moscow + Norway -> Oslo + France -> Paris + \endcode + + Note that the traversal order is arbitrary, you are not guaranteed the + order above. + + Multiple iterators may independently traverse the same dictionary. + A QDict knows about all iterators that are operating on the dictionary. + When an item is removed from the dictionary, QDict update all iterators + that are referring the removed item to point to the next item in the + traversing order. + + \sa QDict, \link collection.html Collection Classes\endlink +*/ + +/*! + \fn QDictIterator::QDictIterator( const QDict<type> &dict ) + Constructs an iterator for \e dict. The current iterator item is + set to point on the first item in the \e dict. +*/ + +/*! + \fn QDictIterator::~QDictIterator() + Destroys the iterator. +*/ + +/*! + \fn uint QDictIterator::count() const + Returns the number of items in the dictionary this iterator operates on. + \sa isEmpty() +*/ + +/*! + \fn bool QDictIterator::isEmpty() const + Returns TRUE if the dictionary is empty, i.e. count() == 0, otherwise FALSE. + \sa count() +*/ + +/*! + \fn type *QDictIterator::toFirst() + Sets the current iterator item to point to the first item in the + dictionary and returns a pointer to the item. + If the dictionary is empty it sets the current item to null and + returns null. +*/ + +/*! + \fn QDictIterator::operator type *() const + Cast operator. Returns a pointer to the current iterator item. + Same as current(). +*/ + +/*! + \fn type *QDictIterator::current() const + Returns a pointer to the current iterator item. +*/ + +/*! + \fn QString QDictIterator::currentKey() const + Returns a pointer to the key for the current iterator item. +*/ + +/*! + \fn type *QDictIterator::operator()() + Makes the succeeding item current and returns the original current item. + + If the current iterator item was the last item in the dictionary or if it + was null, null is returned. +*/ + +/*! + \fn type *QDictIterator::operator++() + Prefix ++ makes the succeeding item current and returns the new current + item. + + If the current iterator item was the last item in the dictionary or if it + was null, null is returned. +*/ + +/*! + \fn type *QDictIterator::operator+=( uint jump ) + Sets the current item to the item \e jump positions after the current item, + and returns a pointer to that item. + + If that item is beyond the last item or if the dictionary is empty, + it sets the current item to null and returns null. +*/ + + diff --git a/trunk/qtools/qdict.h b/trunk/qtools/qdict.h new file mode 100644 index 0000000..682b270 --- /dev/null +++ b/trunk/qtools/qdict.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** +** Definition of QDict template class +** +** Created : 920821 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QDICT_H +#define QDICT_H + +#ifndef QT_H +#include "qgdict.h" +#endif // QT_H + +#define USE_ASCII_STRING + +#ifdef USE_ASCII_STRING + +#define QAsciiDict QDict +#define QAsciiDictIterator QDictIterator +#include "qasciidict.h" + +#else + +template<class type> class Q_EXPORT QDict : public QGDict +{ +public: + QDict(int size=17, bool caseSensitive=TRUE) + : QGDict(size,StringKey,caseSensitive,FALSE) {} + QDict( const QDict<type> &d ) : QGDict(d) {} + ~QDict() { clear(); } + QDict<type> &operator=(const QDict<type> &d) + { return (QDict<type>&)QGDict::operator=(d); } + uint count() const { return QGDict::count(); } + uint size() const { return QGDict::size(); } + bool isEmpty() const { return QGDict::count() == 0; } + + void insert( const QString &k, const type *d ) + { QGDict::look_string(k,(Item)d,1); } + void replace( const QString &k, const type *d ) + { QGDict::look_string(k,(Item)d,2); } + bool remove( const QString &k ) { return QGDict::remove_string(k); } + type *take( const QString &k ) { return (type *)QGDict::take_string(k); } + type *find( const QString &k ) const + { return (type *)((QGDict*)this)->QGDict::look_string(k,0,0); } + type *operator[]( const QString &k ) const + { return (type *)((QGDict*)this)->QGDict::look_string(k,0,0); } + + void clear() { QGDict::clear(); } + void resize( uint n ) { QGDict::resize(n); } + void statistics() const { QGDict::statistics(); } +private: + void deleteItem( Item d ); +}; + +#if defined(Q_DELETING_VOID_UNDEFINED) +template<> inline void QDict<void>::deleteItem( Item ) +{ +} +#endif + +template<class type> inline void QDict<type>::deleteItem( QCollection::Item d ) +{ + if ( del_item ) delete (type *)d; +} + + +template<class type> class Q_EXPORT QDictIterator : public QGDictIterator +{ +public: + QDictIterator(const QDict<type> &d) :QGDictIterator((QGDict &)d) {} + ~QDictIterator() {} + uint count() const { return dict->count(); } + bool isEmpty() const { return dict->count() == 0; } + type *toFirst() { return (type *)QGDictIterator::toFirst(); } + operator type *() const { return (type *)QGDictIterator::get(); } + type *current() const { return (type *)QGDictIterator::get(); } + QString currentKey() const{ return QGDictIterator::getKeyString(); } + type *operator()() { return (type *)QGDictIterator::operator()(); } + type *operator++() { return (type *)QGDictIterator::operator++(); } + type *operator+=(uint j) { return (type *)QGDictIterator::operator+=(j);} +}; + +#endif // USE_ASCII_STRING + +#endif // QDICT_H diff --git a/trunk/qtools/qdir.cpp b/trunk/qtools/qdir.cpp new file mode 100644 index 0000000..ed7ed99 --- /dev/null +++ b/trunk/qtools/qdir.cpp @@ -0,0 +1,1200 @@ +/**************************************************************************** +** +** +** Implementation of QDir class +** +** Created : 950427 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" + +#include "qdir.h" + +#ifndef QT_NO_DIR +#include "qfileinfo.h" +#include "qfiledefs_p.h" +#include "qregexp.h" +#include "qstringlist.h" +#include <stdlib.h> +#include <ctype.h> + +// NOT REVISED +/*! + \class QDir qdir.h + \brief Traverses directory structures and contents in a + platform-independent way. + + \ingroup io + + A QDir can point to a file using either a relative or an absolute file + path. Absolute file paths begin with the directory separator ('/') or a + drive specification (not applicable to UNIX). Relative file names begin + with a directory name or a file name and specify a path relative to the + current directory. + + An example of an absolute path is the string "/tmp/quartz", a relative + path might look like "src/fatlib". You can use the function isRelative() + to check if a QDir is using a relative or an absolute file path. You can + call the function convertToAbs() to convert a relative QDir to an + absolute one. + + The directory "example" under the current directory is checked for existence + in the example below: + + \code + QDir d( "example" ); // "./example" + if ( !d.exists() ) + qWarning( "Cannot find the example directory" ); + \endcode + + If you always use '/' as a directory separator, Qt will translate your + paths to conform to the underlying operating system. + + cd() and cdUp() can be used to navigate the directory tree. Note that the + logical cd and cdUp operations are not performed if the new directory does + not exist. + + Example: + \code + QDir d = QDir::root(); // "/" + if ( !d.cd("tmp") ) { // "/tmp" + qWarning( "Cannot find the \"/tmp\" directory" ); + } else { + QFile f( d.filePath("ex1.txt") ); // "/tmp/ex1.txt" + if ( !f.open(IO_ReadWrite) ) + qWarning( "Cannot create the file %s", f.name() ); + } + \endcode + + To read the contents of a directory you can use the entryList() and + entryInfoList() functions. + + Example: + \code + #include <stdio.h> + #include <qdir.h> + + // + // This program scans the current directory and lists all files + // that are not symbolic links, sorted by size with the smallest files + // first. + // + + int main( int argc, char **argv ) + { + QDir d; + d.setFilter( QDir::Files | QDir::Hidden | QDir::NoSymLinks ); + d.setSorting( QDir::Size | QDir::Reversed ); + + const QFileInfoList *list = d.entryInfoList(); + QFileInfoListIterator it( *list ); // create list iterator + QFileInfo *fi; // pointer for traversing + + printf( " BYTES FILENAME\n" ); // print header + while ( (fi=it.current()) ) { // for each file... + printf( "%10li %s\n", fi->size(), fi->fileName().data() ); + ++it; // goto next list element + } + } + \endcode +*/ + + +/*! + Constructs a QDir pointing to the current directory. + \sa currentDirPath() +*/ + +QDir::QDir() +{ + dPath = QString::fromLatin1("."); + init(); +} + +/*! + Constructs a QDir. + + \arg \e path is the directory. + \arg \e nameFilter is the file name filter. + \arg \e sortSpec is the sort specification, which describes how to + sort the files in the directory. + \arg \e filterSpec is the filter specification, which describes how + to filter the files in the directory. + + Most of these arguments (except \e path) have optional values. + + Example: + \code + // lists all files in /tmp + + QDir d( "/tmp" ); + for ( int i=0; i<d.count(); i++ ) + printf( "%s\n", d[i] ); + \endcode + + If \e path is "" or null, the directory is set to "." (the current + directory). If \e nameFilter is "" or null, it is set to "*" (all + files). + + No check is made to ensure that the directory exists. + + \sa exists(), setPath(), setNameFilter(), setFilter(), setSorting() +*/ + +QDir::QDir( const QString &path, const QString &nameFilter, + int sortSpec, int filterSpec ) +{ + init(); + dPath = cleanDirPath( path ); + if ( dPath.isEmpty() ) + dPath = QString::fromLatin1("."); + nameFilt = nameFilter; + if ( nameFilt.isEmpty() ) + nameFilt = QString::fromLatin1("*"); + filtS = (FilterSpec)filterSpec; + sortS = (SortSpec)sortSpec; +} + +/*! + Constructs a QDir that is a copy of the given directory. + \sa operator=() +*/ + +QDir::QDir( const QDir &d ) +{ + dPath = d.dPath; + fList = 0; + fiList = 0; + nameFilt = d.nameFilt; + dirty = TRUE; + allDirs = d.allDirs; + filtS = d.filtS; + sortS = d.sortS; +} + + +void QDir::init() +{ + fList = 0; + fiList = 0; + nameFilt = QString::fromLatin1("*"); + dirty = TRUE; + allDirs = FALSE; + filtS = All; + sortS = SortSpec(Name | IgnoreCase); +} + +/*! + Destructs the QDir and cleans up. +*/ + +QDir::~QDir() +{ + if ( fList ) + delete fList; + if ( fiList ) + delete fiList; +} + + +/*! + Sets the path of the directory. The path is cleaned of redundant ".", ".." + and multiple separators. No check is made to ensure that a directory + with this path exists. + + The path can be either absolute or relative. Absolute paths begin with the + directory separator ('/') or a drive specification (not + applicable to UNIX). + Relative file names begin with a directory name or a file name and specify + a path relative to the current directory. An example of + an absolute path is the string "/tmp/quartz", a relative path might look like + "src/fatlib". You can use the function isRelative() to check if a QDir + is using a relative or an absolute file path. You can call the function + convertToAbs() to convert a relative QDir to an absolute one. + + \sa path(), absPath(), exists(), cleanDirPath(), dirName(), + absFilePath(), isRelative(), convertToAbs() +*/ + +void QDir::setPath( const QString &path ) +{ + dPath = cleanDirPath( path ); + if ( dPath.isEmpty() ) + dPath = QString::fromLatin1("."); + dirty = TRUE; +} + +/*! + \fn QString QDir::path() const + Returns the path, this may contain symbolic links, but never contains + redundant ".", ".." or multiple separators. + + The returned path can be either absolute or relative (see setPath()). + + \sa setPath(), absPath(), exists(), cleanDirPath(), dirName(), + absFilePath(), convertSeparators() +*/ + +/*! + Returns the absolute (a path that starts with '/') path, which may + contain symbolic links, but never contains redundant ".", ".." or + multiple separators. + + \sa setPath(), canonicalPath(), exists(), cleanDirPath(), dirName(), + absFilePath() +*/ + +QString QDir::absPath() const +{ + if ( QDir::isRelativePath(dPath) ) { + QString tmp = currentDirPath(); + if ( tmp.right(1) != QString::fromLatin1("/") ) + tmp += '/'; + tmp += dPath; + return cleanDirPath( tmp ); + } else { + return cleanDirPath( dPath ); + } +} + +/*! + Returns the name of the directory, this is NOT the same as the path, e.g. + a directory with the name "mail", might have the path "/var/spool/mail". + If the directory has no name (e.g. the root directory) a null string is + returned. + + No check is made to ensure that a directory with this name actually exists. + + \sa path(), absPath(), absFilePath(), exists(), QString::isNull() +*/ + +QString QDir::dirName() const +{ + int pos = dPath.findRev( '/' ); + if ( pos == -1 ) + return dPath; + return dPath.right( dPath.length() - pos - 1 ); +} + +/*! + Returns the path name of a file in the directory. Does NOT check if + the file actually exists in the directory. If the QDir is relative + the returned path name will also be relative. Redundant multiple separators + or "." and ".." directories in \e fileName will not be removed (see + cleanDirPath()). + + If \e acceptAbsPath is TRUE a \e fileName starting with a separator + ('/') will be returned without change. + If \e acceptAbsPath is FALSE an absolute path will be appended to + the directory path. + + \sa absFilePath(), isRelative(), canonicalPath() +*/ + +QString QDir::filePath( const QString &fileName, + bool acceptAbsPath ) const +{ + if ( acceptAbsPath && !isRelativePath(fileName) ) + return QString(fileName); + + QString tmp = dPath; + if ( tmp.isEmpty() || (tmp[(int)tmp.length()-1] != '/' && !!fileName && + fileName[0] != '/') ) + tmp += '/'; + tmp += fileName; + return tmp; +} + +/*! + Returns the absolute path name of a file in the directory. Does NOT check if + the file actually exists in the directory. Redundant multiple separators + or "." and ".." directories in \e fileName will NOT be removed (see + cleanDirPath()). + + If \e acceptAbsPath is TRUE a \e fileName starting with a separator + ('/') will be returned without change. + if \e acceptAbsPath is FALSE an absolute path will be appended to + the directory path. + + \sa filePath() +*/ + +QString QDir::absFilePath( const QString &fileName, + bool acceptAbsPath ) const +{ + if ( acceptAbsPath && !isRelativePath( fileName ) ) + return fileName; + + QString tmp = absPath(); + if ( tmp.isEmpty() || (tmp[(int)tmp.length()-1] != '/' && !!fileName && + fileName[0] != '/') ) + tmp += '/'; + tmp += fileName; + return tmp; +} + + +/*! + Converts the '/' separators in \a pathName to system native + separators. Returns the translated string. + + On Windows, convertSeparators("c:/winnt/system32") returns + "c:\winnt\system32". + + No conversion is done on UNIX. +*/ + +QString QDir::convertSeparators( const QString &pathName ) +{ + QString n( pathName ); +#if defined(_OS_FATFS_) || defined(_OS_OS2EMX_) + for ( int i=0; i<(int)n.length(); i++ ) { + if ( n[i] == '/' ) + n[i] = '\\'; + } +#endif + return n; +} + + +/*! + Changes directory by descending into the given directory. Returns + TRUE if the new directory exists and is readable. Note that the logical + cd operation is NOT performed if the new directory does not exist. + + If \e acceptAbsPath is TRUE a path starting with a separator ('/') + will cd to the absolute directory, if \e acceptAbsPath is FALSE + any number of separators at the beginning of \e dirName will be removed. + + Example: + \code + QDir d = QDir::home(); // now points to home directory + if ( !d.cd("c++") ) { // now points to "c++" under home directory if OK + QFileInfo fi( d, "c++" ); + if ( fi.exists() ) { + if ( fi.isDir() ) + qWarning( "Cannot cd into \"%s\".", (char*)d.absFilePath("c++") ); + else + qWarning( "Cannot create directory \"%s\"\n" + "A file named \"c++\" already exists in \"%s\"", + (const char *)d.absFilePath("c++"), + (const char *)d.path() ); + return; + } else { + qWarning( "Creating directory \"%s\"", + (const char *) d.absFilePath("c++") ); + if ( !d.mkdir( "c++" ) ) { + qWarning("Could not create directory \"%s\"", + (const char *)d.absFilePath("c++") ); + return; + } + } + } + \endcode + + Calling cd( ".." ) is equivalent to calling cdUp(). + + \sa cdUp(), isReadable(), exists(), path() +*/ + +bool QDir::cd( const QString &dirName, bool acceptAbsPath ) +{ + if ( dirName.isEmpty() || dirName==QString::fromLatin1(".") ) + return TRUE; + QString old = dPath; + if ( acceptAbsPath && !isRelativePath(dirName) ) { + dPath = cleanDirPath( dirName ); + } else { + if ( !isRoot() ) + dPath += '/'; + dPath += dirName; + if ( dirName.find('/') >= 0 + || old == QString::fromLatin1(".") + || dirName == QString::fromLatin1("..") ) + dPath = cleanDirPath( dPath ); + } + if ( !exists() ) { + dPath = old; // regret + return FALSE; + } + dirty = TRUE; + return TRUE; +} + +/*! + Changes directory by moving one directory up the path followed to arrive + at the current directory. + + Returns TRUE if the new directory exists and is readable. Note that the + logical cdUp() operation is not performed if the new directory does not + exist. + + \sa cd(), isReadable(), exists(), path() +*/ + +bool QDir::cdUp() +{ + return cd( QString::fromLatin1("..") ); +} + +/*! + \fn QString QDir::nameFilter() const + Returns the string set by setNameFilter() +*/ + +/*! + Sets the name filter used by entryList() and entryInfoList(). + + The name filter is a wildcarding filter that understands "*" and "?" + wildcards, You may specify several filter entries separated by a " " or a ";". If + you want entryList() and entryInfoList() to list all files ending with + ".cpp" and all files ending with ".h", you simply call + dir.setNameFilter("*.cpp *.h") or dir.setNameFilter("*.cpp;*.h") + + \sa nameFilter(), setFilter() +*/ + +void QDir::setNameFilter( const QString &nameFilter ) +{ + nameFilt = nameFilter; + if ( nameFilt.isEmpty() ) + nameFilt = QString::fromLatin1("*"); + dirty = TRUE; +} + +/*! + \fn QDir::FilterSpec QDir::filter() const + Returns the value set by setFilter() +*/ + +/*! \enum QDir::FilterSpec + + This enum describes how QDir is to select what entries in a + directory to return. The filter value is specified by or-ing + together values from the following list: <ul> + + <li> \c Dirs - List directories only + <li> \c Files - List files only + + <li> \c Drives - List disk drives (does nothing under unix) + <li> \c NoSymLinks - Do not list symbolic links (where they exist) + <li> \c Readable - List files for which the application has read access. + <li> \c Writable - List files for which the application has write access. + <li> \c Executable - List files for which the application has execute access + <li> \c Modified - Only list files that have been modified (does nothing + under unix) + <li> \c Hidden - List hidden files (on unix, files starting with a .) + <li> \c System - List system files (does nothing under unix) + </ul> + + If you do not set any of \c Readable, \c Writable or \c Executable, + QDir will set all three of them. This makes the default easy to + write and at the same time useful. + + Examples: \c Readable|Writable means list all files for which the + application has read access, write access or both. \c Dirs|Drives + means list drives, directories, all files that the application can + read, write or execute, and also symlinks to such files/directories. +*/ + + +/*! + Sets the filter used by entryList() and entryInfoList(). The filter is used + to specify the kind of files that should be returned by entryList() and + entryInfoList(). + + \sa filter(), setNameFilter() +*/ + +void QDir::setFilter( int filterSpec ) +{ + if ( filtS == (FilterSpec) filterSpec ) + return; + filtS = (FilterSpec) filterSpec; + dirty = TRUE; +} + +/*! + \fn QDir::SortSpec QDir::sorting() const + + Returns the value set by setSorting() + + \sa setSorting() +*/ + +/*! \enum QDir::SortSpec + + This enum describes how QDir is to sort entries in a directory when + it returns a list of them. The sort value is specified by or-ing + together values from the following list: <ul> + + <li> \c Name - sort by name + <li> \c Time - sort by time (modification time) + <li> \c Size - sort by file size + <li> \c Unsorted - do not sort + + <li> \c DirsFirst - put all directories first in the list + <li> \c Reversed - reverse the sort order + <li> \c IgnoreCase - sort case-insensitively + + </ul> + + You can only specify one of the first four. If you specify both \c + DirsFirst and \c Reversed, directories are still put first but the + list is otherwise reversed. +*/ + +// ### Unsorted+DirsFirst ? Unsorted+Reversed? + +/*! + Sets the sorting order used by entryList() and entryInfoList(). + + The \e sortSpec is specified by or-ing values from the enum + SortSpec. The different values are: + + One of these: + <dl compact> + <dt>Name<dd> Sort by name (alphabetical order). + <dt>Time<dd> Sort by time (most recent first). + <dt>Size<dd> Sort by size (largest first). + <dt>Unsorted<dd> Use the operating system order (UNIX does NOT sort + alphabetically). + + ORed with zero or more of these: + + <dt>DirsFirst<dd> Always put directory names first. + <dt>Reversed<dd> Reverse sort order. + <dt>IgnoreCase<dd> Ignore case when sorting by name. + </dl> +*/ + +void QDir::setSorting( int sortSpec ) +{ + if ( sortS == (SortSpec) sortSpec ) + return; + sortS = (SortSpec) sortSpec; + dirty = TRUE; +} + +/*! + \fn bool QDir::matchAllDirs() const + Returns the value set by setMatchAllDirs() + + \sa setMatchAllDirs() +*/ + +/*! + If \e enable is TRUE, all directories will be listed (even if they do not + match the filter or the name filter), otherwise only matched directories + will be listed. + + \bug Currently, directories that do not match the filter will not be + included (the name filter will be ignored as expected). + + \sa matchAllDirs() +*/ + +void QDir::setMatchAllDirs( bool enable ) +{ + if ( (bool)allDirs == enable ) + return; + allDirs = enable; + dirty = TRUE; +} + + +/*! + Returns the number of files that was found. + Equivalent to entryList().count(). + \sa operator[](), entryList() +*/ + +uint QDir::count() const +{ + return entryList().count(); +} + +/*! + Returns the file name at position \e index in the list of found file + names. + Equivalent to entryList().at(index). + + Returns null if the \e index is out of range or if the entryList() + function failed. + + \sa count(), entryList() +*/ + +QString QDir::operator[]( int index ) const +{ + entryList(); + return fList && index >= 0 && index < (int)fList->count() ? + (*fList)[index] : QString::null; +} + + +/*! + This function is included to easy porting from Qt 1.x to Qt 2.0, + it is the same as entryList(), but encodes the filenames as 8-bit + strings using QFile::encodedName(). + + It is more efficient to use entryList(). +*/ +QStrList QDir::encodedEntryList( int filterSpec, int sortSpec ) const +{ + QStrList r; + QStringList l = entryList(filterSpec,sortSpec); + for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) { + r.append( QFile::encodeName(*it) ); + } + return r; +} + +/*! + This function is included to easy porting from Qt 1.x to Qt 2.0, + it is the same as entryList(), but encodes the filenames as 8-bit + strings using QFile::encodedName(). + + It is more efficient to use entryList(). +*/ +QStrList QDir::encodedEntryList( const QString &nameFilter, + int filterSpec, + int sortSpec ) const +{ + QStrList r; + QStringList l = entryList(nameFilter,filterSpec,sortSpec); + for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) { + r.append( QFile::encodeName(*it) ); + } + return r; +} + + + +/*! + Returns a list of the names of all files and directories in the directory + indicated by the setSorting(), setFilter() and setNameFilter() + specifications. + + The the filter and sorting specifications can be overridden using the + \e filterSpec and \e sortSpec arguments. + + Returns an empty list if the directory is unreadable or does not exist. + + \sa entryInfoList(), setNameFilter(), setSorting(), setFilter(), + encodedEntryList() +*/ + +QStringList QDir::entryList( int filterSpec, int sortSpec ) const +{ + if ( !dirty && filterSpec == (int)DefaultFilter && + sortSpec == (int)DefaultSort ) + return *fList; + return entryList( nameFilt, filterSpec, sortSpec ); +} + +/*! + Returns a list of the names of all files and directories in the directory + indicated by the setSorting(), setFilter() and setNameFilter() + specifications. + + The the filter and sorting specifications can be overridden using the + \e nameFilter, \e filterSpec and \e sortSpec arguments. + + Returns and empty list if the directory is unreadable or does not exist. + + \sa entryInfoList(), setNameFilter(), setSorting(), setFilter(), + encodedEntryList() +*/ + +QStringList QDir::entryList( const QString &nameFilter, + int filterSpec, int sortSpec ) const +{ + if ( filterSpec == (int)DefaultFilter ) + filterSpec = filtS; + if ( sortSpec == (int)DefaultSort ) + sortSpec = sortS; + QDir *that = (QDir*)this; // mutable function + if ( that->readDirEntries(nameFilter, filterSpec, sortSpec) ) + return *that->fList; + else + return QStringList(); +} + +/*! + Returns a list of QFileInfo objects for all files and directories in + the directory pointed to using the setSorting(), setFilter() and + setNameFilter() specifications. + + The the filter and sorting specifications can be overridden using the + \e filterSpec and \e sortSpec arguments. + + Returns 0 if the directory is unreadable or does not exist. + + The returned pointer is a const pointer to a QFileInfoList. The list is + owned by the QDir object and will be reused on the next call to + entryInfoList() for the same QDir instance. If you want to keep the + entries of the list after a subsequent call to this function you will + need to copy them. + + \sa entryList(), setNameFilter(), setSorting(), setFilter() +*/ + +const QFileInfoList *QDir::entryInfoList( int filterSpec, int sortSpec ) const +{ + if ( !dirty && filterSpec == (int)DefaultFilter && + sortSpec == (int)DefaultSort ) + return fiList; + return entryInfoList( nameFilt, filterSpec, sortSpec ); +} + +/*! + Returns a list of QFileInfo objects for all files and directories in + the directory pointed to using the setSorting(), setFilter() and + setNameFilter() specifications. + + The the filter and sorting specifications can be overridden using the + \e nameFilter, \e filterSpec and \e sortSpec arguments. + + Returns 0 if the directory is unreadable or does not exist. + + The returned pointer is a const pointer to a QFileInfoList. The list is + owned by the QDir object and will be reused on the next call to + entryInfoList() for the same QDir instance. If you want to keep the + entries of the list after a subsequent call to this function you will + need to copy them. + + \sa entryList(), setNameFilter(), setSorting(), setFilter() +*/ + +const QFileInfoList *QDir::entryInfoList( const QString &nameFilter, + int filterSpec, int sortSpec ) const +{ + if ( filterSpec == (int)DefaultFilter ) + filterSpec = filtS; + if ( sortSpec == (int)DefaultSort ) + sortSpec = sortS; + QDir *that = (QDir*)this; // mutable function + if ( that->readDirEntries(nameFilter, filterSpec, sortSpec) ) + return that->fiList; + else + return 0; +} + +/*! + Returns TRUE if the directory exists. (If a file with the same + name is found this function will of course return FALSE). + + \sa QFileInfo::exists(), QFile::exists() +*/ + +bool QDir::exists() const +{ + QFileInfo fi( dPath ); + return fi.exists() && fi.isDir(); +} + +/*! + Returns TRUE if the directory path is relative to the current directory, + FALSE if the path is absolute (e.g. under UNIX a path is relative if it + does not start with a '/'). + + According to Einstein this function should always return TRUE. + + \sa convertToAbs() +*/ + +bool QDir::isRelative() const +{ + return isRelativePath( dPath ); +} + +/*! + Converts the directory path to an absolute path. If it is already + absolute nothing is done. + + \sa isRelative() +*/ + +void QDir::convertToAbs() +{ + dPath = absPath(); +} + +/*! + Makes a copy of d and assigns it to this QDir. +*/ + +QDir &QDir::operator=( const QDir &d ) +{ + dPath = d.dPath; + delete fList; + fList = 0; + delete fiList; + fiList = 0; + nameFilt = d.nameFilt; + dirty = TRUE; + allDirs = d.allDirs; + filtS = d.filtS; + sortS = d.sortS; + return *this; +} + +/*! + Sets the directory path to be the given path. +*/ + +QDir &QDir::operator=( const QString &path ) +{ + dPath = cleanDirPath( path ); + dirty = TRUE; + return *this; +} + + +/*! + \fn bool QDir::operator!=( const QDir &d ) const + Returns TRUE if the \e d and this dir have different path or + different sort/filter settings, otherwise FALSE. +*/ + +/*! + Returns TRUE if the \e d and this dir have the same path and all sort + and filter settings are equal, otherwise FALSE. +*/ + +bool QDir::operator==( const QDir &d ) const +{ + return dPath == d.dPath && + nameFilt == d.nameFilt && + allDirs == d.allDirs && + filtS == d.filtS && + sortS == d.sortS; +} + + +/*! + Removes a file. + + If \e acceptAbsPath is TRUE a path starting with a separator ('/') + will remove the file with the absolute path, if \e acceptAbsPath is FALSE + any number of separators at the beginning of \e fileName will be removed. + + Returns TRUE if successful, otherwise FALSE. +*/ + +bool QDir::remove( const QString &fileName, bool acceptAbsPath ) +{ + if ( fileName.isEmpty() ) { +#if defined(CHECK_NULL) + qWarning( "QDir::remove: Empty or null file name" ); +#endif + return FALSE; + } + QString p = filePath( fileName, acceptAbsPath ); + return QFile::remove( p ); +} + +/*! + Checks for existence of a file. + + If \e acceptAbsPaths is TRUE a path starting with a separator ('/') + will check the file with the absolute path, if \e acceptAbsPath is FALSE + any number of separators at the beginning of \e name will be removed. + + Returns TRUE if the file exists, otherwise FALSE. + + \sa QFileInfo::exists(), QFile::exists() +*/ + +bool QDir::exists( const QString &name, bool acceptAbsPath ) +{ + if ( name.isEmpty() ) { +#if defined(CHECK_NULL) + qWarning( "QDir::exists: Empty or null file name" ); +#endif + return FALSE; + } + QString tmp = filePath( name, acceptAbsPath ); + return QFile::exists( tmp ); +} + +/*! + Returns the native directory separator; '/' under UNIX and '\' under + MS-DOS, Windows NT and OS/2. + + You do not need to use this function to build file paths. If you always + use '/', Qt will translate your paths to conform to the underlying + operating system. +*/ + +char QDir::separator() +{ +#if defined(_OS_UNIX_) + return '/'; +#elif defined (_OS_FATFS_) + return '\\'; +#elif defined (_OS_MAC_) + return ':'; +#else + return '/'; +#endif +} + +/*! + Returns the current directory. + \sa currentDirPath(), QDir::QDir() +*/ + +QDir QDir::current() +{ + return QDir( currentDirPath() ); +} + +/*! + Returns the home directory. + \sa homeDirPath() +*/ + +QDir QDir::home() +{ + return QDir( homeDirPath() ); +} + +/*! + Returns the root directory. + \sa rootDirPath() drives() +*/ + +QDir QDir::root() +{ + return QDir( rootDirPath() ); +} + +/*! + \fn QString QDir::homeDirPath() + + Returns the absolute path for the user's home directory, + \sa home() +*/ + +QStringList qt_makeFilterList( const QString &filter ) +{ + if ( filter.isEmpty() ) + return QStringList(); + + QChar sep( ';' ); + int i = filter.find( sep, 0 ); + if ( i == -1 && filter.find( ' ', 0 ) != -1 ) + sep = QChar( ' ' ); + + QStringList lst = QStringList::split( sep, filter ); + QStringList lst2; + QStringList::Iterator it = lst.begin(); + + for ( ; it != lst.end(); ++it ) { + QString s = *it; + lst2 << s.stripWhiteSpace(); + } + return lst2; +} + +/*! + Returns TRUE if the \e fileName matches one of the wildcards in the list \e filters. + \sa QRegExp +*/ + +bool QDir::match( const QStringList &filters, const QString &fileName ) +{ + QStringList::ConstIterator sit = filters.begin(); + bool matched = FALSE; + for ( ; sit != filters.end(); ++sit ) { + QRegExp regexp( *sit, FALSE, TRUE ); + if ( regexp.match( fileName ) != -1 ) { + matched = TRUE; + break; + } + } + + return matched; +} + +/*! + Returns TRUE if the \e fileName matches the wildcard \e filter. + \a Filter may also contain multiple wildcards separated by spaces or + semicolons. + \sa QRegExp +*/ + +bool QDir::match( const QString &filter, const QString &fileName ) +{ + QStringList lst = qt_makeFilterList( filter ); + return match( lst, fileName ); +} + + +/*! + Removes all multiple directory separators ('/') and resolves + any "." or ".." found in the path. + + Symbolic links are kept. This function does not return the + canonical path, but rather the most simplified version of the input. + "../stuff" becomes "stuff", "stuff/../nonsense" becomes "nonsense" + and "\\stuff\\more\\..\\nonsense" becomes "\\stuff\\nonsense". + + \sa absPath() canonicalPath() +*/ + +QString QDir::cleanDirPath( const QString &filePath ) +{ + QString name = filePath; + QString newPath; + + if ( name.isEmpty() ) + return name; + + slashify( name ); + + bool addedSeparator; + if ( isRelativePath(name) ) { + addedSeparator = TRUE; + name.insert( 0, '/' ); + } else { + addedSeparator = FALSE; + } + + int ePos, pos, upLevel; + + pos = ePos = name.length(); + upLevel = 0; + int len; + + while ( pos && (pos = name.findRev('/',--pos)) != -1 ) { + len = ePos - pos - 1; + if ( len == 2 && name.at(pos + 1) == '.' + && name.at(pos + 2) == '.' ) { + upLevel++; + } else { + if ( len != 0 && (len != 1 || name.at(pos + 1) != '.') ) { + if ( !upLevel ) + newPath = QString::fromLatin1("/") + + name.mid(pos + 1, len) + newPath; + else + upLevel--; + } + } + ePos = pos; + } + if ( addedSeparator ) { + while ( upLevel-- ) + newPath.insert( 0, QString::fromLatin1("/..") ); + if ( !newPath.isEmpty() ) + newPath.remove( 0, 1 ); + else + newPath = QString::fromLatin1("."); + } else { + if ( newPath.isEmpty() ) + newPath = QString::fromLatin1("/"); +#if defined(_OS_FATFS_) || defined(_OS_OS2EMX_) + if ( name[0] == '/' ) { + if ( name[1] == '/' ) // "\\machine\x\ ..." + newPath.insert( 0, '/' ); + } else { + newPath = name.left(2) + newPath; + } +#endif + } + return newPath; +} + +int qt_cmp_si_sortSpec; + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +int qt_cmp_si( const void *n1, const void *n2 ) +{ + if ( !n1 || !n2 ) + return 0; + + QDirSortItem* f1 = (QDirSortItem*)n1; + QDirSortItem* f2 = (QDirSortItem*)n2; + + if ( qt_cmp_si_sortSpec & QDir::DirsFirst ) + if ( f1->item->isDir() != f2->item->isDir() ) + return f1->item->isDir() ? -1 : 1; + + int r = 0; + int sortBy = qt_cmp_si_sortSpec & QDir::SortByMask; + + switch ( sortBy ) { + case QDir::Time: + r = f1->item->lastModified().secsTo(f2->item->lastModified()); + break; + case QDir::Size: + r = f2->item->size() - f1->item->size(); + break; + default: + ; + } + + if ( r == 0 && sortBy != QDir::Unsorted ) { + // Still not sorted - sort by name + bool ic = qt_cmp_si_sortSpec & QDir::IgnoreCase; + + if ( f1->filename_cache.isNull() ) + f1->filename_cache = ic ? f1->item->fileName().lower() + : f1->item->fileName(); + if ( f2->filename_cache.isNull() ) + f2->filename_cache = ic ? f2->item->fileName().lower() + : f2->item->fileName(); + + r = f1->filename_cache.compare(f2->filename_cache); + } + + if ( r == 0 ) { + // Enforce an order - the order the items appear in the array + r = (char*)n1 - (char*)n2; + } + + if ( qt_cmp_si_sortSpec & QDir::Reversed ) + return -r; + else + return r; +} + +#if defined(Q_C_CALLBACKS) +} +#endif + +#endif // QT_NO_DIR diff --git a/trunk/qtools/qdir.h b/trunk/qtools/qdir.h new file mode 100644 index 0000000..dd74271 --- /dev/null +++ b/trunk/qtools/qdir.h @@ -0,0 +1,235 @@ +/**************************************************************************** +** +** +** Definition of QDir class +** +** Created : 950427 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QDIR_H +#define QDIR_H + +#ifndef QT_H +#include "qstrlist.h" +#include "qfileinfo.h" +#endif // QT_H + +#ifndef QT_NO_DIR +typedef QList<QFileInfo> QFileInfoList; +typedef QListIterator<QFileInfo> QFileInfoListIterator; +class QStringList; + + +class Q_EXPORT QDir +{ +public: + enum FilterSpec { Dirs = 0x001, + Files = 0x002, + Drives = 0x004, + NoSymLinks = 0x008, + All = 0x007, + TypeMask = 0x00F, + + Readable = 0x010, + Writable = 0x020, + Executable = 0x040, + RWEMask = 0x070, + + Modified = 0x080, + Hidden = 0x100, + System = 0x200, + AccessMask = 0x3F0, + + DefaultFilter = -1 }; + + enum SortSpec { Name = 0x00, + Time = 0x01, + Size = 0x02, + Unsorted = 0x03, + SortByMask = 0x03, + + DirsFirst = 0x04, + Reversed = 0x08, + IgnoreCase = 0x10, + DefaultSort = -1 }; + + QDir(); + QDir( const QString &path, const QString &nameFilter = QString::null, + int sortSpec = Name | IgnoreCase, int filterSpec = All ); + QDir( const QDir & ); + + virtual ~QDir(); + + QDir &operator=( const QDir & ); + QDir &operator=( const QString &path ); + + virtual void setPath( const QString &path ); + virtual QString path() const; + virtual QString absPath() const; + virtual QString canonicalPath() const; + + virtual QString dirName() const; + virtual QString filePath( const QString &fileName, + bool acceptAbsPath = TRUE ) const; + virtual QString absFilePath( const QString &fileName, + bool acceptAbsPath = TRUE ) const; + + static QString convertSeparators( const QString &pathName ); + + virtual bool cd( const QString &dirName, bool acceptAbsPath = TRUE ); + virtual bool cdUp(); + + QString nameFilter() const; + virtual void setNameFilter( const QString &nameFilter ); + FilterSpec filter() const; + virtual void setFilter( int filterSpec ); + SortSpec sorting() const; + virtual void setSorting( int sortSpec ); + + bool matchAllDirs() const; + virtual void setMatchAllDirs( bool ); + + uint count() const; + QString operator[]( int ) const; + + virtual QStrList encodedEntryList( int filterSpec = DefaultFilter, + int sortSpec = DefaultSort ) const; + virtual QStrList encodedEntryList( const QString &nameFilter, + int filterSpec = DefaultFilter, + int sortSpec = DefaultSort ) const; + virtual QStringList entryList( int filterSpec = DefaultFilter, + int sortSpec = DefaultSort ) const; + virtual QStringList entryList( const QString &nameFilter, + int filterSpec = DefaultFilter, + int sortSpec = DefaultSort ) const; + + virtual const QFileInfoList *entryInfoList( int filterSpec = DefaultFilter, + int sortSpec = DefaultSort ) const; + virtual const QFileInfoList *entryInfoList( const QString &nameFilter, + int filterSpec = DefaultFilter, + int sortSpec = DefaultSort ) const; + + static const QFileInfoList *drives(); + + virtual bool mkdir( const QString &dirName, + bool acceptAbsPath = TRUE ) const; + virtual bool rmdir( const QString &dirName, + bool acceptAbsPath = TRUE ) const; + + virtual bool isReadable() const; + virtual bool exists() const; + virtual bool isRoot() const; + + virtual bool isRelative() const; + virtual void convertToAbs(); + + virtual bool operator==( const QDir & ) const; + virtual bool operator!=( const QDir & ) const; + + virtual bool remove( const QString &fileName, + bool acceptAbsPath = TRUE ); + virtual bool rename( const QString &name, const QString &newName, + bool acceptAbsPaths = TRUE ); + virtual bool exists( const QString &name, + bool acceptAbsPath = TRUE ); + + static char separator(); + + static bool setCurrent( const QString &path ); + static QDir current(); + static QDir home(); + static QDir root(); + static QString currentDirPath(); + static QString homeDirPath(); + static QString rootDirPath(); + + static bool match( const QStringList &filters, const QString &fileName ); + static bool match( const QString &filter, const QString &fileName ); + static QString cleanDirPath( const QString &dirPath ); + static bool isRelativePath( const QString &path ); + +private: + void init(); + virtual bool readDirEntries( const QString &nameFilter, + int FilterSpec, int SortSpec ); + + static void slashify ( QString &); + + QString dPath; + QStringList *fList; + QFileInfoList *fiList; + QString nameFilt; + FilterSpec filtS; + SortSpec sortS; + uint dirty : 1; + uint allDirs : 1; +}; + + +inline QString QDir::path() const +{ + return dPath; +} + +inline QString QDir::nameFilter() const +{ + return nameFilt; +} + +inline QDir::FilterSpec QDir::filter() const +{ + return filtS; +} + +inline QDir::SortSpec QDir::sorting() const +{ + return sortS; +} + +inline bool QDir::matchAllDirs() const +{ + return allDirs; +} + +inline bool QDir::operator!=( const QDir &d ) const +{ + return !(*this == d); +} + + +struct QDirSortItem { + QString filename_cache; + QFileInfo* item; +}; + +#endif // QT_NO_DIR +#endif // QDIR_H diff --git a/trunk/qtools/qdir_unix.cpp b/trunk/qtools/qdir_unix.cpp new file mode 100644 index 0000000..46a3b69 --- /dev/null +++ b/trunk/qtools/qdir_unix.cpp @@ -0,0 +1,288 @@ +/**************************************************************************** +** +** +** Implementation of QDirclass +** +** Created : 950628 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses for Unix/X11 or for Qt/Embedded may use this file in accordance +** with the Qt Commercial License Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" + +#include "qdir.h" +#ifndef QT_NO_DIR + +#include "qfileinfo.h" +#include "qfiledefs_p.h" +#include "qregexp.h" +#include "qstringlist.h" +#include <stdlib.h> +#include <ctype.h> + +extern QStringList qt_makeFilterList( const QString &filter ); + +extern int qt_cmp_si_sortSpec; + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +extern int qt_cmp_si( const void *, const void * ); + +#if defined(Q_C_CALLBACKS) +} +#endif + + +void QDir::slashify( QString& ) +{ +} + +QString QDir::homeDirPath() +{ + QString d; + d = QFile::decodeName(getenv("HOME")); + slashify( d ); + if ( d.isNull() ) + d = rootDirPath(); + return d; +} + +QString QDir::canonicalPath() const +{ + QString r; + + char cur[PATH_MAX]; + char tmp[PATH_MAX]; + GETCWD( cur, PATH_MAX ); + if ( CHDIR(QFile::encodeName(dPath)) >= 0 ) { + GETCWD( tmp, PATH_MAX ); + r = QFile::decodeName(tmp); + } + CHDIR( cur ); + + slashify( r ); + return r; +} + +bool QDir::mkdir( const QString &dirName, bool acceptAbsPath ) const +{ + return MKDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)), 0777 ) + == 0; +} + +bool QDir::rmdir( const QString &dirName, bool acceptAbsPath ) const +{ + return RMDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)) ) == 0; +} + +bool QDir::isReadable() const +{ + return ACCESS( QFile::encodeName(dPath), R_OK | X_OK ) == 0; +} + +bool QDir::isRoot() const +{ + return dPath == QString::fromLatin1("/"); +} + +bool QDir::rename( const QString &name, const QString &newName, + bool acceptAbsPaths ) +{ + if ( name.isEmpty() || newName.isEmpty() ) { +#if defined(CHECK_NULL) + qWarning( "QDir::rename: Empty or null file name(s)" ); +#endif + return FALSE; + } + QString fn1 = filePath( name, acceptAbsPaths ); + QString fn2 = filePath( newName, acceptAbsPaths ); + return ::rename( QFile::encodeName(fn1), + QFile::encodeName(fn2) ) == 0; +} + +bool QDir::setCurrent( const QString &path ) +{ + int r; + r = CHDIR( QFile::encodeName(path) ); + return r >= 0; +} + +QString QDir::currentDirPath() +{ + QString result; + + STATBUF st; + if ( STAT( ".", &st ) == 0 ) { + char currentName[PATH_MAX]; + if ( GETCWD( currentName, PATH_MAX ) != 0 ) + result = QFile::decodeName(currentName); +#if defined(DEBUG) + if ( result.isNull() ) + qWarning( "QDir::currentDirPath: getcwd() failed" ); +#endif + } else { +#if defined(DEBUG) + qWarning( "QDir::currentDirPath: stat(\".\") failed" ); +#endif + } + slashify( result ); + return result; +} + +QString QDir::rootDirPath() +{ + QString d = QString::fromLatin1( "/" ); + return d; +} + +bool QDir::isRelativePath( const QString &path ) +{ + int len = path.length(); + if ( len == 0 ) + return TRUE; + return path[0] != '/'; +} + +bool QDir::readDirEntries( const QString &nameFilter, + int filterSpec, int sortSpec ) +{ + int i; + if ( !fList ) { + fList = new QStringList; + CHECK_PTR( fList ); + fiList = new QFileInfoList; + CHECK_PTR( fiList ); + fiList->setAutoDelete( TRUE ); + } else { + fList->clear(); + fiList->clear(); + } + + QStringList filters = qt_makeFilterList( nameFilter ); + + bool doDirs = (filterSpec & Dirs) != 0; + bool doFiles = (filterSpec & Files) != 0; + bool noSymLinks = (filterSpec & NoSymLinks) != 0; + bool doReadable = (filterSpec & Readable) != 0; + bool doWritable = (filterSpec & Writable) != 0; + bool doExecable = (filterSpec & Executable) != 0; + bool doHidden = (filterSpec & Hidden) != 0; + +#if defined(_OS_OS2EMX_) + //QRegExp wc( nameFilter, FALSE, TRUE ); // wild card, case insensitive +#else + //QRegExp wc( nameFilter, TRUE, TRUE ); // wild card, case sensitive +#endif + QFileInfo fi; + DIR *dir; + dirent *file; + + dir = opendir( QFile::encodeName(dPath) ); + if ( !dir ) { +#if defined(CHECK_NULL) + qWarning( "QDir::readDirEntries: Cannot read the directory: %s", + QFile::encodeName(dPath).data() ); +#endif + return FALSE; + } + + while ( (file = readdir(dir)) ) { + QString fn = QFile::decodeName(file->d_name); + fi.setFile( *this, fn ); + if ( !match( filters, fn ) && !(allDirs && fi.isDir()) ) + continue; + if ( (doDirs && fi.isDir()) || (doFiles && fi.isFile()) ) { + if ( noSymLinks && fi.isSymLink() ) + continue; + if ( (filterSpec & RWEMask) != 0 ) + if ( (doReadable && !fi.isReadable()) || + (doWritable && !fi.isWritable()) || + (doExecable && !fi.isExecutable()) ) + continue; + if ( !doHidden && fn[0] == '.' && + fn != QString::fromLatin1(".") + && fn != QString::fromLatin1("..") ) + continue; + fiList->append( new QFileInfo( fi ) ); + } + } + if ( closedir(dir) != 0 ) { +#if defined(CHECK_NULL) + qWarning( "QDir::readDirEntries: Cannot close the directory: %s", + dPath.local8Bit().data() ); +#endif + } + + // Sort... + if(fiList->count()) { + QDirSortItem* si= new QDirSortItem[fiList->count()]; + QFileInfo* itm; + i=0; + for (itm = fiList->first(); itm; itm = fiList->next()) + si[i++].item = itm; + qt_cmp_si_sortSpec = sortSpec; + qsort( si, i, sizeof(si[0]), qt_cmp_si ); + // put them back in the list + fiList->setAutoDelete( FALSE ); + fiList->clear(); + int j; + for ( j=0; j<i; j++ ) { + fiList->append( si[j].item ); + fList->append( si[j].item->fileName() ); + } + delete [] si; + fiList->setAutoDelete( TRUE ); + } + + if ( filterSpec == (FilterSpec)filtS && sortSpec == (SortSpec)sortS && + nameFilter == nameFilt ) + dirty = FALSE; + else + dirty = TRUE; + return TRUE; +} + +const QFileInfoList * QDir::drives() +{ + // at most one instance of QFileInfoList is leaked, and this variable + // points to that list + static QFileInfoList * knownMemoryLeak = 0; + + if ( !knownMemoryLeak ) { + knownMemoryLeak = new QFileInfoList; + // non-win32 versions both use just one root directory + knownMemoryLeak->append( new QFileInfo( rootDirPath() ) ); + } + + return knownMemoryLeak; +} +#endif //QT_NO_DIR diff --git a/trunk/qtools/qdir_win32.cpp b/trunk/qtools/qdir_win32.cpp new file mode 100644 index 0000000..b1eee66 --- /dev/null +++ b/trunk/qtools/qdir_win32.cpp @@ -0,0 +1,406 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2001 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + * Based on qdir_unix.cpp + * + * Copyright (C) 1992-2000 Trolltech AS. + */ + + +#include "qglobal.h" + +#include "qdir.h" +#ifndef QT_NO_DIR + + +#include "qfileinfo.h" +#include "qfiledefs_p.h" +#include "qregexp.h" +#include "qstringlist.h" +#include <stdlib.h> +#include <ctype.h> +#if defined(_OS_WIN32_) +#if defined(_CC_BOOL_DEF_) +#undef bool +#include <windows.h> +#define bool int +#else +#include <windows.h> +#endif +#endif +#if defined(_OS_OS2EMX_) +extern Q_UINT32 DosQueryCurrentDisk(Q_UINT32*,Q_UINT32*); +#define NO_ERROR 0 +#endif + +extern QStringList qt_makeFilterList( const QString &filter ); + +extern int qt_cmp_si_sortSpec; + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +extern int qt_cmp_si( const void *, const void * ); + +#if defined(Q_C_CALLBACKS) +} +#endif + + +void QDir::slashify( QString& n ) +{ + for ( int i=0; i<(int)n.length(); i++ ) + { + if ( n[i] == '\\' ) + n[i] = '/'; + } +} + +QString QDir::homeDirPath() +{ + QString d; + d = QFile::decodeName(getenv("HOME")); + slashify( d ); + if ( d.isNull() ) + d = rootDirPath(); + return d; +} + +QString QDir::canonicalPath() const +{ + QString r; + + char cur[PATH_MAX]; + char tmp[PATH_MAX]; + GETCWD( cur, PATH_MAX ); + if ( CHDIR(QFile::encodeName(dPath)) >= 0 ) { + GETCWD( tmp, PATH_MAX ); + r = QFile::decodeName(tmp); + } + CHDIR( cur ); + + slashify( r ); + return r; +} + +bool QDir::mkdir( const QString &dirName, bool acceptAbsPath ) const +{ +#if defined(__CYGWIN32_) + return MKDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)), 0777 ) + == 0; +#else + return MKDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)) ) == 0; + +#endif +} + +bool QDir::rmdir( const QString &dirName, bool acceptAbsPath ) const +{ + return RMDIR( QFile::encodeName(filePath(dirName,acceptAbsPath)) ) == 0; +} + +bool QDir::isReadable() const +{ + return ACCESS( QFile::encodeName(dPath), R_OK ) == 0; +} + +bool QDir::isRoot() const +{ + return dPath == QString::fromLatin1("/"); +} + +bool QDir::rename( const QString &name, const QString &newName, + bool acceptAbsPaths ) +{ + if ( name.isEmpty() || newName.isEmpty() ) { +#if defined(CHECK_NULL) + qWarning( "QDir::rename: Empty or null file name(s)" ); +#endif + return FALSE; + } + QString fn1 = filePath( name, acceptAbsPaths ); + QString fn2 = filePath( newName, acceptAbsPaths ); + return ::rename( QFile::encodeName(fn1), + QFile::encodeName(fn2) ) == 0; +} + +bool QDir::setCurrent( const QString &path ) +{ + int r; + r = CHDIR( QFile::encodeName(path) ); + return r >= 0; +} + +QString QDir::currentDirPath() +{ + QString result; + + STATBUF st; + if ( STAT( ".", &st ) == 0 ) { + char currentName[PATH_MAX]; + if ( GETCWD( currentName, PATH_MAX ) != 0 ) + result = QFile::decodeName(currentName); +#if defined(DEBUG) + if ( result.isNull() ) + qWarning( "QDir::currentDirPath: getcwd() failed" ); +#endif + } else { +#if defined(DEBUG) + qWarning( "QDir::currentDirPath: stat(\".\") failed" ); +#endif + } + slashify( result ); + return result; +} + +QString QDir::rootDirPath() +{ + QString d = QString::fromLatin1( "/" ); + return d; +} + +bool QDir::isRelativePath( const QString &path ) +{ + int len = path.length(); + if ( len == 0 ) + return TRUE; + int i = 0; + if ( isalpha(path[0]) && path[1] == ':' ) // drive, e.g. a: + i = 2; + return path[i] != '/' && path[i] != '\\'; +} + +#undef IS_SUBDIR +#undef IS_RDONLY +#undef IS_ARCH +#undef IS_HIDDEN +#undef IS_SYSTEM +#undef FF_GETFIRST +#undef FF_GETNEXT +#undef FF_ERROR + +#if defined(_OS_WIN32_) +#define IS_SUBDIR FILE_ATTRIBUTE_DIRECTORY +#define IS_RDONLY FILE_ATTRIBUTE_READONLY +#define IS_ARCH FILE_ATTRIBUTE_ARCHIVE +#define IS_HIDDEN FILE_ATTRIBUTE_HIDDEN +#define IS_SYSTEM FILE_ATTRIBUTE_SYSTEM +#define FF_GETFIRST FindFirstFile +#define FF_GETNEXT FindNextFile +#define FF_ERROR INVALID_HANDLE_VALUE +#else +#define IS_SUBDIR _A_SUBDIR +#define IS_RDONLY _A_RDONLY +#define IS_ARCH _A_ARCH +#define IS_HIDDEN _A_HIDDEN +#define IS_SYSTEM _A_SYSTEM +#define FF_GETFIRST _findfirst +#define FF_GETNEXT _findnext +#define FF_ERROR -1 +#endif + + +bool QDir::readDirEntries( const QString &nameFilter, + int filterSpec, int sortSpec ) +{ + int i; + if ( !fList ) { + fList = new QStringList; + CHECK_PTR( fList ); + fiList = new QFileInfoList; + CHECK_PTR( fiList ); + fiList->setAutoDelete( TRUE ); + } else { + fList->clear(); + fiList->clear(); + } + + QStringList filters = qt_makeFilterList( nameFilter ); + + bool doDirs = (filterSpec & Dirs) != 0; + bool doFiles = (filterSpec & Files) != 0; + bool noSymLinks = (filterSpec & NoSymLinks) != 0; + bool doReadable = (filterSpec & Readable) != 0; + bool doWritable = (filterSpec & Writable) != 0; + bool doExecable = (filterSpec & Executable) != 0; + bool doHidden = (filterSpec & Hidden) != 0; + // show hidden files if the user asks explicitly for e.g. .* + if ( !doHidden && !nameFilter.isEmpty() && nameFilter[0] == '.' ) + doHidden = TRUE; + bool doModified = (filterSpec & Modified) != 0; + bool doSystem = (filterSpec & System) != 0; + + QRegExp wc( nameFilter, FALSE, TRUE ); // wild card, case insensitive + bool first = TRUE; + QString p = dPath.copy(); + int plen = p.length(); +#if defined(_OS_WIN32_) + HANDLE ff; + WIN32_FIND_DATA finfo; +#else + long ff; + _finddata_t finfo; +#endif + QFileInfo fi; + if ( plen == 0 ) + { +#if defined(CHECK_NULL) + warning( "QDir::readDirEntries: No directory name specified" ); +#endif + return FALSE; + } + if ( p.at(plen-1) != '/' && p.at(plen-1) != '\\' ) + p += '/'; + p += "*.*"; + + ff = FF_GETFIRST( p.data(), &finfo ); + if ( ff == FF_ERROR ) + { +#if defined(DEBUG) + warning( "QDir::readDirEntries: Cannot read the directory: %s", + (const char *)dPath ); +#endif + return FALSE; + } + + while ( TRUE ) + { + if ( first ) + first = FALSE; + else + { +#if defined(_OS_WIN32_) + if ( !FF_GETNEXT(ff,&finfo) ) + break; +#else + if ( FF_GETNEXT(ff,&finfo) == -1 ) + break; +#endif + } +#if defined(_OS_WIN32_) + int attrib = finfo.dwFileAttributes; +#else + int attrib = finfo.attrib; +#endif + bool isDir = (attrib & IS_SUBDIR) != 0; + bool isFile = !isDir; + bool isSymLink = FALSE; + bool isReadable = TRUE; + bool isWritable = (attrib & IS_RDONLY) == 0; + bool isExecable = FALSE; + bool isModified = (attrib & IS_ARCH) != 0; + bool isHidden = (attrib & IS_HIDDEN) != 0; + bool isSystem = (attrib & IS_SYSTEM) != 0; + +#if defined(_OS_WIN32_) + const char *fname = finfo.cFileName; +#else + const char *fname = finfo.name; +#endif + if ( wc.match(fname) == -1 && !(allDirs && isDir) ) + continue; + + QString name = fname; + if ( doExecable ) + { + QString ext = name.right(4).lower(); + if ( ext == ".exe" || ext == ".com" || ext == ".bat" || + ext == ".pif" || ext == ".cmd" ) + isExecable = TRUE; + } + + if ( (doDirs && isDir) || (doFiles && isFile) ) + { + if ( noSymLinks && isSymLink ) + continue; + if ( (filterSpec & RWEMask) != 0 ) + if ( (doReadable && !isReadable) || + (doWritable && !isWritable) || + (doExecable && !isExecable) ) + continue; + if ( doModified && !isModified ) + continue; + if ( !doHidden && isHidden ) + continue; + if ( !doSystem && isSystem ) + continue; + fi.setFile( *this, name ); + fiList->append( new QFileInfo( fi ) ); + } + } +#if defined(_OS_WIN32_) + FindClose( ff ); +#else + _findclose( ff ); +#endif + + // Sort... + QDirSortItem* si= new QDirSortItem[fiList->count()]; + QFileInfo* itm; + i=0; + for (itm = fiList->first(); itm; itm = fiList->next()) + si[i++].item = itm; + qt_cmp_si_sortSpec = sortSpec; + qsort( si, i, sizeof(si[0]), qt_cmp_si ); + // put them back in the list + fiList->setAutoDelete( FALSE ); + fiList->clear(); + int j; + for ( j=0; j<i; j++ ) { + fiList->append( si[j].item ); + fList->append( si[j].item->fileName() ); + } + delete [] si; + fiList->setAutoDelete( TRUE ); + + if ( filterSpec == (FilterSpec)filtS && sortSpec == (SortSpec)sortS && + nameFilter == nameFilt ) + dirty = FALSE; + else + dirty = TRUE; + return TRUE; +} + +const QFileInfoList * QDir::drives() +{ + // at most one instance of QFileInfoList is leaked, and this variable + // points to that list + static QFileInfoList * knownMemoryLeak = 0; + + if ( !knownMemoryLeak ) { + knownMemoryLeak = new QFileInfoList; + +#if defined(_OS_WIN32_) + Q_UINT32 driveBits = (Q_UINT32) GetLogicalDrives() & 0x3ffffff; +#elif defined(_OS_OS2EMX_) + Q_UINT32 driveBits, cur; + if (DosQueryCurrentDisk(&cur,&driveBits) != NO_ERROR) + exit(1); + driveBits &= 0x3ffffff; +#endif + char driveName[4]; + qstrcpy( driveName, "a:/" ); + while( driveBits ) { + if ( driveBits & 1 ) + knownMemoryLeak->append( new QFileInfo( driveName ) ); + driveName[0]++; + driveBits = driveBits >> 1; + } + } + + return knownMemoryLeak; +} +#endif //QT_NO_DIR diff --git a/trunk/qtools/qfeatures.h b/trunk/qtools/qfeatures.h new file mode 100644 index 0000000..84fa715 --- /dev/null +++ b/trunk/qtools/qfeatures.h @@ -0,0 +1,978 @@ +/**************************************************************************** +** +** +** Global feature selection +** +** Created : 000417 +** +** Copyright (C) 2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QFEATURES_H +#define QFEATURES_H + +/*! \page features....html + ... +*/ + +// Qt ships with a number of pre-defined configurations. If none suit +// your needs, define QCONFIG_LOCAL and create a "qconfig-local.h" file. +// +// Note that disabling some features will produce a libqt that is not +// compatible with other libqt builds. Such modifications are only +// supported on Qt/Embedded where reducing the library size is important +// and where the application-suite is often a fixed set. +// +#if defined(QCONFIG_LOCAL) +#include <qconfig-local.h> +#elif defined(QCONFIG_MINIMAL) +#include <qconfig-minimal.h> +#elif defined(QCONFIG_SMALL) +#include <qconfig-small.h> +#elif defined(QCONFIG_MEDIUM) +#include <qconfig-medium.h> +#elif defined(QCONFIG_LARGE) +#include <qconfig-large.h> +#else // everything... +#include <qconfig.h> +#endif + + +// Data structures +/*! + QStringList +*/ +//#define QT_NO_STRINGLIST + +#if defined(QT_NO_IMAGE_SMOOTHSCALE) +/*! + QIconSet +*/ +# define QT_NO_ICONSET +#endif + +// File I/O +#if defined(QT_NO_STRINGLIST) + /*! + QDir + */ +# define QT_NO_DIR +#endif + +/*! + Palettes +*/ +//#define QT_NO_PALETTE + +/*! + QTextStream +*/ +//#define QT_NO_TEXTSTREAM +/*! + QDataStream +*/ +//#define QT_NO_DATASTREAM + +/*! + Dynamic module linking +*/ +//#define QT_NO_PLUGIN + + +// Images +/*! + BMP image I/O + <p>The Windows Bitmap (BMP) image format is common on MS-Windows. + <p>This is an uncompressed image format + offering few advantages over PNG or JPEG. +*/ +#if defined(QT_NO_DATASTREAM) +# define QT_NO_IMAGEIO_BMP +#endif +/*! + PPM image I/O + <p>The Portable PixMap (PPM) image format is common on Unix. + <p>This is an uncompressed image format + offering few advantages over PNG or JPEG. +*/ +//#define QT_NO_IMAGEIO_PPM +/*! + XBM image I/O + <p>The X11 BitMap (XBM) image format is common on X11. + <p>This is an uncompressed monochrome image format. + Qt uses this format for some internal images (eg. mouse cursors). +*/ +//#define QT_NO_IMAGEIO_XBM +/*! + XPM image I/O + <p>The X11 PixMap (XPM) image format is common on X11. + <p>This is an uncompressed image format. + XPM images have the small advantage that they can be trivially + included in source files as they are C code. + Qt uses this format for some internal images (eg. QMessageBox icons). +*/ +#if defined(QT_NO_TEXTSTREAM) +# define QT_NO_IMAGEIO_XPM +#endif +/*! + PNG image I/O + <p>The Portable Network Graphics (PNG) is a compressed image format. + <p>See <a href=http://www.libpng.org/pub/png/>The PNG Home Site</a> for + details of the format. +*/ +//#define QT_NO_IMAGEIO_PNG +/*! + MNG image I/O + <p>The Multiple-image Network Graphics (MNG) is a compressed animation format. + <p>See <a href=http://www.libpng.org/pub/mng/>The MNG Home Site</a> for + details of the format. +*/ +//#define QT_NO_IMAGEIO_MNG +/*! + JPEG image I/O + <p>The Joint Photographic Experts Group (JPEG) is a compressed lossy image format that gives high compression + for real-world and photo-realistic images. +*/ +//#define QT_NO_IMAGEIO_JPEG + +/*! + Asynchronous I/O + <p>Allows push-driven data processing. +*/ +//#define QT_NO_ASYNC_IO +/*! + Asynchronous image I/O + <p>Allows push-driven images. +*/ +//#define QT_NO_ASYNC_IMAGE_IO +#if defined(QT_NO_ASYNC_IO) || defined(QT_NO_ASYNC_IMAGE_IO) + /*! + Animated images + <p>This includes animated GIFs. + <p><b>Note: this currently also requires <tt>QT_BUILTIN_GIF_READER</tt> to + be defined when building Qt.</b> + */ +# define QT_NO_MOVIE +#endif + +// Fonts +/*! + TrueType font files + <p>Scalable font format common on MS-Windows and becoming common on Unix. + <p>Only supported on Qt/Embedded. +*/ +//#define QT_NO_TRUETYPE +/*! + BDF font files + <p>The Bitmap Distribution Format (BDF) font file format, common + on Unix. + <p>Only supported on Qt/Embedded. +*/ +#if defined(QT_NO_TEXTSTREAM) || defined(QT_NO_STRINGLIST) +# define QT_NO_BDF +#endif +/*! + QFontDatabase +*/ +#if defined(QT_NO_STRINGLIST) +# define QT_NO_FONTDATABASE +#endif + +// Internationalization + +/*! + QObject::tr() +*/ +#if defined(QT_NO_DATASTREAM) +# define QT_NO_TRANSLATION +#endif + +/*! + QTextCodec class and subclasses +*/ +//#define QT_NO_TEXTCODEC + +#if defined(QT_NO_TEXTCODEC) + /*! + QTextCodec classes + <p>This includes some large conversion tables. + */ +# define QT_NO_CODECS +#endif +#if defined(QT_LITE_UNICODE) + /*! + Unicode property tables + <p>These include some large tables. + */ +# define QT_NO_UNICODETABLES +#endif + +/*! + MIME +*/ +#if defined(QT_NO_DIR) +# define QT_NO_MIME +#endif +#if defined(QT_NO_MIME) || defined(QT_NO_TEXTSTREAM) || defined(QT_NO_DRAWUTIL) || defined(QT_NO_IMAGE_SMOOTHSCALE) + /*! + RichText (HTML) display + */ +# define QT_NO_RICHTEXT +#endif + +/*! + XML +*/ +#if defined(QT_NO_STRINGLIST) || defined(QT_NO_TEXTSTREAM) || defined(QT_NO_TEXTCODEC) +# define QT_NO_XML +#endif + +/*! + Document Object Model +*/ +#if defined(QT_NO_XML) || defined(QT_NO_MIME) +# define QT_NO_DOM +#endif + +// Sound +/*! + Playing sounds +*/ +//#define QT_NO_SOUND + +/*! + Properties +*/ +#if defined(QT_NO_STRINGLIST) || defined(QT_NO_ICONSET) +# define QT_NO_PROPERTIES +#endif + + + +// Networking + +/*! + Network support +*/ +//#define QT_NO_NETWORK + +#if defined(QT_NO_NETWORK) || defined(QT_NO_STRINGLIST) || defined(QT_NO_TEXTSTREAM) + /*! + DNS + */ +# define QT_NO_DNS +#endif +/*! + Network file access +*/ +#if defined(QT_NO_NETWORK) || defined(QT_NO_DIR) || defined(QT_NO_STRINGLIST) +# define QT_NO_NETWORKPROTOCOL +#endif +#if defined(QT_NO_NETWORKPROTOCOL) || defined(QT_NO_DNS) + /*! + FTP file access + */ +# define QT_NO_NETWORKPROTOCOL_FTP + /*! + HTTP file access + */ +# define QT_NO_NETWORKPROTOCOL_HTTP +#endif + +/*! + External process invocation. +*/ +//#define QT_NO_PROCESS + + +// Qt/Embedded-specific + +#if defined(QT_NO_NETWORK) + /*! + Multi-process support. + */ +# define QT_NO_QWS_MULTIPROCESS +#endif + +#if defined(QT_NO_QWS_MULTIPROCESS) || defined(QT_NO_DATASTREAM) + /*! + Palmtop Communication Protocol + */ +# define QT_NO_COP +#endif + +/*! + Console keyboard support +*/ +//#define QT_NO_QWS_KEYBOARD + +/*! + Visible cursor +*/ +#if defined(QT_NO_CURSOR) +# define QT_NO_QWS_CURSOR +#endif + +/*! + Alpha-blended cursor +*/ +//#define QT_NO_QWS_ALPHA_CURSOR +/*! + Mach64 acceleration +*/ +//#define QT_NO_QWS_MACH64 +/*! + Voodoo3 acceleration +*/ +//#define QT_NO_QWS_VOODOO3 +/*! + Matrox MGA acceleration (Millennium/Millennium II/Mystique/G200/G400) +*/ +//#define QT_NO_QWS_MATROX +/*! + Virtual frame buffer +*/ + +//#define QT_NO_QWS_VFB +/*! + Transformed frame buffer +*/ +//#define QT_NO_QWS_TRANSFORMED +#if defined(QT_NO_NETWORK) +/*! + Remote frame buffer (VNC) +*/ +# ifndef QT_NO_QWS_VNC +# define QT_NO_QWS_VNC +# endif +#endif +/*! + 1-bit monochrome +*/ +//#define QT_NO_QWS_DEPTH_1 +/*! + 4-bit greyscale +*/ +//#define QT_NO_QWS_DEPTH_4 +/*! + 4-bit VGA +*/ +//#define QT_NO_QWS_VGA_16 +/*! + SVGALib Support + Not implemented yet +*/ +#define QT_NO_QWS_SVGALIB +/*! + 8-bit grayscale +*/ +#define QT_NO_QWS_DEPTH_8GRAYSCALE +/*! + 8-bit color +*/ +//#define QT_NO_QWS_DEPTH_8 +/*! + 15 or 16-bit color (define QT_QWS_DEPTH16_RGB as 555 for 15-bit) +*/ +//#define QT_NO_QWS_DEPTH_16 +/*! + 24-bit color +*/ +//#define QT_NO_QWS_DEPTH_24 +/*! + 32-bit color +*/ +//#define QT_NO_QWS_DEPTH_32 + +/*! + Window Manager +*/ +//#define QT_NO_QWS_MANAGER + +/*! + Window Manager Styles +*/ +#define QT_NO_QWS_KDE2_WM_STYLE +#if defined( QT_NO_QWS_MANAGER ) || defined( QT_NO_IMAGEIO_XPM ) +# define QT_NO_QWS_AQUA_WM_STYLE +# define QT_NO_QWS_BEOS_WM_STYLE +# define QT_NO_QWS_KDE_WM_STYLE +# define QT_NO_QWS_QPE_WM_STYLE +# define QT_NO_QWS_WINDOWS_WM_STYLE +#endif + +/*! + Saving of fonts +*/ +//#define QT_NO_QWS_SAVEFONTS + +/*! + Favour code size over graphics speed + <p>Smaller, slower code will be used for drawing operations. + <p>Only supported on Qt/Embedded. +*/ +//#define QT_NO_QWS_GFX_SPEED + +/*! + Qt/Embedded window system properties. +*/ +//#define QT_NO_QWS_PROPERTIES + +#if defined(QT_NO_QWS_PROPERTIES) || defined(QT_NO_MIME) + /*! + Cut and paste + */ +# define QT_NO_CLIPBOARD +#endif + +#if defined(QT_NO_MIME) || defined(QT_NO_QWS_PROPERTIES) + /*! + Drag and drop + */ +# define QT_NO_DRAGANDDROP +#endif + +#if defined(QT_NO_PROPERTIES) + /*! + SQL + */ +# define QT_NO_SQL +#endif + +#if defined(QT_NO_CLIPBOARD) || defined(QT_NO_MIME) || defined(_WS_QWS_) + /*! + Cut and paste of complex data types (non-text) + Not yet implemented for QWS. + */ +# define QT_NO_MIMECLIPBOARD +#endif + + +/*! + Drawing utility functions +*/ +//#define QT_NO_DRAWUTIL +/*! + TrueColor QImage +*/ +//#define QT_NO_IMAGE_TRUECOLOR +/*! + Smooth QImage scaling +*/ +//#define QT_NO_IMAGE_SMOOTHSCALE +/*! + Image file text strings +*/ +#if defined(QT_NO_STRINGLIST) +# define QT_NO_IMAGE_TEXT +#endif + +#if defined(QT_NO_IMAGE_TRUECOLOR) + /*! + 16-bit QImage + */ +# define QT_NO_IMAGE_16_BIT +#endif +/*! + Cursors +*/ +//#define QT_NO_CURSOR + +// Painting +/*! + Named colors +*/ +//#define QT_NO_COLORNAMES +/*! + Scaling and rotation +*/ +//#define QT_NO_TRANSFORMATIONS + +/*! + Printing +*/ +#if defined(QT_NO_TEXTSTREAM) +# define QT_NO_PRINTER +#endif + +/*! + QPicture +*/ +#if defined(QT_NO_DATASTREAM) +# define QT_NO_PICTURE +#endif + +// Layout +/*! + Automatic widget layout +*/ +//#define QT_NO_LAYOUT + +// Widgets +#if defined(QT_NO_DRAWUTIL) || defined(QT_NO_PALETTE) +/*! + QStyle +*/ +# define QT_NO_STYLE +#endif + + +/*! + Dialogs +*/ +//#define QT_NO_DIALOG +/*! + Semi-modal dialogs +*/ +//#define QT_NO_SEMIMODAL +/*! + Framed widgets +*/ +//#define QT_NO_FRAME + +/*! + Special widget effects (fading, scrolling) +*/ +//#define QT_NO_EFFECTS + + +/*! + QLabel +*/ +#ifdef QT_NO_FRAME +# define QT_NO_LABEL +#endif + +/*! + Toolbars +*/ +#ifdef QT_NO_LAYOUT +# define QT_NO_TOOLBAR +#endif + +/*! + Buttons +*/ +#if defined(QT_NO_BUTTON) || defined(QT_NO_STYLE) +/*! + Check-boxes +*/ +# define QT_NO_CHECKBOX +/*! + Radio-buttons +*/ +# define QT_NO_RADIOBUTTON +#endif +#if defined(QT_NO_BUTTON) || defined(QT_NO_TOOLBAR) || defined(QT_NO_ICONSET) +/*! + Tool-buttons +*/ +# define QT_NO_TOOLBUTTON +#endif +/*! + Grid layout widgets +*/ +#ifdef QT_NO_FRAME +# define QT_NO_GRID +#endif +/*! + Group boxes +*/ +#ifdef QT_NO_FRAME +# define QT_NO_GROUPBOX +#endif +#if defined(QT_NO_GROUPBOX) +/*! + Button groups +*/ +# define QT_NO_BUTTONGROUP +/*! + Horizontal group boxes +*/ +# define QT_NO_HGROUPBOX +#endif +#if defined(QT_NO_HGROUPBOX) +/*! + Vertical group boxes +*/ +# define QT_NO_VGROUPBOX +#endif +#if defined(QT_NO_BUTTONGROUP) +/*! + Horizontal button groups +*/ +# define QT_NO_HBUTTONGROUP +#endif +#if defined(QT_NO_HBUTTONGROUP) +/*! + Vertical button groups +*/ +# define QT_NO_VBUTTONGROUP +#endif +/*! + Horizonal box layout widgets +*/ +#ifdef QT_NO_FRAME +# define QT_NO_HBOX +#endif +#if defined(QT_NO_HBOX) +/*! + Vertical box layout widgets +*/ +# define QT_NO_VBOX +#endif +/*! + Single-line edits +*/ +#if defined(QT_NO_PALETTE) +# define QT_NO_LINEEDIT +#endif +#if defined(QT_NO_TOOLBAR) +/*! + Main-windows +*/ +# define QT_NO_MAINWINDOW +#endif +#if defined(QT_NO_ICONSET) +/*! + Menu-like widgets +*/ +# define QT_NO_MENUDATA +#endif +#if defined(QT_NO_MENUDATA) +/*! + Popup-menus +*/ +# define QT_NO_POPUPMENU +/*! + Menu bars +*/ +# define QT_NO_MENUBAR +#endif +#if defined(QT_NO_BUTTON) || defined(QT_NO_ICONSET) || defined(QT_NO_POPUPMENU) +/*! + Push-buttons +*/ +# define QT_NO_PUSHBUTTON +#endif +/*! + Progress bars +*/ +#ifdef QT_NO_FRAME +# define QT_NO_PROGRESSBAR +#endif +/*! + Range-control widgets +*/ +//#define QT_NO_RANGECONTROL +#if defined(QT_NO_RANGECONTROL) || defined(QT_NO_STYLE) +/*! + Scroll bars +*/ +# define QT_NO_SCROLLBAR +/*! + Sliders +*/ +# define QT_NO_SLIDER +/*! + Spin boxes +*/ +# define QT_NO_SPINBOX +/*! + Dials +*/ +# define QT_NO_DIAL +#endif + + +#if defined(QT_NO_SCROLLBAR) || defined(QT_NO_FRAME) +/*! + Scrollable view widgets +*/ +# define QT_NO_SCROLLVIEW +#endif +#if defined(QT_NO_SCROLLVIEW) +/*! + QCanvas +*/ +# define QT_NO_CANVAS +/*! + QIconView +*/ +# define QT_NO_ICONVIEW +#endif + +#if defined(QT_NO_SCROLLBAR) +/*! + Table-like widgets +*/ +# define QT_NO_TABLEVIEW +#endif +#if defined(QT_NO_TABLEVIEW) +/*! + Multi-line edits +*/ +# define QT_NO_MULTILINEEDIT +#endif + +/*! + Splitters +*/ +#ifdef QT_NO_FRAME +# define QT_NO_SPLITTER +#endif +/*! + Status bars +*/ +#ifdef QT_NO_LAYOUT +# define QT_NO_STATUSBAR +#endif +/*! + Tab-bars +*/ +#if defined(QT_NO_ICONSET) +# define QT_NO_TABBAR +#endif +#if defined(QT_NO_TABBAR) +/*! + Tab widgets +*/ +# define QT_NO_TABWIDGET +#endif +/*! + Tool tips +*/ +#if defined( QT_NO_LABEL ) || defined( QT_NO_PALETTE ) +# define QT_NO_TOOLTIP +#endif +/*! + Input validators +*/ +//#define QT_NO_VALIDATOR +/*! + "What's this" help +*/ +#if defined( QT_NO_TOOLTIP ) +# define QT_NO_WHATSTHIS +#endif +/*! + Widget stacks +*/ +#ifdef QT_NO_FRAME +# define QT_NO_WIDGETSTACK +#endif + +#if defined(QT_NO_RICHTEXT) || defined(QT_NO_SCROLLVIEW) + /*! + QTextView + */ +# define QT_NO_TEXTVIEW +#endif + +#if defined(QT_NO_TEXTVIEW) + /*! + QTextBrowser + */ +# define QT_NO_TEXTBROWSER +#endif + +#if defined(QT_NO_STYLE) + /*! + Windows style + */ +# define QT_NO_STYLE_WINDOWS + /*! + Motif style + */ +# define QT_NO_STYLE_MOTIF +#endif + +#if defined(QT_NO_STYLE_MOTIF) + /*! + Motif-plus style + */ +# define QT_NO_STYLE_MOTIFPLUS +#endif + + +#if defined(QT_NO_SCROLLVIEW) || defined(QT_NO_STRINGLIST) + /*! + QListBox + */ +# define QT_NO_LISTBOX +#endif + +/*! + QAccel +*/ +//#define QT_NO_ACCEL + +/*! + QSizeGrip +*/ +#ifdef QT_NO_PALETTE +# define QT_NO_SIZEGRIP +#endif +/*! + QHeader +*/ +#ifdef QT_NO_ICONSET +# define QT_NO_HEADER +#endif +/*! + QWorkSpace +*/ +#ifdef QT_NO_FRAME +# define QT_NO_WORKSPACE +#endif +/*! + QLCDNumber +*/ +#ifdef QT_NO_FRAME +# define QT_NO_LCDNUMBER +#endif +/*! + QAction +*/ +//#define QT_NO_ACTION + +#if defined(QT_NO_HEADER) + /*! + QTable + */ +# define QT_NO_TABLE +#endif + +#if defined(QT_NO_LISTBOX) + /*! + QComboBox + */ +# define QT_NO_COMBOBOX +#endif + +#if defined(QT_NO_HEADER) || defined(QT_NO_SCROLLVIEW) + /*! + QListView + */ +# define QT_NO_LISTVIEW +#endif + +#if defined(QT_NO_STYLE_WINDOWS) + /*! + Compact Windows style + */ +# define QT_NO_STYLE_COMPACT +#endif + +#if defined(QT_NO_STYLE_MOTIF) || defined(QT_NO_TRANSFORMATIONS) + /*! + CDE style + */ +# define QT_NO_STYLE_CDE + /*! + SGI style + */ +# define QT_NO_STYLE_SGI +#endif +#if defined(QT_NO_STYLE_WINDOWS) + /*! + Platinum style + */ +# define QT_NO_STYLE_PLATINUM +#endif + +/*! + QColorDialog +*/ +#if defined(QT_NO_LAYOUT) || defined(QT_NO_LABEL) || defined(QT_NO_PUSHBUTTON) || defined(QT_NO_DIALOG) +# define QT_NO_COLORDIALOG +#endif +#if defined(QT_NO_DIALOG) +/*! + QMessageBox +*/ +# define QT_NO_MESSAGEBOX +#endif +#if defined(QT_NO_DIALOG) || defined(QT_NO_TABBAR) +/*! + QTabDialog +*/ +#define QT_NO_TABDIALOG +#endif + +#if defined(QT_NO_DIALOG) +/*! + QWizard +*/ +# define QT_NO_WIZARD +#endif + +#if defined(QT_NO_DIALOG) || defined(QT_NO_LISTVIEW) || defined(QT_NO_NETWORKPROTOCOL) || defined(QT_NO_COMBOBOX) || defined(QT_NO_DIR) || defined(QT_NO_MESSAGEBOX) || defined(QT_NO_SEMIMODAL) + /*! + QFileDialog + */ +# define QT_NO_FILEDIALOG +#endif + +#if defined(QT_NO_DIALOG) || defined(QT_NO_FONTDATABASE) || defined(QT_NO_COMBOBOX) + /*! + QFontDialog + */ +# define QT_NO_FONTDIALOG +#endif + +#if defined(QT_NO_DIALOG) || defined(QT_NO_LISTVIEW) || defined(QT_NO_PRINTER) || defined(QT_NO_COMBOBOX) || defined(QT_NO_DIR) || defined(QT_NO_LAYOUT) || defined(QT_NO_LABEL) + /*! + QPrintDialog + */ +# define QT_NO_PRINTDIALOG +#endif + +#if defined(QT_NO_SEMIMODAL) + /*! + QProgressDialog + */ +# define QT_NO_PROGRESSDIALOG +#endif +#if defined(QT_NO_DIALOG) || defined(QT_NO_COMBOBOX) + /*! + QInputDialog + */ +# define QT_NO_INPUTDIALOG +#endif + +#if defined(QT_NO_STRINGLIST) + /*! + Session management support + */ +# define QT_NO_SESSIONMANAGER +#endif + +#endif // QFEATURES_H diff --git a/trunk/qtools/qfile.cpp b/trunk/qtools/qfile.cpp new file mode 100644 index 0000000..98ed9a3 --- /dev/null +++ b/trunk/qtools/qfile.cpp @@ -0,0 +1,550 @@ +/**************************************************************************** +** +** +** Implementation of QFile class +** +** Created : 930812 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" +#if defined(_OS_WIN32_) +#ifdef UNICODE +#ifndef _UNICODE +#define _UNICODE +#endif +#endif +#endif + +#include "qfile.h" +#include "qfiledefs_p.h" + +extern bool qt_file_access( const QString& fn, int t ); + +// NOT REVISED +/*! + \class QFile qfile.h + \brief The QFile class is an I/O device that operates on files. + + \ingroup io + + QFile is an I/O device for reading and writing binary and text files. A + QFile may be used by itself (readBlock and writeBlock) or by more + conveniently using QDataStream or QTextStream. + + Here is a code fragment that uses QTextStream to read a text + file line by line. It prints each line with a line number. + \code + QFile f("file.txt"); + if ( f.open(IO_ReadOnly) ) { // file opened successfully + QTextStream t( &f ); // use a text stream + QString s; + int n = 1; + while ( !t.eof() ) { // until end of file... + s = t.readLine(); // line of text excluding '\n' + printf( "%3d: %s\n", n++, (const char *)s ); + } + f.close(); + } + \endcode + + The QFileInfo class holds detailed information about a file, such as + access permissions, file dates and file types. + + The QDir class manages directories and lists of file names. + + \sa QDataStream, QTextStream +*/ + + +/*! + Constructs a QFile with no name. +*/ + +QFile::QFile() +{ + init(); +} + +/*! + Constructs a QFile with a file name \e name. + \sa setName() +*/ + +QFile::QFile( const QString &name ) + : fn(name) +{ + init(); +} + + +/*! + Destructs a QFile. Calls close(). +*/ + +QFile::~QFile() +{ + close(); +} + + +/*! + \internal + Initialize internal data. +*/ + +void QFile::init() +{ + setFlags( IO_Direct ); + setStatus( IO_Ok ); + fh = 0; + fd = 0; + length = 0; + ioIndex = 0; + ext_f = FALSE; // not an external file handle +} + + +/*! + \fn QString QFile::name() const + Returns the name set by setName(). + \sa setName(), QFileInfo::fileName() +*/ + +/*! + Sets the name of the file. The name can include an absolute directory + path or it can be a name or a path relative to the current directory. + + Do not call this function if the file has already been opened. + + Note that if the name is relative QFile does not associate it with the + current directory. If you change directory before calling open(), open + uses the new current directory. + + Example: + \code + QFile f; + QDir::setCurrent( "/tmp" ); + f.setName( "readme.txt" ); + QDir::setCurrent( "/home" ); + f.open( IO_ReadOnly ); // opens "/home/readme.txt" under UNIX + \endcode + + Also note that the directory separator '/' works for all operating + systems supported by Qt. + + \sa name(), QFileInfo, QDir +*/ + +void QFile::setName( const QString &name ) +{ + if ( isOpen() ) { +#if defined(CHECK_STATE) + qWarning( "QFile::setName: File is open" ); +#endif + close(); + } + fn = name; +} + +/*! + Returns TRUE if this file exists, otherwise FALSE. + \sa name() +*/ + +bool QFile::exists() const +{ + return qt_file_access( fn, F_OK ); +} + +/*! + Returns TRUE if the file given by \e fileName exists, otherwise FALSE. +*/ + +bool QFile::exists( const QString &fileName ) +{ + return qt_file_access( fileName, F_OK ); +} + + +/*! + Removes the file specified by the file name currently set. + Returns TRUE if successful, otherwise FALSE. + + The file is closed before it is removed. +*/ + +bool QFile::remove() +{ + close(); + return remove( fn ); +} + +#if defined(_OS_MAC_) || defined(_OS_MSDOS_) || defined(_OS_WIN32_) || defined(_OS_OS2_) || defined(_OS_CYGWIN_) +# define HAS_TEXT_FILEMODE // has translate/text filemode +#endif +#if defined(O_NONBLOCK) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NONBLOCK +#elif defined(O_NDELAY) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NDELAY +#endif + +/*! + Flushes the file buffer to the disk. + + close() also flushes the file buffer. +*/ + +void QFile::flush() +{ + if ( isOpen() && fh ) // can only flush open/buffered + fflush( fh ); // file +} + +/*! + Returns TRUE if the end of file has been reached, otherwise FALSE. + \sa size() +*/ + +bool QFile::atEnd() const +{ + if ( !isOpen() ) { +#if defined(CHECK_STATE) + qWarning( "QFile::atEnd: File is not open" ); +#endif + return FALSE; + } + if ( isDirectAccess() && !isTranslated() ) { + if ( at() < length ) + return FALSE; + } + return QIODevice::atEnd(); +} + +/*! + Reads a line of text. + + Reads bytes from the file until end-of-line is reached, or up to \a + maxlen bytes, and returns the number of bytes read, or -1 in case of + error. The terminating newline is not stripped. + + This function is efficient only for buffered files. Avoid + readLine() for files that have been opened with the \c IO_Raw + flag. + + \sa readBlock(), QTextStream::readLine() +*/ + +int QFile::readLine( char *p, uint maxlen ) +{ + if ( maxlen == 0 ) // application bug? + return 0; +#if defined(CHECK_STATE) + CHECK_PTR( p ); + if ( !isOpen() ) { // file not open + qWarning( "QFile::readLine: File not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QFile::readLine: Read operation not permitted" ); + return -1; + } +#endif + int nread; // number of bytes read + if ( isRaw() ) { // raw file + nread = QIODevice::readLine( p, maxlen ); + } else { // buffered file + p = fgets( p, maxlen, fh ); + if ( p ) { + nread = qstrlen( p ); + ioIndex += nread; + } else { + nread = -1; + setStatus(IO_ReadError); + } + } + return nread; +} + + +/*! + Reads a line of text. + + Reads bytes from the file until end-of-line is reached, or up to \a + maxlen bytes, and returns the number of bytes read, or -1 in case of + error. The terminating newline is not stripped. + + This function is efficient only for buffered files. Avoid + readLine() for files that have been opened with the \c IO_Raw + flag. + + Note that the string is read as plain Latin1 bytes, not Unicode. + + \sa readBlock(), QTextStream::readLine() +*/ + +int QFile::readLine( QString& s, uint maxlen ) +{ + QByteArray ba(maxlen); + int l = readLine(ba.data(),maxlen); + if ( l >= 0 ) { + ba.truncate(l); + s = QString(ba); + } + return l; +} + + +/*! + Reads a single byte/character from the file. + + Returns the byte/character read, or -1 if the end of the file has been + reached. + + \sa putch(), ungetch() +*/ + +int QFile::getch() +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::getch: File not open" ); + return EOF; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QFile::getch: Read operation not permitted" ); + return EOF; + } +#endif + + int ch; + + if ( !ungetchBuffer.isEmpty() ) { + int len = ungetchBuffer.length(); + ch = ungetchBuffer[ len-1 ]; + ungetchBuffer.truncate( len - 1 ); + return ch; + } + + if ( isRaw() ) { // raw file (inefficient) + char buf[1]; + ch = readBlock( buf, 1 ) == 1 ? buf[0] : EOF; + } else { // buffered file + if ( (ch = getc( fh )) != EOF ) + ioIndex++; + else + setStatus(IO_ReadError); + } + return ch; +} + +/*! + \fn int QFile::writeBlock( const QByteArray& data ) + \reimp + \internal + Should be removed in 3.0 +*/ + +/*! + Writes the character \e ch to the file. + + Returns \e ch, or -1 if some error occurred. + + \sa getch(), ungetch() +*/ + +int QFile::putch( int ch ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::putch: File not open" ); + return EOF; + } + if ( !isWritable() ) { // writing not permitted + qWarning( "QFile::putch: Write operation not permitted" ); + return EOF; + } +#endif + if ( isRaw() ) { // raw file (inefficient) + char buf[1]; + buf[0] = ch; + ch = writeBlock( buf, 1 ) == 1 ? ch : EOF; + } else { // buffered file + if ( (ch = putc( ch, fh )) != EOF ) { + ioIndex++; + if ( ioIndex > length ) // update file length + length = ioIndex; + } else { + setStatus(IO_WriteError); + } + } + return ch; +} + +/*! + Puts the character \e ch back into the file and decrements the index if it + is not zero. + + This function is normally called to "undo" a getch() operation. + + Returns \e ch, or -1 if some error occurred. + + \sa getch(), putch() +*/ + +int QFile::ungetch( int ch ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::ungetch: File not open" ); + return EOF; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QFile::ungetch: Read operation not permitted" ); + return EOF; + } +#endif + if ( ch == EOF ) // cannot unget EOF + return ch; + + if ( isSequentialAccess() && !fh) { + // pipe or similar => we cannot ungetch, so do it manually + ungetchBuffer +=ch; + return ch; + } + + if ( isRaw() ) { // raw file (very inefficient) + char buf[1]; + at( ioIndex-1 ); + buf[0] = ch; + if ( writeBlock(buf, 1) == 1 ) + at ( ioIndex-1 ); + else + ch = EOF; + } else { // buffered file + if ( (ch = ungetc(ch, fh)) != EOF ) + ioIndex--; + else + setStatus( IO_ReadError ); + } + return ch; +} + + +static QCString locale_encoder( const QString &fileName ) +{ + return fileName.local8Bit(); +} + + +static QFile::EncoderFn encoder = locale_encoder; + +/*! + When you use QFile, QFileInfo, and QDir to access the filesystem + with Qt, you can use Unicode filenames. On Unix, these filenames + are converted to an 8-bit encoding. If you want to do your own + file I/O on Unix, you should convert the filename using this + function. On Windows NT, Unicode filenames are supported directly + in the filesystem and this function should be avoided. On Windows 95, + non-Latin1 locales are not supported at this time. + + By default, this function converts to the local 8-bit encoding + determined by the user's locale. This is sufficient for + filenames that the user chooses. Filenames hard-coded into the + application should only use 7-bit ASCII filename characters. + + The conversion scheme can be changed using setEncodingFunction(). + This might be useful if you wish to give the user an option to + store in filenames in UTF-8, etc., but beware that such filenames + would probably then be unrecognizable when seen by other programs. + + \sa decodeName() +*/ + +QCString QFile::encodeName( const QString &fileName ) +{ + return (*encoder)(fileName); +} + +/*! + \enum QFile::EncoderFn + + This is used by QFile::setEncodingFunction(). +*/ + +/*! + Sets the function for encoding Unicode filenames. + The default encodes in the locale-specific 8-bit encoding. + + \sa encodeName() +*/ +void QFile::setEncodingFunction( EncoderFn f ) +{ + encoder = f; +} + +static +QString locale_decoder( const QCString &localFileName ) +{ + return QString::fromLocal8Bit(localFileName); +} + +static QFile::DecoderFn decoder = locale_decoder; + +/*! + This does the reverse of QFile::encodeName(). + + \sa setDecodingFunction() +*/ +QString QFile::decodeName( const QCString &localFileName ) +{ + return (*decoder)(localFileName); +} + +/*! + \enum QFile::DecoderFn + + This is used by QFile::setDecodingFunction(). +*/ + +/*! + Sets the function for decoding 8-bit filenames. + The default uses the locale-specific 8-bit encoding. + + \sa encodeName(), decodeName() +*/ + +void QFile::setDecodingFunction( DecoderFn f ) +{ + decoder = f; +} diff --git a/trunk/qtools/qfile.h b/trunk/qtools/qfile.h new file mode 100644 index 0000000..a447d2f --- /dev/null +++ b/trunk/qtools/qfile.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** +** Definition of QFile class +** +** Created : 930831 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QFILE_H +#define QFILE_H + +#ifndef QT_H +#include "qiodevice.h" +#include "qstring.h" +#include <stdio.h> +#endif // QT_H + +class QDir; + + +class Q_EXPORT QFile : public QIODevice // file I/O device class +{ +public: + QFile(); + QFile( const QString &name ); + virtual ~QFile(); + + QString name() const; + void setName( const QString &name ); + + typedef QCString (*EncoderFn)( const QString &fileName ); + typedef QString (*DecoderFn)( const QCString &localfileName ); + static QCString encodeName( const QString &fileName ); + static QString decodeName( const QCString &localFileName ); + static void setEncodingFunction( EncoderFn ); + static void setDecodingFunction( DecoderFn ); + + bool exists() const; + static bool exists( const QString &fileName ); + + bool remove(); + static bool remove( const QString &fileName ); + + bool open( int ); + bool open( int, FILE * ); + bool open( int, int ); + void close(); + void flush(); + + uint size() const; + int at() const; + bool at( int ); + bool atEnd() const; + + int readBlock( char *data, uint len ); + int writeBlock( const char *data, uint len ); + int writeBlock( const QByteArray& data ) + { return QIODevice::writeBlock(data); } + int readLine( char *data, uint maxlen ); + int readLine( QString &, uint maxlen ); + + int getch(); + int putch( int ); + int ungetch( int ); + + int handle() const; + + int64 pos() const; + int64 toEnd(); + bool seek(int64 pos); + +protected: + QString fn; + FILE *fh; + int fd; + int length; + bool ext_f; + void * d; + +private: + void init(); + QCString ungetchBuffer; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QFile( const QFile & ); + QFile &operator=( const QFile & ); +#endif +}; + + +inline QString QFile::name() const +{ return fn; } + +inline int QFile::at() const +{ return ioIndex; } + + +#endif // QFILE_H diff --git a/trunk/qtools/qfile_unix.cpp b/trunk/qtools/qfile_unix.cpp new file mode 100644 index 0000000..fa53d13 --- /dev/null +++ b/trunk/qtools/qfile_unix.cpp @@ -0,0 +1,668 @@ +/**************************************************************************** +** +** +** Implementation of QFileInfo class +** +** Created : 950628 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses for Unix/X11 or for Qt/Embedded may use this file in accordance +** with the Qt Commercial License Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" + +#include "qfile.h" +#include "qfiledefs_p.h" + +#if (defined(_OS_MAC_) && (!defined(_OS_UNIX_))) || defined(_OS_MSDOS_) || defined(_OS_WIN32_) || defined(_OS_OS2_) || defined(_OS_CYGWIN_) +# define HAS_TEXT_FILEMODE // has translate/text filemode +#endif +#if defined(O_NONBLOCK) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NONBLOCK +#elif defined(O_NDELAY) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NDELAY +#endif + +bool qt_file_access( const QString& fn, int t ) +{ + if ( fn.isEmpty() ) + return FALSE; + return ACCESS( QFile::encodeName(fn), t ) == 0; +} + +/*! + Removes the file \a fileName. + Returns TRUE if successful, otherwise FALSE. +*/ + +bool QFile::remove( const QString &fileName ) +{ + if ( fileName.isEmpty() ) { +#if defined(CHECK_NULL) + qWarning( "QFile::remove: Empty or null file name" ); +#endif + return FALSE; + } + return unlink( QFile::encodeName(fileName) ) == 0; + // unlink more common in UNIX +} + +#if defined(O_NONBLOCK) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NONBLOCK +#elif defined(O_NDELAY) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NDELAY +#endif + +/*! + Opens the file specified by the file name currently set, using the mode \e m. + Returns TRUE if successful, otherwise FALSE. + + The mode parameter \e m must be a combination of the following flags: + <ul> + <li>\c IO_Raw specified raw (non-buffered) file access. + <li>\c IO_ReadOnly opens the file in read-only mode. + <li>\c IO_WriteOnly opens the file in write-only mode (and truncates). + <li>\c IO_ReadWrite opens the file in read/write mode, equivalent to + \c (IO_ReadOnly|IO_WriteOnly). + <li>\c IO_Append opens the file in append mode. This mode is very useful + when you want to write something to a log file. The file index is set to + the end of the file. Note that the result is undefined if you position the + file index manually using at() in append mode. + <li>\c IO_Truncate truncates the file. + <li>\c IO_Translate enables carriage returns and linefeed translation + for text files under MS-DOS, Windows and OS/2. + </ul> + + The raw access mode is best when I/O is block-operated using 4kB block size + or greater. Buffered access works better when reading small portions of + data at a time. + + <strong>Important:</strong> When working with buffered files, data may + not be written to the file at once. Call \link flush() flush\endlink + to make sure the data is really written. + + \warning We have experienced problems with some C libraries when a buffered + file is opened for both reading and writing. If a read operation takes place + immediately after a write operation, the read buffer contains garbage data. + Worse, the same garbage is written to the file. Calling flush() before + readBlock() solved this problem. + + If the file does not exist and \c IO_WriteOnly or \c IO_ReadWrite is + specified, it is created. + + Example: + \code + QFile f1( "/tmp/data.bin" ); + QFile f2( "readme.txt" ); + f1.open( IO_Raw | IO_ReadWrite | IO_Append ); + f2.open( IO_ReadOnly | IO_Translate ); + \endcode + + \sa name(), close(), isOpen(), flush() +*/ + +bool QFile::open( int m ) +{ + if ( isOpen() ) { // file already open +#if defined(CHECK_STATE) + qWarning( "QFile::open: File already open" ); +#endif + return FALSE; + } + if ( fn.isNull() ) { // no file name defined +#if defined(CHECK_NULL) + qWarning( "QFile::open: No file name specified" ); +#endif + return FALSE; + } + init(); // reset params + setMode( m ); + if ( !(isReadable() || isWritable()) ) { +#if defined(CHECK_RANGE) + qWarning( "QFile::open: File access not specified" ); +#endif + return FALSE; + } + bool ok = TRUE; + STATBUF st; + if ( isRaw() ) { // raw file I/O + int oflags = OPEN_RDONLY; + if ( isReadable() && isWritable() ) + oflags = OPEN_RDWR; + else if ( isWritable() ) + oflags = OPEN_WRONLY; + if ( flags() & IO_Append ) { // append to end of file? + if ( flags() & IO_Truncate ) + oflags |= (OPEN_CREAT | OPEN_TRUNC); + else + oflags |= (OPEN_APPEND | OPEN_CREAT); + setFlags( flags() | IO_WriteOnly ); // append implies write + } else if ( isWritable() ) { // create/trunc if writable + if ( flags() & IO_Truncate ) + oflags |= (OPEN_CREAT | OPEN_TRUNC); + else + oflags |= OPEN_CREAT; + } +#if defined(HAS_TEXT_FILEMODE) + if ( isTranslated() ) +#ifdef __CYGWIN__ + /* Do nothing, allowing the Cygwin mount mode to take effect. */; +#else + oflags |= OPEN_TEXT; +#endif + else + oflags |= OPEN_BINARY; +#endif +#if defined(HAS_ASYNC_FILEMODE) + if ( isAsynchronous() ) + oflags |= OPEN_ASYNC; +#endif + fd = OPEN( QFile::encodeName(fn), oflags, 0666 ); + + if ( fd != -1 ) { // open successful + FSTAT( fd, &st ); // get the stat for later usage + } else { + ok = FALSE; + } + } else { // buffered file I/O + QCString perm; + char perm2[4]; + bool try_create = FALSE; + if ( flags() & IO_Append ) { // append to end of file? + setFlags( flags() | IO_WriteOnly ); // append implies write + perm = isReadable() ? "a+" : "a"; + } else { + if ( isReadWrite() ) { + if ( flags() & IO_Truncate ) { + perm = "w+"; + } else { + perm = "r+"; + try_create = TRUE; // try to create if not exists + } + } else if ( isReadable() ) { + perm = "r"; + } else if ( isWritable() ) { + perm = "w"; + } + } + qstrcpy( perm2, perm ); +#if defined(HAS_TEXT_FILEMODE) + if ( isTranslated() ) +#ifdef __CYGWIN__ + /* Do nothing, allowing the Cygwin mount mode to take effect. */; +#else + strcat( perm2, "t" ); +#endif + else + strcat( perm2, "b" ); +#endif + while (1) { // At most twice + + fh = fopen( QFile::encodeName(fn), perm2 ); + + if ( !fh && try_create ) { + perm2[0] = 'w'; // try "w+" instead of "r+" + try_create = FALSE; + } else { + break; + } + } + if ( fh ) { + FSTAT( FILENO(fh), &st ); // get the stat for later usage + } else { + ok = FALSE; + } + } + if ( ok ) { + setState( IO_Open ); + // on successful open the file stat was got; now test what type + // of file we have + if ( (st.st_mode & STAT_MASK) != STAT_REG ) { + // non-seekable + setType( IO_Sequential ); + length = INT_MAX; + ioIndex = (flags() & IO_Append) == 0 ? 0 : length; + } else { + length = (int)st.st_size; + ioIndex = (flags() & IO_Append) == 0 ? 0 : length; + if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) { + // try if you can read from it (if you can, it's a sequential + // device; e.g. a file in the /proc filesystem) + int c = getch(); + if ( c != -1 ) { + ungetch(c); + setType( IO_Sequential ); + length = INT_MAX; + } + } + } + } else { + init(); + if ( errno == EMFILE ) // no more file handles/descrs + setStatus( IO_ResourceError ); + else + setStatus( IO_OpenError ); + } + return ok; +} + +/*! + Opens a file in the mode \e m using an existing file handle \e f. + Returns TRUE if successful, otherwise FALSE. + + Example: + \code + #include <stdio.h> + + void printError( const char* msg ) + { + QFile f; + f.open( IO_WriteOnly, stderr ); + f.writeBlock( msg, qstrlen(msg) ); // write to stderr + f.close(); + } + \endcode + + When a QFile is opened using this function, close() does not actually + close the file, only flushes it. + + \warning If \e f is \c stdin, \c stdout, \c stderr, you may not + be able to seek. See QIODevice::isSequentialAccess() for more + information. + + \sa close() +*/ + +bool QFile::open( int m, FILE *f ) +{ + if ( isOpen() ) { +#if defined(CHECK_RANGE) + qWarning( "QFile::open: File already open" ); +#endif + return FALSE; + } + init(); + setMode( m &~IO_Raw ); + setState( IO_Open ); + fh = f; + ext_f = TRUE; + STATBUF st; + FSTAT( FILENO(fh), &st ); + ioIndex = (int)ftell( fh ); + if ( (st.st_mode & STAT_MASK) != STAT_REG || f == stdin ) { //stdin is non seekable + // non-seekable + setType( IO_Sequential ); + length = INT_MAX; + } else { + length = (int)st.st_size; + if ( !(flags()&IO_Truncate) && length == 0 && isReadable() ) { + // try if you can read from it (if you can, it's a sequential + // device; e.g. a file in the /proc filesystem) + int c = getch(); + if ( c != -1 ) { + ungetch(c); + setType( IO_Sequential ); + length = INT_MAX; + } + } + } + return TRUE; +} + +/*! + Opens a file in the mode \e m using an existing file descriptor \e f. + Returns TRUE if successful, otherwise FALSE. + + When a QFile is opened using this function, close() does not actually + close the file. + + \warning If \e f is one of 0 (stdin), 1 (stdout) or 2 (stderr), you may not + be able to seek. size() is set to \c INT_MAX (in limits.h). + + \sa close() +*/ + + +bool QFile::open( int m, int f ) +{ + if ( isOpen() ) { +#if defined(CHECK_RANGE) + qWarning( "QFile::open: File already open" ); +#endif + return FALSE; + } + init(); + setMode( m |IO_Raw ); + setState( IO_Open ); + fd = f; + ext_f = TRUE; + STATBUF st; + FSTAT( fd, &st ); + ioIndex = (int)LSEEK(fd, 0, SEEK_CUR); + if ( (st.st_mode & STAT_MASK) != STAT_REG || f == 0 ) { // stdin is not seekable... + // non-seekable + setType( IO_Sequential ); + length = INT_MAX; + } else { + length = (int)st.st_size; + if ( length == 0 && isReadable() ) { + // try if you can read from it (if you can, it's a sequential + // device; e.g. a file in the /proc filesystem) + int c = getch(); + if ( c != -1 ) { + ungetch(c); + setType( IO_Sequential ); + length = INT_MAX; + } + resetStatus(); + } + } + return TRUE; +} + +/*! + Returns the file size. + \sa at() +*/ + +uint QFile::size() const +{ + STATBUF st; + if ( isOpen() ) { + FSTAT( fh ? FILENO(fh) : fd, &st ); + } else { + STAT( QFile::encodeName(fn), &st ); + } + return st.st_size; +} + +/*! + \fn int QFile::at() const + Returns the file index. + \sa size() +*/ + +/*! + Sets the file index to \e pos. Returns TRUE if successful, otherwise FALSE. + + Example: + \code + QFile f( "data.bin" ); + f.open( IO_ReadOnly ); // index set to 0 + f.at( 100 ); // set index to 100 + f.at( f.at()+50 ); // set index to 150 + f.at( f.size()-80 ); // set index to 80 before EOF + f.close(); + \endcode + + \warning The result is undefined if the file was \link open() opened\endlink + using the \c IO_Append specifier. + + \sa size(), open() +*/ + +bool QFile::at( int pos ) +{ + if ( !isOpen() ) { +#if defined(CHECK_STATE) + qWarning( "QFile::at: File is not open" ); +#endif + return FALSE; + } + bool ok; + if ( isRaw() ) { // raw file + pos = (int)LSEEK(fd, pos, SEEK_SET); + ok = pos != -1; + } else { // buffered file + ok = fseek(fh, pos, SEEK_SET) == 0; + } + if ( ok ) + ioIndex = pos; +#if defined(CHECK_RANGE) + else + qWarning( "QFile::at: Cannot set file position %d", pos ); +#endif + return ok; +} + +/*! + Reads at most \e len bytes from the file into \e p and returns the + number of bytes actually read. + + Returns -1 if a serious error occurred. + + \warning We have experienced problems with some C libraries when a buffered + file is opened for both reading and writing. If a read operation takes place + immediately after a write operation, the read buffer contains garbage data. + Worse, the same garbage is written to the file. Calling flush() before + readBlock() solved this problem. + + \sa writeBlock() +*/ + +int QFile::readBlock( char *p, uint len ) +{ +#if defined(CHECK_NULL) + if ( !p ) + qWarning( "QFile::readBlock: Null pointer error" ); +#endif +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::readBlock: File not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QFile::readBlock: Read operation not permitted" ); + return -1; + } +#endif + int nread = 0; // number of bytes read + if ( !ungetchBuffer.isEmpty() ) { + // need to add these to the returned string. + int l = ungetchBuffer.length(); + while( nread < l ) { + *p = ungetchBuffer[ l - nread - 1 ]; + p++; + nread++; + } + ungetchBuffer.truncate( l - nread ); + } + + if ( nread < (int)len ) { + if ( isRaw() ) { // raw file + nread += READ( fd, p, len-nread ); + if ( len && nread <= 0 ) { + nread = 0; + setStatus(IO_ReadError); + } + } else { // buffered file + nread += fread( p, 1, len-nread, fh ); + if ( (uint)nread != len ) { + if ( ferror( fh ) || nread==0 ) + setStatus(IO_ReadError); + } + } + } + ioIndex += nread; + return nread; +} + +/*! \overload int writeBlock( const QByteArray& data ) +*/ + +/*! \reimp + + Writes \e len bytes from \e p to the file and returns the number of + bytes actually written. + + Returns -1 if a serious error occurred. + + \warning When working with buffered files, data may not be written + to the file at once. Call flush() to make sure the data is really + written. + + \sa readBlock() +*/ + +int QFile::writeBlock( const char *p, uint len ) +{ +#if defined(CHECK_NULL) + if ( p == 0 && len != 0 ) + qWarning( "QFile::writeBlock: Null pointer error" ); +#endif +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::writeBlock: File not open" ); + return -1; + } + if ( !isWritable() ) { // writing not permitted + qWarning( "QFile::writeBlock: Write operation not permitted" ); + return -1; + } +#endif + int nwritten; // number of bytes written + if ( isRaw() ) // raw file + nwritten = WRITE( fd, p, len ); + else // buffered file + nwritten = fwrite( p, 1, len, fh ); + if ( nwritten != (int)len ) { // write error + if ( errno == ENOSPC ) // disk is full + setStatus( IO_ResourceError ); + else + setStatus( IO_WriteError ); + if ( isRaw() ) // recalc file position + ioIndex = (int)LSEEK( fd, 0, SEEK_CUR ); + else + ioIndex = fseek( fh, 0, SEEK_CUR ); + } else { + ioIndex += nwritten; + } + if ( ioIndex > length ) // update file length + length = ioIndex; + return nwritten; +} + +/*! + Returns the file handle of the file. + + This is a small positive integer, suitable for use with C library + functions such as fdopen() and fcntl(), as well as with QSocketNotifier. + + If the file is not open or there is an error, handle() returns -1. + + \sa QSocketNotifier +*/ + +int QFile::handle() const +{ + if ( !isOpen() ) + return -1; + else if ( fh ) + return FILENO( fh ); + else + return fd; +} + +/*! + Closes an open file. + + The file is not closed if it was opened with an existing file handle. + If the existing file handle is a \c FILE*, the file is flushed. + If the existing file handle is an \c int file descriptor, nothing + is done to the file. + + Some "write-behind" filesystems may report an unspecified error on + closing the file. These errors only indicate that something may + have gone wrong since the previous open(). In such a case status() + reports IO_UnspecifiedError after close(), otherwise IO_Ok. + + \sa open(), flush() +*/ + + +void QFile::close() +{ + bool ok = FALSE; + if ( isOpen() ) { // file is not open + if ( fh ) { // buffered file + if ( ext_f ) + ok = fflush( fh ) != -1; // flush instead of closing + else + ok = fclose( fh ) != -1; + } else { // raw file + if ( ext_f ) + ok = TRUE; // cannot close + else + ok = CLOSE( fd ) != -1; + } + init(); // restore internal state + } + if (!ok) + setStatus (IO_UnspecifiedError); + + return; +} + +int64 QFile::pos() const +{ + if (isOpen()) + { + // TODO: support 64 bit size + return ftell( fh ); + } + return -1; +} + +int64 QFile::toEnd() +{ + if (isOpen()) + { + // TODO: support 64 bit size + if (fseek( fh, 0, SEEK_END )!=-1) + { + return ftell( fh ); + } + } + return -1; +} + +bool QFile::seek( int64 pos ) +{ + if (isOpen()) + { + // TODO: support 64 bit size + return fseek( fh, pos, SEEK_SET )!=-1; + } + return FALSE; +} + diff --git a/trunk/qtools/qfile_win32.cpp b/trunk/qtools/qfile_win32.cpp new file mode 100644 index 0000000..0cc91de --- /dev/null +++ b/trunk/qtools/qfile_win32.cpp @@ -0,0 +1,629 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2001 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + * Based on qfile_unix.cpp + * + * Copyright (C) 1992-2000 Trolltech AS. + */ + +#include "qglobal.h" + +#include "qfile.h" +#include "qfiledefs_p.h" + +#if defined(_OS_MAC_) || defined(_OS_MSDOS_) || defined(_OS_WIN32_) || defined(_OS_OS2_) +# define HAS_TEXT_FILEMODE // has translate/text filemode +#endif +#if defined(O_NONBLOCK) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NONBLOCK +#elif defined(O_NDELAY) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NDELAY +#endif + +bool qt_file_access( const QString& fn, int t ) +{ + if ( fn.isEmpty() ) + return FALSE; + return ACCESS( QFile::encodeName(fn), t ) == 0; +} + +/*! + Removes the file \a fileName. + Returns TRUE if successful, otherwise FALSE. +*/ + +bool QFile::remove( const QString &fileName ) +{ + if ( fileName.isEmpty() ) { +#if defined(CHECK_NULL) + qWarning( "QFile::remove: Empty or null file name" ); +#endif + return FALSE; + } + return ::remove( QFile::encodeName(fileName) ) == 0; + // unlink more common in UNIX +} + +#if defined(O_NONBLOCK) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NONBLOCK +#elif defined(O_NDELAY) +# define HAS_ASYNC_FILEMODE +# define OPEN_ASYNC O_NDELAY +#endif + +/*! + Opens the file specified by the file name currently set, using the mode \e m. + Returns TRUE if successful, otherwise FALSE. + + The mode parameter \e m must be a combination of the following flags: + <ul> + <li>\c IO_Raw specified raw (non-buffered) file access. + <li>\c IO_ReadOnly opens the file in read-only mode. + <li>\c IO_WriteOnly opens the file in write-only mode (and truncates). + <li>\c IO_ReadWrite opens the file in read/write mode, equivalent to + \c (IO_ReadOnly|IO_WriteOnly). + <li>\c IO_Append opens the file in append mode. This mode is very useful + when you want to write something to a log file. The file index is set to + the end of the file. Note that the result is undefined if you position the + file index manually using at() in append mode. + <li>\c IO_Truncate truncates the file. + <li>\c IO_Translate enables carriage returns and linefeed translation + for text files under MS-DOS, Windows and OS/2. + </ul> + + The raw access mode is best when I/O is block-operated using 4kB block size + or greater. Buffered access works better when reading small portions of + data at a time. + + <strong>Important:</strong> When working with buffered files, data may + not be written to the file at once. Call \link flush() flush\endlink + to make sure the data is really written. + + \warning We have experienced problems with some C libraries when a buffered + file is opened for both reading and writing. If a read operation takes place + immediately after a write operation, the read buffer contains garbage data. + Worse, the same garbage is written to the file. Calling flush() before + readBlock() solved this problem. + + If the file does not exist and \c IO_WriteOnly or \c IO_ReadWrite is + specified, it is created. + + Example: + \code + QFile f1( "/tmp/data.bin" ); + QFile f2( "readme.txt" ); + f1.open( IO_Raw | IO_ReadWrite | IO_Append ); + f2.open( IO_ReadOnly | IO_Translate ); + \endcode + + \sa name(), close(), isOpen(), flush() +*/ + +bool QFile::open( int m ) +{ + if ( isOpen() ) { // file already open +#if defined(CHECK_STATE) + qWarning( "QFile::open: File already open" ); +#endif + return FALSE; + } + if ( fn.isNull() ) { // no file name defined +#if defined(CHECK_NULL) + qWarning( "QFile::open: No file name specified" ); +#endif + return FALSE; + } + init(); // reset params + setMode( m ); + if ( !(isReadable() || isWritable()) ) { +#if defined(CHECK_RANGE) + qWarning( "QFile::open: File access not specified" ); +#endif + return FALSE; + } + bool ok = TRUE; + STATBUF st; + if ( isRaw() ) { // raw file I/O + int oflags = OPEN_RDONLY; + if ( isReadable() && isWritable() ) + oflags = OPEN_RDWR; + else if ( isWritable() ) + oflags = OPEN_WRONLY; + if ( flags() & IO_Append ) { // append to end of file? + if ( flags() & IO_Truncate ) + oflags |= (OPEN_CREAT | OPEN_TRUNC); + else + oflags |= (OPEN_APPEND | OPEN_CREAT); + setFlags( flags() | IO_WriteOnly ); // append implies write + } else if ( isWritable() ) { // create/trunc if writable + if ( flags() & IO_Truncate ) + oflags |= (OPEN_CREAT | OPEN_TRUNC); + else + oflags |= OPEN_CREAT; + } +#if defined(HAS_TEXT_FILEMODE) + if ( isTranslated() ) + oflags |= OPEN_TEXT; + else + oflags |= OPEN_BINARY; +#endif +#if defined(HAS_ASYNC_FILEMODE) + if ( isAsynchronous() ) + oflags |= OPEN_ASYNC; +#endif + fd = OPEN( QFile::encodeName(fn), oflags, 0666 ); + + if ( fd != -1 ) { // open successful + FSTAT( fd, &st ); // get the stat for later usage + } else { + ok = FALSE; + } + } else { // buffered file I/O + QCString perm; + char perm2[4]; + bool try_create = FALSE; + if ( flags() & IO_Append ) { // append to end of file? + setFlags( flags() | IO_WriteOnly ); // append implies write + perm = isReadable() ? "a+" : "a"; + } else { + if ( isReadWrite() ) { + if ( flags() & IO_Truncate ) { + perm = "w+"; + } else { + perm = "r+"; + try_create = TRUE; // try to create if not exists + } + } else if ( isReadable() ) { + perm = "r"; + } else if ( isWritable() ) { + perm = "w"; + } + } + qstrcpy( perm2, perm ); + if ( isTranslated() ) + strcat( perm2, "t" ); + else + strcat( perm2, "b" ); + while (1) { // At most twice + + fh = fopen( QFile::encodeName(fn), perm2 ); + + if ( !fh && try_create ) { + perm2[0] = 'w'; // try "w+" instead of "r+" + try_create = FALSE; + } else { + break; + } + } + if ( fh ) { + FSTAT( FILENO(fh), &st ); // get the stat for later usage + } else { + ok = FALSE; + } + } + if ( ok ) { + setState( IO_Open ); + // on successful open the file stat was got; now test what type + // of file we have + if ( (st.st_mode & STAT_MASK) != STAT_REG ) { + // non-seekable + setType( IO_Sequential ); + length = INT_MAX; + ioIndex = (flags() & IO_Append) == 0 ? 0 : length; + } else { + length = (int)st.st_size; + ioIndex = (flags() & IO_Append) == 0 ? 0 : length; + if ( (flags() & !IO_Truncate) && length == 0 && isReadable() ) { + // try if you can read from it (if you can, it's a sequential + // device; e.g. a file in the /proc filesystem) + int c = getch(); + if ( c != -1 ) { + ungetch(c); + setType( IO_Sequential ); + length = INT_MAX; + } + } + } + } else { + init(); + if ( errno == EMFILE ) // no more file handles/descrs + setStatus( IO_ResourceError ); + else + setStatus( IO_OpenError ); + } + return ok; +} + +/*! + Opens a file in the mode \e m using an existing file handle \e f. + Returns TRUE if successful, otherwise FALSE. + + Example: + \code + #include <stdio.h> + + void printError( const char* msg ) + { + QFile f; + f.open( IO_WriteOnly, stderr ); + f.writeBlock( msg, qstrlen(msg) ); // write to stderr + f.close(); + } + \endcode + + When a QFile is opened using this function, close() does not actually + close the file, only flushes it. + + \warning If \e f is \c stdin, \c stdout, \c stderr, you may not + be able to seek. See QIODevice::isSequentialAccess() for more + information. + + \sa close() +*/ + +bool QFile::open( int m, FILE *f ) +{ + if ( isOpen() ) { +#if defined(CHECK_RANGE) + qWarning( "QFile::open: File already open" ); +#endif + return FALSE; + } + init(); + setMode( m &~IO_Raw ); + setState( IO_Open ); + fh = f; + ext_f = TRUE; + STATBUF st; + FSTAT( FILENO(fh), &st ); + ioIndex = (int)ftell( fh ); + if ( (st.st_mode & STAT_MASK) != STAT_REG ) { + // non-seekable + setType( IO_Sequential ); + length = INT_MAX; + } else { + length = (int)st.st_size; + if ( (flags() & !IO_Truncate) && length == 0 && isReadable() ) { + // try if you can read from it (if you can, it's a sequential + // device; e.g. a file in the /proc filesystem) + int c = getch(); + if ( c != -1 ) { + ungetch(c); + setType( IO_Sequential ); + length = INT_MAX; + } + } + } + return TRUE; +} + +/*! + Opens a file in the mode \e m using an existing file descriptor \e f. + Returns TRUE if successful, otherwise FALSE. + + When a QFile is opened using this function, close() does not actually + close the file. + + \warning If \e f is one of 0 (stdin), 1 (stdout) or 2 (stderr), you may not + be able to seek. size() is set to \c INT_MAX (in limits.h). + + \sa close() +*/ + + +bool QFile::open( int m, int f ) +{ + if ( isOpen() ) { +#if defined(CHECK_RANGE) + qWarning( "QFile::open: File already open" ); +#endif + return FALSE; + } + init(); + setMode( m |IO_Raw ); + setState( IO_Open ); + fd = f; + ext_f = TRUE; + STATBUF st; + FSTAT( fd, &st ); + ioIndex = (int)LSEEK(fd, 0, SEEK_CUR); + if ( (st.st_mode & STAT_MASK) != STAT_REG ) { + // non-seekable + setType( IO_Sequential ); + length = INT_MAX; + } else { + length = (int)st.st_size; + if ( length == 0 && isReadable() ) { + // try if you can read from it (if you can, it's a sequential + // device; e.g. a file in the /proc filesystem) + int c = getch(); + if ( c != -1 ) { + ungetch(c); + setType( IO_Sequential ); + length = INT_MAX; + } + } + } + return TRUE; +} + +/*! + Returns the file size. + \sa at() +*/ + +uint QFile::size() const +{ + STATBUF st; + if ( isOpen() ) { + FSTAT( fh ? FILENO(fh) : fd, &st ); + } else { + STAT( QFile::encodeName(fn), &st ); + } + return st.st_size; +} + +/*! + \fn int QFile::at() const + Returns the file index. + \sa size() +*/ + +/*! + Sets the file index to \e pos. Returns TRUE if successful, otherwise FALSE. + + Example: + \code + QFile f( "data.bin" ); + f.open( IO_ReadOnly ); // index set to 0 + f.at( 100 ); // set index to 100 + f.at( f.at()+50 ); // set index to 150 + f.at( f.size()-80 ); // set index to 80 before EOF + f.close(); + \endcode + + \warning The result is undefined if the file was \link open() opened\endlink + using the \c IO_Append specifier. + + \sa size(), open() +*/ + +bool QFile::at( int pos ) +{ + if ( !isOpen() ) { +#if defined(CHECK_STATE) + qWarning( "QFile::at: File is not open" ); +#endif + return FALSE; + } + bool ok; + if ( isRaw() ) { // raw file + pos = (int)LSEEK(fd, pos, SEEK_SET); + ok = pos != -1; + } else { // buffered file + ok = fseek(fh, pos, SEEK_SET) == 0; + } + if ( ok ) + ioIndex = pos; +#if defined(CHECK_RANGE) + else + qWarning( "QFile::at: Cannot set file position %d", pos ); +#endif + return ok; +} + +/*! + Reads at most \e len bytes from the file into \e p and returns the + number of bytes actually read. + + Returns -1 if a serious error occurred. + + \warning We have experienced problems with some C libraries when a buffered + file is opened for both reading and writing. If a read operation takes place + immediately after a write operation, the read buffer contains garbage data. + Worse, the same garbage is written to the file. Calling flush() before + readBlock() solved this problem. + + \sa writeBlock() +*/ + +int QFile::readBlock( char *p, uint len ) +{ +#if defined(CHECK_NULL) + if ( !p ) + qWarning( "QFile::readBlock: Null pointer error" ); +#endif +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::readBlock: File not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QFile::readBlock: Read operation not permitted" ); + return -1; + } +#endif + int nread; // number of bytes read + if ( isRaw() ) { // raw file + nread = READ( fd, p, len ); + if ( len && nread <= 0 ) { + nread = 0; + setStatus(IO_ReadError); + } + } else { // buffered file + nread = fread( p, 1, len, fh ); + if ( (uint)nread != len ) { + if ( ferror( fh ) || nread==0 ) + setStatus(IO_ReadError); + } + } + ioIndex += nread; + return nread; +} + +/*! \overload int writeBlock( const QByteArray& data ) +*/ + +/*! \reimp + + Writes \e len bytes from \e p to the file and returns the number of + bytes actually written. + + Returns -1 if a serious error occurred. + + \warning When working with buffered files, data may not be written + to the file at once. Call flush() to make sure the data is really + written. + + \sa readBlock() +*/ + +int QFile::writeBlock( const char *p, uint len ) +{ +#if defined(CHECK_NULL) + if ( p == 0 && len != 0 ) + qWarning( "QFile::writeBlock: Null pointer error" ); +#endif +#if defined(CHECK_STATE) + if ( !isOpen() ) { // file not open + qWarning( "QFile::writeBlock: File not open" ); + return -1; + } + if ( !isWritable() ) { // writing not permitted + qWarning( "QFile::writeBlock: Write operation not permitted" ); + return -1; + } +#endif + int nwritten; // number of bytes written + if ( isRaw() ) // raw file + nwritten = WRITE( fd, p, len ); + else // buffered file + nwritten = fwrite( p, 1, len, fh ); + if ( nwritten != (int)len ) { // write error + if ( errno == ENOSPC ) // disk is full + setStatus( IO_ResourceError ); + else + setStatus( IO_WriteError ); + if ( isRaw() ) // recalc file position + ioIndex = (int)LSEEK( fd, 0, SEEK_CUR ); + else + ioIndex = fseek( fh, 0, SEEK_CUR ); + } else { + ioIndex += nwritten; + } + if ( ioIndex > length ) // update file length + length = ioIndex; + return nwritten; +} + +/*! + Returns the file handle of the file. + + This is a small positive integer, suitable for use with C library + functions such as fdopen() and fcntl(), as well as with QSocketNotifier. + + If the file is not open or there is an error, handle() returns -1. + + \sa QSocketNotifier +*/ + +int QFile::handle() const +{ + if ( !isOpen() ) + return -1; + else if ( fh ) + return FILENO( fh ); + else + return fd; +} + +/*! + Closes an open file. + + The file is not closed if it was opened with an existing file handle. + If the existing file handle is a \c FILE*, the file is flushed. + If the existing file handle is an \c int file descriptor, nothing + is done to the file. + + Some "write-behind" filesystems may report an unspecified error on + closing the file. These errors only indicate that something may + have gone wrong since the previous open(). In such a case status() + reports IO_UnspecifiedError after close(), otherwise IO_Ok. + + \sa open(), flush() +*/ + + +void QFile::close() +{ + bool ok = FALSE; + if ( isOpen() ) { // file is not open + if ( fh ) { // buffered file + if ( ext_f ) + ok = fflush( fh ) != -1; // flush instead of closing + else + ok = fclose( fh ) != -1; + } else { // raw file + if ( ext_f ) + ok = TRUE; // cannot close + else + ok = CLOSE( fd ) != -1; + } + init(); // restore internal state + } + if (!ok) + setStatus (IO_UnspecifiedError); + + return; +} + +int64 QFile::pos() const +{ + if (isOpen()) + { + // TODO: support 64 bit size + return ftell( fh ); + } + return -1; +} + +int64 QFile::toEnd() +{ + if (isOpen()) + { + // TODO: support 64 bit size + if (fseek( fh, 0, SEEK_END )!=-1) + { + return ftell( fh ); + } + } + return -1; +} + +bool QFile::seek( int64 pos ) +{ + if (isOpen()) + { + // TODO: support 64 bit size + return fseek( fh, pos, SEEK_SET )!=-1; + } + return FALSE; +} + + + diff --git a/trunk/qtools/qfiledefs_p.h b/trunk/qtools/qfiledefs_p.h new file mode 100644 index 0000000..5105c45 --- /dev/null +++ b/trunk/qtools/qfiledefs_p.h @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** +** Common macros and system include files for QFile, QFileInfo and QDir. +** +** Created : 930812 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QFILEDEFS_P_H +#define QFILEDEFS_P_H + + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of qfile.cpp, qfileinfo.cpp and qdir.cpp. +// This header file may change from version to version without notice, +// or even be removed. +// +// +#if defined(_CC_MWERKS_) +# include <stdlib.h> +# include <stat.h> +#elif !defined(_OS_MAC_) +# include <sys/types.h> +# include <sys/stat.h> +#elif defined(_OS_MAC_) +# include <sys/types.h> +# include <sys/stat.h> +# define _OS_UNIX_ +#endif +#include <fcntl.h> +#include <errno.h> +#if defined(_OS_UNIX_) +# include <dirent.h> +# include <unistd.h> +#endif +#if defined(_OS_MSDOS_) || defined(_OS_WIN32_) || defined(_OS_OS2_) +# define _OS_FATFS_ +# if defined(__CYGWIN32__) +# include <dirent.h> +# include <unistd.h> +# if !defined(_OS_UNIX_) +# define _OS_UNIX_ +# endif +# else +# include <io.h> +# if !defined(_CC_MWERKS_) +# include <dos.h> +# endif +# include <direct.h> +# endif +#endif +#include <limits.h> + + +#if !defined(PATH_MAX) +#if defined( MAXPATHLEN ) +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX 1024 +#endif +#endif + + +#undef STATBUF +#undef STAT +#undef STAT_REG +#undef STAT_DIR +#undef STAT_LNK +#undef STAT_MASK +#undef FILENO +#undef OPEN +#undef CLOSE +#undef LSEEK +#undef READ +#undef WRITE +#undef ACCESS +#undef GETCWD +#undef CHDIR +#undef MKDIR +#undef RMDIR +#undef OPEN_RDONLY +#undef OPEN_WRONLY +#undef OPEN_CREAT +#undef OPEN_TRUNC +#undef OPEN_APPEND +#undef OPEN_TEXT +#undef OPEN_BINARY + + +#if defined(_CC_MSVC_) || defined(_CC_SYM_) + +# define STATBUF struct _stat // non-ANSI defs +# define STATBUF4TSTAT struct _stat // non-ANSI defs +# define STAT ::_stat +# define FSTAT ::_fstat +# define STAT_REG _S_IFREG +# define STAT_DIR _S_IFDIR +# define STAT_MASK _S_IFMT +# if defined(_S_IFLNK) +# define STAT_LNK _S_IFLNK +# endif +# define FILENO _fileno +# define OPEN ::_open +# define CLOSE ::_close +# define LSEEK ::_lseek +# define READ ::_read +# define WRITE ::_write +# define ACCESS ::_access +# define GETCWD ::_getcwd +# define CHDIR ::_chdir +# define MKDIR ::_mkdir +# define RMDIR ::_rmdir +# define OPEN_RDONLY _O_RDONLY +# define OPEN_WRONLY _O_WRONLY +# define OPEN_RDWR _O_RDWR +# define OPEN_CREAT _O_CREAT +# define OPEN_TRUNC _O_TRUNC +# define OPEN_APPEND _O_APPEND +# if defined(O_TEXT) +# define OPEN_TEXT _O_TEXT +# define OPEN_BINARY _O_BINARY +# endif + +#elif defined(_CC_BOR_) && __BORLANDC__ >= 0x550 + +# define STATBUF struct stat // non-ANSI defs +# define STATBUF4TSTAT struct _stat // non-ANSI defs +# define STAT ::stat +# define FSTAT ::fstat +# define STAT_REG _S_IFREG +# define STAT_DIR _S_IFDIR +# define STAT_MASK _S_IFMT +# if defined(_S_IFLNK) +# define STAT_LNK _S_IFLNK +# endif +# define FILENO _fileno +# define OPEN ::open +# define CLOSE ::_close +# define LSEEK ::_lseek +# define READ ::_read +# define WRITE ::_write +# define ACCESS ::_access +# define GETCWD ::_getcwd +# define CHDIR ::chdir +# define MKDIR ::_mkdir +# define RMDIR ::_rmdir +# define OPEN_RDONLY _O_RDONLY +# define OPEN_WRONLY _O_WRONLY +# define OPEN_RDWR _O_RDWR +# define OPEN_CREAT _O_CREAT +# define OPEN_TRUNC _O_TRUNC +# define OPEN_APPEND _O_APPEND +# if defined(O_TEXT) +# define OPEN_TEXT _O_TEXT +# define OPEN_BINARY _O_BINARY +# endif + +#else // all other systems + +# define STATBUF struct stat +# define STATBUF4TSTAT struct stat +# define STAT ::stat +# define FSTAT ::fstat +# define STAT_REG S_IFREG +# define STAT_DIR S_IFDIR +# define STAT_MASK S_IFMT +# if defined(S_IFLNK) +# define STAT_LNK S_IFLNK +# endif +# define FILENO fileno +# define OPEN ::open +# define CLOSE ::close +# define LSEEK ::lseek +# define READ ::read +# define WRITE ::write +# define ACCESS ::access +# if defined(_OS_OS2EMX_) +# define GETCWD ::_getcwd2 +# define CHDIR ::_chdir2 +# else +# define GETCWD ::getcwd +# define CHDIR ::chdir +# endif +# define MKDIR ::mkdir +# define RMDIR ::rmdir +# define OPEN_RDONLY O_RDONLY +# define OPEN_WRONLY O_WRONLY +# define OPEN_RDWR O_RDWR +# define OPEN_CREAT O_CREAT +# define OPEN_TRUNC O_TRUNC +# define OPEN_APPEND O_APPEND +# if defined(O_TEXT) +# define OPEN_TEXT O_TEXT +# define OPEN_BINARY O_BINARY +# endif +#endif + +#if defined(_CC_MWERKS_) +#undef mkdir +#undef MKDIR +#define MKDIR _mkdir +#undef rmdir +#undef RMDIR +#define RMDIR _rmdir +#endif + + +#if defined(_OS_FATFS_) +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 +#endif + +#if defined(_OS_MAC_) && !defined(_OS_UNIX_) +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 +#endif + +struct QFileInfoCache +{ + STATBUF st; + bool isSymLink; +}; + +#endif diff --git a/trunk/qtools/qfileinfo.cpp b/trunk/qtools/qfileinfo.cpp new file mode 100644 index 0000000..5053b76 --- /dev/null +++ b/trunk/qtools/qfileinfo.cpp @@ -0,0 +1,458 @@ +/**************************************************************************** +** +** +** Implementation of QFileInfo class +** +** Created : 950628 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" + +#include "qfileinfo.h" +#include "qfiledefs_p.h" +#include "qdatetime.h" +#include "qdir.h" + +extern bool qt_file_access( const QString& fn, int t ); + +// NOT REVISED +/*! + \class QFileInfo qfileinfo.h + \brief The QFileInfo class provides system-independent file information. + + \ingroup io + + QFileInfo provides information about a file's name and position (path) in + the file system, its access rights and whether it is a directory or a + symbolic link. Its size and last modified/read times are also available. + + To speed up performance QFileInfo caches information about the file. Since + files can be changed by other users or programs, or even by other parts of + the same program there is a function that refreshes the file information; + refresh(). If you would rather like a QFileInfo to access the file system + every time you request information from it, you can call the function + setCaching( FALSE ). + + A QFileInfo can point to a file using either a relative or an absolute + file path. Absolute file paths begin with the directory separator + ('/') or a drive specification (not applicable to UNIX). + Relative file names begin with a directory name or a file name and specify + a path relative to the current directory. An example of + an absolute path is the string "/tmp/quartz". A relative path might look like + "src/fatlib". You can use the function isRelative() to check if a QFileInfo + is using a relative or an absolute file path. You can call the function + convertToAbs() to convert a relative QFileInfo to an absolute one. + + If you need to read and traverse directories, see the QDir class. +*/ + + +/*! + Constructs a new empty QFileInfo. +*/ + +QFileInfo::QFileInfo() +{ + fic = 0; + cache = TRUE; +} + +/*! + Constructs a new QFileInfo that gives information about the given file. + The string given can be an absolute or a relative file path. + + \sa bool setFile(QString ), isRelative(), QDir::setCurrent(), + QDir::isRelativePath() +*/ + +QFileInfo::QFileInfo( const QString &file ) +{ + fn = file; + slashify( fn ); + fic = 0; + cache = TRUE; +} + +/*! + Constructs a new QFileInfo that gives information about \e file. + + If the file has a relative path, the QFileInfo will also have one. + + \sa isRelative() +*/ + +QFileInfo::QFileInfo( const QFile &file ) +{ + fn = file.name(); + slashify( fn ); + fic = 0; + cache = TRUE; +} + +/*! + Constructs a new QFileInfo that gives information about the file + named \e fileName in the directory \e d. + + If the directory has a relative path, the QFileInfo will also have one. + + \sa isRelative() +*/ +#ifndef QT_NO_DIR +QFileInfo::QFileInfo( const QDir &d, const QString &fileName ) +{ + fn = d.filePath( fileName ); + slashify( fn ); + fic = 0; + cache = TRUE; +} +#endif +/*! + Constructs a new QFileInfo that is a copy of \e fi. +*/ + +QFileInfo::QFileInfo( const QFileInfo &fi ) +{ + fn = fi.fn; + if ( fi.fic ) { + fic = new QFileInfoCache; + *fic = *fi.fic; + } else { + fic = 0; + } + cache = fi.cache; +} + +/*! + Destructs the QFileInfo. +*/ + +QFileInfo::~QFileInfo() +{ + delete fic; +} + + +/*! + Makes a copy of \e fi and assigns it to this QFileInfo. +*/ + +QFileInfo &QFileInfo::operator=( const QFileInfo &fi ) +{ + fn = fi.fn; + if ( !fi.fic ) { + delete fic; + fic = 0; + } else { + if ( !fic ) { + fic = new QFileInfoCache; + CHECK_PTR( fic ); + } + *fic = *fi.fic; + } + cache = fi.cache; + return *this; +} + + +/*! + Sets the file to obtain information about. + + The string given can be an absolute or a relative file path. Absolute file + paths begin with the directory separator (e.g. '/' under UNIX) or a drive + specification (not applicable to UNIX). Relative file names begin with a + directory name or a file name and specify a path relative to the current + directory. + + Example: + \code + #include <qfileinfo.h> + #include <qdir.h> + + void test() + { + QString absolute = "/liver/aorta"; + QString relative = "liver/aorta"; + QFileInfo fi1( absolute ); + QFileInfo fi2( relative ); + + QDir::setCurrent( QDir::rootDirPath() ); + // fi1 and fi2 now point to the same file + + QDir::setCurrent( "/tmp" ); + // fi1 now points to "/liver/aorta", + // while fi2 points to "/tmp/liver/aorta" + } + \endcode + + \sa isRelative(), QDir::setCurrent(), QDir::isRelativePath() +*/ + +void QFileInfo::setFile( const QString &file ) +{ + fn = file; + slashify( fn ); + delete fic; + fic = 0; +} + +/*! + Sets the file to obtain information about. + + If the file has a relative path, the QFileInfo will also have one. + + \sa isRelative() +*/ + +void QFileInfo::setFile( const QFile &file ) +{ + fn = file.name(); + slashify( fn ); + delete fic; + fic = 0; +} + +/*! + Sets the file to obtains information about to \e fileName in the + directory \e d. + + If the directory has a relative path, the QFileInfo will also have one. + + \sa isRelative() +*/ +#ifndef QT_NO_DIR +void QFileInfo::setFile( const QDir &d, const QString &fileName ) +{ + fn = d.filePath( fileName ); + slashify( fn ); + delete fic; + fic = 0; +} +#endif + +/*! + Returns TRUE if the file pointed to exists, otherwise FALSE. +*/ + +bool QFileInfo::exists() const +{ + return qt_file_access( fn, F_OK ); +} + +/*! + Refresh the information about the file, i.e. read in information from the + file system the next time a cached property is fetched. + + \sa setCaching() +*/ + +void QFileInfo::refresh() const +{ + QFileInfo *that = (QFileInfo*)this; // Mutable function + delete that->fic; + that->fic = 0; +} + +/*! + \fn bool QFileInfo::caching() const + Returns TRUE if caching is enabled. + \sa setCaching(), refresh() +*/ + +/*! + Enables caching of file information if \e enable is TRUE, or disables it + if \e enable is FALSE. + + When caching is enabled, QFileInfo reads the file information the first + time + + Caching is enabled by default. + + \sa refresh(), caching() +*/ + +void QFileInfo::setCaching( bool enable ) +{ + if ( cache == enable ) + return; + cache = enable; + if ( cache ) { + delete fic; + fic = 0; + } +} + + +/*! + Returns the name, i.e. the file name including the path (which can be + absolute or relative). + + \sa isRelative(), absFilePath() +*/ + +QString QFileInfo::filePath() const +{ + return fn; +} + +/*! + Returns the base name of the file. + + The base name consists of all characters in the file name up to (but not + including) the first '.' character. The path is not included. + + Example: + \code + QFileInfo fi( "/tmp/abdomen.lower" ); + QString base = fi.baseName(); // base = "abdomen" + \endcode + + \sa fileName(), extension() +*/ + +QString QFileInfo::baseName() const +{ + QString tmp = fileName(); + int pos = tmp.find( '.' ); + if ( pos == -1 ) + return tmp; + else + return tmp.left( pos ); +} + +/*! + Returns the extension name of the file. + + If \a complete is TRUE (the default), extension() returns the string + of all characters in the file name after (but not including) the + first '.' character. For a file named "archive.tar.gz" this + returns "tar.gz". + + If \a complete is FALSE, extension() returns the string of all + characters in the file name after (but not including) the last '.' + character. For a file named "archive.tar.gz" this returns "gz". + + Example: + \code + QFileInfo fi( "lex.yy.c" ); + QString ext = fi.extension(); // ext = "yy.c" + QString ext = fi.extension( FALSE ); // ext = "c" + \endcode + + \sa fileName(), baseName() + +*/ + +QString QFileInfo::extension( bool complete ) const +{ + QString s = fileName(); + int pos = complete ? s.find( '.' ) : s.findRev( '.' ); + if ( pos < 0 ) + return QString::fromLatin1( "" ); + else + return s.right( s.length() - pos - 1 ); +} + +/*! + Returns the directory path of the file. + + If the QFileInfo is relative and \e absPath is FALSE, the QDir will be + relative, otherwise it will be absolute. + + \sa dirPath(), filePath(), fileName(), isRelative() +*/ +#ifndef QT_NO_DIR +QDir QFileInfo::dir( bool absPath ) const +{ + return QDir( dirPath(absPath) ); +} +#endif + + +/*! + Returns TRUE if the file is readable. + \sa isWritable(), isExecutable(), permission() +*/ + +bool QFileInfo::isReadable() const +{ + return qt_file_access( fn, R_OK ); +} + +/*! + Returns TRUE if the file is writable. + \sa isReadable(), isExecutable(), permission() +*/ + +bool QFileInfo::isWritable() const +{ + return qt_file_access( fn, W_OK ); +} + +/*! + Returns TRUE if the file is executable. + \sa isReadable(), isWritable(), permission() +*/ + +bool QFileInfo::isExecutable() const +{ + return qt_file_access( fn, X_OK ); +} + + +/*! + Returns TRUE if the file path name is relative to the current directory, + FALSE if the path is absolute (e.g. under UNIX a path is relative if it + does not start with a '/'). + + According to Einstein this function should always return TRUE. +*/ +#ifndef QT_NO_DIR +bool QFileInfo::isRelative() const +{ + return QDir::isRelativePath( fn ); +} + +/*! + Converts the file path name to an absolute path. + + If it is already absolute nothing is done. + + \sa filePath(), isRelative() +*/ + +bool QFileInfo::convertToAbs() +{ + if ( isRelative() ) + fn = absFilePath(); + return QDir::isRelativePath( fn ); +} +#endif diff --git a/trunk/qtools/qfileinfo.h b/trunk/qtools/qfileinfo.h new file mode 100644 index 0000000..76ef8c2 --- /dev/null +++ b/trunk/qtools/qfileinfo.h @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** +** Definition of QFileInfo class +** +** Created : 950628 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QFILEINFO_H +#define QFILEINFO_H + +#ifndef QT_H +#include "qfile.h" +#include "qdatetime.h" +#endif // QT_H + + +class QDir; +struct QFileInfoCache; + + +class Q_EXPORT QFileInfo // file information class +{ +public: + enum PermissionSpec { + ReadUser = 0400, WriteUser = 0200, ExeUser = 0100, + ReadGroup = 0040, WriteGroup = 0020, ExeGroup = 0010, + ReadOther = 0004, WriteOther = 0002, ExeOther = 0001 }; + + QFileInfo(); + QFileInfo( const QString &file ); + QFileInfo( const QFile & ); +#ifndef QT_NO_DIR + QFileInfo( const QDir &, const QString &fileName ); +#endif + QFileInfo( const QFileInfo & ); + ~QFileInfo(); + + QFileInfo &operator=( const QFileInfo & ); + + void setFile( const QString &file ); + void setFile( const QFile & ); +#ifndef QT_NO_DIR + void setFile( const QDir &, const QString &fileName ); +#endif + bool exists() const; + void refresh() const; + bool caching() const; + void setCaching( bool ); + + QString filePath() const; + QString fileName() const; +#ifndef QT_NO_DIR //### + QString absFilePath() const; +#endif + QString baseName() const; + QString extension( bool complete = TRUE ) const; + +#ifndef QT_NO_DIR //### + QString dirPath( bool absPath = FALSE ) const; +#endif +#ifndef QT_NO_DIR + QDir dir( bool absPath = FALSE ) const; +#endif + bool isReadable() const; + bool isWritable() const; + bool isExecutable() const; + +#ifndef QT_NO_DIR //### + bool isRelative() const; + bool convertToAbs(); +#endif + + bool isFile() const; + bool isDir() const; + bool isSymLink() const; + + QString readLink() const; + + QString owner() const; + uint ownerId() const; + QString group() const; + uint groupId() const; + + bool permission( int permissionSpec ) const; + + uint size() const; + + QDateTime lastModified() const; + QDateTime lastRead() const; + +private: + void doStat() const; + static void slashify( QString & ); + static void makeAbs( QString & ); + + QString fn; + QFileInfoCache *fic; + bool cache; +}; + + +inline bool QFileInfo::caching() const +{ + return cache; +} + + +#endif // QFILEINFO_H diff --git a/trunk/qtools/qfileinfo_unix.cpp b/trunk/qtools/qfileinfo_unix.cpp new file mode 100644 index 0000000..5a8fe04 --- /dev/null +++ b/trunk/qtools/qfileinfo_unix.cpp @@ -0,0 +1,425 @@ +/**************************************************************************** +** +** +** Implementation of QFileInfo class +** +** Created : 950628 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses for Unix/X11 or for Qt/Embedded may use this file in accordance +** with the Qt Commercial License Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" + +#if defined(_OS_SUN_) +#define readlink _qt_hide_readlink +#endif + +#include <pwd.h> +#include <grp.h> + +#include "qfileinfo.h" +#include "qfiledefs_p.h" +#include "qdatetime.h" +#include "qdir.h" + +#if defined(_OS_SUN_) +#undef readlink +extern "C" int readlink( const char *, void *, uint ); +#endif + + +void QFileInfo::slashify( QString& ) +{ + return; +} + + +void QFileInfo::makeAbs( QString & ) +{ + return; +} + +extern bool qt_file_access( const QString& fn, int t ); + +/*! + Returns TRUE if we are pointing to a real file. + \sa isDir(), isSymLink() +*/ +bool QFileInfo::isFile() const +{ + if ( !fic || !cache ) + doStat(); + return fic ? (fic->st.st_mode & STAT_MASK) == STAT_REG : FALSE; +} + +/*! + Returns TRUE if we are pointing to a directory or a symbolic link to + a directory. + \sa isFile(), isSymLink() +*/ + +bool QFileInfo::isDir() const +{ + if ( !fic || !cache ) + doStat(); + return fic ? (fic->st.st_mode & STAT_MASK) == STAT_DIR : FALSE; +} + +/*! + Returns TRUE if we are pointing to a symbolic link. + \sa isFile(), isDir(), readLink() +*/ + +bool QFileInfo::isSymLink() const +{ + if ( !fic || !cache ) + doStat(); + return fic ? fic->isSymLink : FALSE; +} + + +/*! + Returns the name a symlink points to, or a null QString if the + object does not refer to a symbolic link. + + This name may not represent an existing file; it is only a string. + QFileInfo::exists() returns TRUE if the symlink points to an + existing file. + + \sa exists(), isSymLink(), isDir(), isFile() +*/ + +QString QFileInfo::readLink() const +{ + QString r; + +#if defined(_OS_UNIX_) && !defined(_OS_OS2EMX_) + char s[PATH_MAX+1]; + if ( !isSymLink() ) + return QString(); + int len = readlink( QFile::encodeName(fn).data(), s, PATH_MAX ); + if ( len >= 0 ) { + s[len] = '\0'; + r = QFile::decodeName(s); + } +#endif + + return r; +} + +static const uint nobodyID = (uint) -2; + +/*! + Returns the owner of the file. + + On systems where files do not have owners this function returns 0. + + Note that this function can be time-consuming under UNIX. (in the order + of milliseconds on a 486 DX2/66 running Linux). + + \sa ownerId(), group(), groupId() +*/ + +QString QFileInfo::owner() const +{ + passwd *pw = getpwuid( ownerId() ); + if ( pw ) + return QFile::decodeName( pw->pw_name ); + return QString::null; +} + +/*! + Returns the id of the owner of the file. + + On systems where files do not have owners this function returns ((uint) -2). + + \sa owner(), group(), groupId() +*/ + +uint QFileInfo::ownerId() const +{ + if ( !fic || !cache ) + doStat(); + if ( fic ) + return fic->st.st_uid; + return nobodyID; +} + +/*! + Returns the group the file belongs to. + + On systems where files do not have groups this function always + returns 0. + + Note that this function can be time-consuming under UNIX (in the order of + milliseconds on a 486 DX2/66 running Linux). + + \sa groupId(), owner(), ownerId() +*/ + +QString QFileInfo::group() const +{ + struct group *gr = getgrgid( groupId() ); + if ( gr ) + return QFile::decodeName( gr->gr_name ); + return QString::null; +} + +/*! + Returns the id of the group the file belongs to. + + On systems where files do not have groups this function always + returns ((uind) -2). + + \sa group(), owner(), ownerId() +*/ + +uint QFileInfo::groupId() const +{ + if ( !fic || !cache ) + doStat(); + if ( fic ) + return fic->st.st_gid; + return nobodyID; +} + + +/*! + \fn bool QFileInfo::permission( int permissionSpec ) const + + Tests for file permissions. The \e permissionSpec argument can be several + flags of type PermissionSpec or'ed together to check for permission + combinations. + + On systems where files do not have permissions this function always + returns TRUE. + + Example: + \code + QFileInfo fi( "/tmp/tonsils" ); + if ( fi.permission( QFileInfo::WriteUser | QFileInfo::ReadGroup ) ) + qWarning( "Tonsils can be changed by me, and the group can read them."); + if ( fi.permission( QFileInfo::WriteGroup | QFileInfo::WriteOther ) ) + qWarning( "Danger! Tonsils can be changed by the group or others!" ); + \endcode + + \sa isReadable(), isWritable(), isExecutable() +*/ + +bool QFileInfo::permission( int permissionSpec ) const +{ + if ( !fic || !cache ) + doStat(); + if ( fic ) { + uint mask = 0; + if ( permissionSpec & ReadUser) + mask |= S_IRUSR; + if ( permissionSpec & WriteUser) + mask |= S_IWUSR; + if ( permissionSpec & ExeUser) + mask |= S_IXUSR; + if ( permissionSpec & ReadGroup) + mask |= S_IRGRP; + if ( permissionSpec & WriteGroup) + mask |= S_IWGRP; + if ( permissionSpec & ExeGroup) + mask |= S_IXGRP; + if ( permissionSpec & ReadOther) + mask |= S_IROTH; + if ( permissionSpec & WriteOther) + mask |= S_IWOTH; + if ( permissionSpec & ExeOther) + mask |= S_IXOTH; + if ( mask ) { + return (fic->st.st_mode & mask) == mask; + } else { +#if defined(CHECK_NULL) + qWarning( "QFileInfo::permission: permissionSpec is 0" ); +#endif + return TRUE; + } + } else { + return FALSE; + } +} + +/*! + Returns the file size in bytes, or 0 if the file does not exist if the size + cannot be fetched. +*/ + +uint QFileInfo::size() const +{ + if ( !fic || !cache ) + doStat(); + if ( fic ) + return (uint)fic->st.st_size; + else + return 0; +} + + +/*! + Returns the date and time when the file was last modified. + \sa lastRead() +*/ + +QDateTime QFileInfo::lastModified() const +{ + QDateTime dt; + if ( !fic || !cache ) + doStat(); + if ( fic ) + dt.setTime_t( fic->st.st_mtime ); + return dt; +} + +/*! + Returns the date and time when the file was last read (accessed). + + On systems that do not support last read times, the modification time is + returned. + + \sa lastModified() +*/ + +QDateTime QFileInfo::lastRead() const +{ + QDateTime dt; + if ( !fic || !cache ) + doStat(); + if ( fic ) + dt.setTime_t( fic->st.st_atime ); + return dt; +} + + +void QFileInfo::doStat() const +{ + QFileInfo *that = ((QFileInfo*)this); // mutable function + if ( !that->fic ) + that->fic = new QFileInfoCache; + STATBUF *b = &that->fic->st; + that->fic->isSymLink = FALSE; + +#if defined(_OS_UNIX_) && defined(S_IFLNK) + if ( ::lstat(QFile::encodeName(fn),b) == 0 ) { + if ( S_ISLNK( b->st_mode ) ) + that->fic->isSymLink = TRUE; + else + return; + } +#endif + int r; + + r = STAT( QFile::encodeName(fn), b ); + + if ( r != 0 ) { + delete that->fic; + that->fic = 0; + } +} + +/*! + Returns the directory path of the file. + + If \e absPath is TRUE an absolute path is always returned. + + \sa dir(), filePath(), fileName(), isRelative() +*/ +#ifndef QT_NO_DIR +QString QFileInfo::dirPath( bool absPath ) const +{ + QString s; + if ( absPath ) + s = absFilePath(); + else + s = fn; + int pos = s.findRev( '/' ); + if ( pos == -1 ) { + return QString::fromLatin1("."); + } else { + if ( pos == 0 ) + return QString::fromLatin1( "/" ); + return s.left( pos ); + } +} +#endif +/*! + Returns the name of the file, the file path is not included. + + Example: + \code + QFileInfo fi( "/tmp/abdomen.lower" ); + QString name = fi.fileName(); // name = "abdomen.lower" + \endcode + + \sa isRelative(), filePath(), baseName(), extension() +*/ + +QString QFileInfo::fileName() const +{ + int p = fn.findRev( '/' ); + if ( p == -1 ) { + return fn; + } else { + return fn.mid(p+1); + } +} + +/*! + Returns the absolute path name. + + The absolute path name is the file name including the absolute path. If + the QFileInfo is absolute (i.e. not relative) this function will return + the same string as filePath(). + + Note that this function can be time-consuming under UNIX. (in the order + of milliseconds on a 486 DX2/66 running Linux). + + \sa isRelative(), filePath() +*/ +#ifndef QT_NO_DIR +QString QFileInfo::absFilePath() const +{ + if ( QDir::isRelativePath(fn) ) { + QString tmp = QDir::currentDirPath(); + tmp += '/'; + tmp += fn; + makeAbs( tmp ); + return QDir::cleanDirPath( tmp ); + } else { + QString tmp = fn; + makeAbs( tmp ); + return QDir::cleanDirPath( tmp ); + } + +} +#endif diff --git a/trunk/qtools/qfileinfo_win32.cpp b/trunk/qtools/qfileinfo_win32.cpp new file mode 100644 index 0000000..bfcc6ac --- /dev/null +++ b/trunk/qtools/qfileinfo_win32.cpp @@ -0,0 +1,334 @@ +/****************************************************************************** + * + * + * + * Copyright (C) 1997-2001 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + * Based on qfileinfo_unix.cpp + * + * Copyright (C) 1992-2000 Trolltech AS. + */ + +#include "qglobal.h" + +#include "qfileinfo.h" +#include "qfiledefs_p.h" +#include "qdatetime.h" +#include "qdir.h" + +void QFileInfo::slashify( QString& n ) +{ + for ( int i=0; i<(int)n.length(); i++ ) + { + if ( n[i] == '\\' ) + n[i] = '/'; + } +} + +void QFileInfo::makeAbs( QString & ) +{ + // TODO: what to do here? + return; +} + +extern bool qt_file_access( const QString& fn, int t ); + +/*! + Returns TRUE if we are pointing to a real file. + \sa isDir(), isSymLink() +*/ +bool QFileInfo::isFile() const +{ + if ( !fic || !cache ) + doStat(); + return fic ? (fic->st.st_mode & STAT_MASK) == STAT_REG : FALSE; +} + +/*! + Returns TRUE if we are pointing to a directory or a symbolic link to + a directory. + \sa isFile(), isSymLink() +*/ + +bool QFileInfo::isDir() const +{ + if ( !fic || !cache ) + doStat(); + return fic ? (fic->st.st_mode & STAT_MASK) == STAT_DIR : FALSE; +} + +/*! + Returns TRUE if we are pointing to a symbolic link. + \sa isFile(), isDir(), readLink() +*/ + +bool QFileInfo::isSymLink() const +{ + if ( !fic || !cache ) + doStat(); + return fic ? fic->isSymLink : FALSE; +} + + +/*! + Returns the name a symlink points to, or a null QString if the + object does not refer to a symbolic link. + + This name may not represent an existing file; it is only a string. + QFileInfo::exists() returns TRUE if the symlink points to an + existing file. + + \sa exists(), isSymLink(), isDir(), isFile() +*/ + +QString QFileInfo::readLink() const +{ + QString r; + return r; +} + +static const uint nobodyID = (uint) -2; + +/*! + Returns the owner of the file. + + On systems where files do not have owners this function returns + a null string. + + Note that this function can be time-consuming under UNIX. (in the order + of milliseconds on a 486 DX2/66 running Linux). + + \sa ownerId(), group(), groupId() +*/ + +QString QFileInfo::owner() const +{ + return QString::null; +} + +/*! + Returns the id of the owner of the file. + + On systems where files do not have owners this function returns ((uint) -2). + + \sa owner(), group(), groupId() +*/ + +uint QFileInfo::ownerId() const +{ + return (uint)-2; +} + +/*! + Returns the group the file belongs to. + + On systems where files do not have groups this function always + returns 0. + + Note that this function can be time-consuming under UNIX (in the order of + milliseconds on a 486 DX2/66 running Linux). + + \sa groupId(), owner(), ownerId() +*/ + +QString QFileInfo::group() const +{ + return QString::null; +} + +/*! + Returns the id of the group the file belongs to. + + On systems where files do not have groups this function always + returns ((uind) -2). + + \sa group(), owner(), ownerId() +*/ + +uint QFileInfo::groupId() const +{ + return (uint)-2; +} + + +/*! + \fn bool QFileInfo::permission( int permissionSpec ) const + + Tests for file permissions. The \e permissionSpec argument can be several + flags of type PermissionSpec or'ed together to check for permission + combinations. + + On systems where files do not have permissions this function always + returns TRUE. + + Example: + \code + QFileInfo fi( "/tmp/tonsils" ); + if ( fi.permission( QFileInfo::WriteUser | QFileInfo::ReadGroup ) ) + qWarning( "Tonsils can be changed by me, and the group can read them."); + if ( fi.permission( QFileInfo::WriteGroup | QFileInfo::WriteOther ) ) + qWarning( "Danger! Tonsils can be changed by the group or others!" ); + \endcode + + \sa isReadable(), isWritable(), isExecutable() +*/ + +bool QFileInfo::permission( int permissionSpec ) const +{ + return TRUE; +} + +/*! + Returns the file size in bytes, or 0 if the file does not exist if the size + cannot be fetched. +*/ + +uint QFileInfo::size() const +{ + if ( !fic || !cache ) + doStat(); + if ( fic ) + return (uint)fic->st.st_size; + else + return 0; +} + + +/*! + Returns the date and time when the file was last modified. + \sa lastRead() +*/ + +QDateTime QFileInfo::lastModified() const +{ + QDateTime dt; + if ( !fic || !cache ) + doStat(); + if ( fic ) + dt.setTime_t( fic->st.st_mtime ); + return dt; +} + +/*! + Returns the date and time when the file was last read (accessed). + + On systems that do not support last read times, the modification time is + returned. + + \sa lastModified() +*/ + +QDateTime QFileInfo::lastRead() const +{ + QDateTime dt; + if ( !fic || !cache ) + doStat(); + if ( fic ) + dt.setTime_t( fic->st.st_atime ); + return dt; +} + + +void QFileInfo::doStat() const +{ + QFileInfo *that = ((QFileInfo*)this); // mutable function + if ( !that->fic ) + that->fic = new QFileInfoCache; + STATBUF *b = &that->fic->st; + that->fic->isSymLink = FALSE; + + int r; + + r = STAT( QFile::encodeName(fn), b ); + + if ( r != 0 ) { + delete that->fic; + that->fic = 0; + } +} + +/*! + Returns the directory path of the file. + + If \e absPath is TRUE an absolute path is always returned. + + \sa dir(), filePath(), fileName(), isRelative() +*/ +#ifndef QT_NO_DIR +QString QFileInfo::dirPath( bool absPath ) const +{ + QString s; + if ( absPath ) + s = absFilePath(); + else + s = fn; + int pos = s.findRev( '/' ); + if ( pos == -1 ) { + return QString::fromLatin1("."); + } else { + if ( pos == 0 ) + return QString::fromLatin1( "/" ); + return s.left( pos ); + } +} +#endif +/*! + Returns the name of the file, the file path is not included. + + Example: + \code + QFileInfo fi( "/tmp/abdomen.lower" ); + QString name = fi.fileName(); // name = "abdomen.lower" + \endcode + + \sa isRelative(), filePath(), baseName(), extension() +*/ + +QString QFileInfo::fileName() const +{ + int p = fn.findRev( '/' ); + if ( p == -1 ) { + return fn; + } else { + return fn.mid(p+1); + } +} + +/*! + Returns the absolute path name. + + The absolute path name is the file name including the absolute path. If + the QFileInfo is absolute (i.e. not relative) this function will return + the same string as filePath(). + + Note that this function can be time-consuming under UNIX. (in the order + of milliseconds on a 486 DX2/66 running Linux). + + \sa isRelative(), filePath() +*/ +#ifndef QT_NO_DIR +QString QFileInfo::absFilePath() const +{ + if ( QDir::isRelativePath(fn) ) { + QString tmp = QDir::currentDirPath(); + tmp += '/'; + tmp += fn; + makeAbs( tmp ); + return QDir::cleanDirPath( tmp ); + } else { + QString tmp = fn; + makeAbs( tmp ); + return QDir::cleanDirPath( tmp ); + } + +} +#endif diff --git a/trunk/qtools/qgarray.cpp b/trunk/qtools/qgarray.cpp new file mode 100644 index 0000000..efc9de0 --- /dev/null +++ b/trunk/qtools/qgarray.cpp @@ -0,0 +1,747 @@ +/**************************************************************************** +** +** +** Implementation of QGArray class +** +** Created : 930906 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#define QGARRAY_CPP +#include "qgarray.h" +#include "qstring.h" +#include <stdlib.h> + +#define USE_MALLOC // comment to use new/delete + +#undef NEW +#undef DELETE + +#if defined(USE_MALLOC) +#define NEW(type,size) ((type*)malloc(size*sizeof(type))) +#define DELETE(array) (free((char*)array)) +#else +#define NEW(type,size) (new type[size]) +#define DELETE(array) (delete[] array) +#define DONT_USE_REALLOC // comment to use realloc() +#endif + + +// NOT REVISED +/*! + \class QShared qshared.h + \brief The QShared struct is internally used for implementing shared classes. + + It only contains a reference count and member functions to increment and + decrement it. + + Shared classes normally have internal classes that inherit QShared and + add the shared data. + + \sa \link shclass.html Shared Classes\endlink +*/ + + +/*! + \class QGArray qgarray.h + \brief The QGArray class is an internal class for implementing the QArray class. + + QGArray is a strictly internal class that acts as base class for the + QArray template array. + + It contains an array of bytes and has no notion of an array element. +*/ + + +/*! + \internal + Constructs a null array. +*/ + +QGArray::QGArray() +{ + shd = newData(); + CHECK_PTR( shd ); +} + +/*! + \internal + Dummy constructor; does not allocate any data. + + This constructor does not initialize any array data so subclasses + must do it. The intention is to make the code more efficient. +*/ + +QGArray::QGArray( int, int ) +{ +} + +/*! + \internal + Constructs an array with room for \e size bytes. +*/ + +QGArray::QGArray( int size ) +{ + if ( size < 0 ) { +#if defined(CHECK_RANGE) + qWarning( "QGArray: Cannot allocate array with negative length" ); +#endif + size = 0; + } + shd = newData(); + CHECK_PTR( shd ); + if ( size == 0 ) // zero length + return; + shd->data = NEW(char,size); + CHECK_PTR( shd->data ); + shd->len = size; +} + +/*! + \internal + Constructs a shallow copy of \e a. +*/ + +QGArray::QGArray( const QGArray &a ) +{ + shd = a.shd; + shd->ref(); +} + +/*! + \internal + Dereferences the array data and deletes it if this was the last + reference. +*/ + +QGArray::~QGArray() +{ + if ( shd && shd->deref() ) { // delete when last reference + if ( shd->data ) // is lost + DELETE(shd->data); + deleteData( shd ); + } +} + + +/*! + \fn QGArray &QGArray::operator=( const QGArray &a ) + \internal + Assigns a shallow copy of \e a to this array and returns a reference to + this array. Equivalent to assign(). +*/ + +/*! + \fn void QGArray::detach() + \internal + Detaches this array from shared array data. +*/ + +/*! + \fn char *QGArray::data() const + \internal + Returns a pointer to the actual array data. +*/ + +/*! + \fn uint QGArray::nrefs() const + \internal + Returns the reference count. +*/ + +/*! + \fn uint QGArray::size() const + \internal + Returns the size of the array, in bytes. +*/ + + +/*! + \internal + Returns TRUE if this array is equal to \e a, otherwise FALSE. + The comparison is bitwise, of course. +*/ + +bool QGArray::isEqual( const QGArray &a ) const +{ + if ( size() != a.size() ) // different size + return FALSE; + if ( data() == a.data() ) // has same data + return TRUE; + return (size() ? memcmp( data(), a.data(), size() ) : 0) == 0; +} + + +/*! + \internal + Resizes the array to \e newsize bytes. +*/ + +bool QGArray::resize( uint newsize ) +{ + if ( newsize == shd->len ) // nothing to do + return TRUE; + if ( newsize == 0 ) { // remove array + duplicate( 0, 0 ); + return TRUE; + } + if ( shd->data ) { // existing data +#if defined(DONT_USE_REALLOC) + char *newdata = NEW(char,newsize); // manual realloc + memcpy( newdata, shd->data, QMIN(shd->len,newsize) ); + DELETE(shd->data); + shd->data = newdata; +#else + shd->data = (char *)realloc( shd->data, newsize ); +#endif + } else { + shd->data = NEW(char,newsize); + } + CHECK_PTR( shd->data ); + if ( !shd->data ) // no memory + return FALSE; + shd->len = newsize; + return TRUE; +} + +/*! + \internal + Fills the array with the repeated occurrences of \e d, which is + \e sz bytes long. + If \e len is specified as different from -1, then the array will be + resized to \e len*sz before it is filled. + + Returns TRUE if successful, or FALSE if the memory cannot be allocated + (only when \e len != -1). + + \sa resize() +*/ + +bool QGArray::fill( const char *d, int len, uint sz ) +{ + if ( len < 0 ) + len = shd->len/sz; // default: use array length + else if ( !resize( len*sz ) ) + return FALSE; + if ( sz == 1 ) // 8 bit elements + memset( data(), *d, len ); + else if ( sz == 4 ) { // 32 bit elements + register Q_INT32 *x = (Q_INT32*)data(); + Q_INT32 v = *((Q_INT32*)d); + while ( len-- ) + *x++ = v; + } else if ( sz == 2 ) { // 16 bit elements + register Q_INT16 *x = (Q_INT16*)data(); + Q_INT16 v = *((Q_INT16*)d); + while ( len-- ) + *x++ = v; + } else { // any other size elements + register char *x = data(); + while ( len-- ) { // more complicated + memcpy( x, d, sz ); + x += sz; + } + } + return TRUE; +} + +/*! + \internal + Shallow copy. Dereference the current array and references the data + contained in \e a instead. Returns a reference to this array. + \sa operator=() +*/ + +QGArray &QGArray::assign( const QGArray &a ) +{ + a.shd->ref(); // avoid 'a = a' + if ( shd->deref() ) { // delete when last reference + if ( shd->data ) // is lost + DELETE(shd->data); + deleteData( shd ); + } + shd = a.shd; + return *this; +} + +/*! + \internal + Shallow copy. Dereference the current array and references the + array data \e d, which contains \e len bytes. + Returns a reference to this array. + + Do not delete \e d later, because QGArray takes care of that. +*/ + +QGArray &QGArray::assign( const char *d, uint len ) +{ + if ( shd->count > 1 ) { // disconnect this + shd->count--; + shd = newData(); + CHECK_PTR( shd ); + } else { + if ( shd->data ) + DELETE(shd->data); + } + shd->data = (char *)d; + shd->len = len; + return *this; +} + +/*! + \internal + Deep copy. Dereference the current array and obtains a copy of the data + contained in \e a instead. Returns a reference to this array. + \sa assign(), operator=() +*/ + +QGArray &QGArray::duplicate( const QGArray &a ) +{ + if ( a.shd == shd ) { // a.duplicate(a) ! + if ( shd->count > 1 ) { + shd->count--; + register array_data *n = newData(); + CHECK_PTR( n ); + if ( (n->len=shd->len) ) { + n->data = NEW(char,n->len); + CHECK_PTR( n->data ); + if ( n->data ) + memcpy( n->data, shd->data, n->len ); + } else { + n->data = 0; + } + shd = n; + } + return *this; + } + char *oldptr = 0; + if ( shd->count > 1 ) { // disconnect this + shd->count--; + shd = newData(); + CHECK_PTR( shd ); + } else { // delete after copy was made + oldptr = shd->data; + } + if ( a.shd->len ) { // duplicate data + shd->data = NEW(char,a.shd->len); + CHECK_PTR( shd->data ); + if ( shd->data ) + memcpy( shd->data, a.shd->data, a.shd->len ); + } else { + shd->data = 0; + } + shd->len = a.shd->len; + if ( oldptr ) + DELETE(oldptr); + return *this; +} + +/*! + \internal + Deep copy. Dereferences the current array and obtains a copy of the + array data \e d instead. Returns a reference to this array. + \sa assign(), operator=() +*/ + +QGArray &QGArray::duplicate( const char *d, uint len ) +{ + char *data; + if ( d == 0 || len == 0 ) { + data = 0; + len = 0; + } else { + if ( shd->count == 1 && shd->len == len ) { + memcpy( shd->data, d, len ); // use same buffer + return *this; + } + data = NEW(char,len); + CHECK_PTR( data ); + memcpy( data, d, len ); + } + if ( shd->count > 1 ) { // detach + shd->count--; + shd = newData(); + CHECK_PTR( shd ); + } else { // just a single reference + if ( shd->data ) + DELETE(shd->data); + } + shd->data = data; + shd->len = len; + return *this; +} + +/*! + \internal + Resizes this array to \e len bytes and copies the \e len bytes at + address \e into it. + + \warning This function disregards the reference count mechanism. If + other QGArrays reference the same data as this, all will be updated. +*/ + +void QGArray::store( const char *d, uint len ) +{ // store, but not deref + resize( len ); + memcpy( shd->data, d, len ); +} + + +/*! + \fn array_data *QGArray::sharedBlock() const + \internal + Returns a pointer to the shared array block. + + \warning + + Do not use this function. Using it is begging for trouble. We dare + not remove it, for fear of breaking code, but we \e strongly + discourage new use of it. +*/ + +/*! + \fn void QGArray::setSharedBlock( array_data *p ) + \internal + Sets the shared array block to \e p. + + \warning + + Do not use this function. Using it is begging for trouble. We dare + not remove it, for fear of breaking code, but we \e strongly + discourage new use of it. +*/ + + +/*! + \internal + Sets raw data and returns a reference to the array. + + Dereferences the current array and sets the new array data to \e d and + the new array size to \e len. Do not attempt to resize or re-assign the + array data when raw data has been set. + Call resetRawData(d,len) to reset the array. + + Setting raw data is useful because it set QArray data without allocating + memory or copying data. + + Example of intended use: + \code + static uchar bindata[] = { 231, 1, 44, ... }; + QByteArray a; + a.setRawData( bindata, sizeof(bindata) ); // a points to bindata + QDataStream s( a, IO_ReadOnly ); // open on a's data + s >> <something>; // read raw bindata + s.close(); + a.resetRawData( bindata, sizeof(bindata) ); // finished + \endcode + + Example of misuse (do not do this): + \code + static uchar bindata[] = { 231, 1, 44, ... }; + QByteArray a, b; + a.setRawData( bindata, sizeof(bindata) ); // a points to bindata + a.resize( 8 ); // will crash + b = a; // will crash + a[2] = 123; // might crash + // forget to resetRawData - will crash + \endcode + + \warning If you do not call resetRawData(), QGArray will attempt to + deallocate or reallocate the raw data, which might not be too good. + Be careful. +*/ + +QGArray &QGArray::setRawData( const char *d, uint len ) +{ + duplicate( 0, 0 ); // set null data + shd->data = (char *)d; + shd->len = len; + return *this; +} + +/*! + \internal + Resets raw data. + + The arguments must be the data and length that were passed to + setRawData(). This is for consistency checking. +*/ + +void QGArray::resetRawData( const char *d, uint len ) +{ + if ( d != shd->data || len != shd->len ) { +#if defined(CHECK_STATE) + qWarning( "QGArray::resetRawData: Inconsistent arguments" ); +#endif + return; + } + shd->data = 0; + shd->len = 0; +} + + +/*! + \internal + Finds the first occurrence of \e d in the array from position \e index, + where \e sz is the size of the \e d element. + + Note that \e index is given in units of \e sz, not bytes. + + This function only compares whole cells, not bytes. +*/ + +int QGArray::find( const char *d, uint index, uint sz ) const +{ + index *= sz; + if ( index >= shd->len ) { +#if defined(CHECK_RANGE) + qWarning( "QGArray::find: Index %d out of range", index/sz ); +#endif + return -1; + } + register uint i; + uint ii; + switch ( sz ) { + case 1: { // 8 bit elements + register char *x = data() + index; + char v = *d; + for ( i=index; i<shd->len; i++ ) { + if ( *x++ == v ) + break; + } + ii = i; + } + break; + case 2: { // 16 bit elements + register Q_INT16 *x = (Q_INT16*)(data() + index); + Q_INT16 v = *((Q_INT16*)d); + for ( i=index; i<shd->len; i+=2 ) { + if ( *x++ == v ) + break; + } + ii = i/2; + } + break; + case 4: { // 32 bit elements + register Q_INT32 *x = (Q_INT32*)(data() + index); + Q_INT32 v = *((Q_INT32*)d); + for ( i=index; i<shd->len; i+=4 ) { + if ( *x++ == v ) + break; + } + ii = i/4; + } + break; + default: { // any size elements + for ( i=index; i<shd->len; i+=sz ) { + if ( memcmp( d, &shd->data[i], sz ) == 0 ) + break; + } + ii = i/sz; + } + break; + } + return i<shd->len ? (int)ii : -1; +} + +/*! + \internal + Returns the number of occurrences of \e d in the array, where \e sz is + the size of the \e d element. + + This function only compares whole cells, not bytes. +*/ + +int QGArray::contains( const char *d, uint sz ) const +{ + register uint i = shd->len; + int count = 0; + switch ( sz ) { + case 1: { // 8 bit elements + register char *x = data(); + char v = *d; + while ( i-- ) { + if ( *x++ == v ) + count++; + } + } + break; + case 2: { // 16 bit elements + register Q_INT16 *x = (Q_INT16*)data(); + Q_INT16 v = *((Q_INT16*)d); + i /= 2; + while ( i-- ) { + if ( *x++ == v ) + count++; + } + } + break; + case 4: { // 32 bit elements + register Q_INT32 *x = (Q_INT32*)data(); + Q_INT32 v = *((Q_INT32*)d); + i /= 4; + while ( i-- ) { + if ( *x++ == v ) + count++; + } + } + break; + default: { // any size elements + for ( i=0; i<shd->len; i+=sz ) { + if ( memcmp(d, &shd->data[i], sz) == 0 ) + count++; + } + } + break; + } + return count; +} + +static int cmp_item_size = 0; + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +static int cmp_arr( const void *n1, const void *n2 ) +{ + return ( n1 && n2 ) ? memcmp( n1, n2, cmp_item_size ) + : (int)((long)n1 - (long)n2); + // Qt 3.0: Add a virtual compareItems() method and call that instead +} + +#if defined(Q_C_CALLBACKS) +} +#endif + +/*! + \internal + + Sort the array. +*/ + +void QGArray::sort( uint sz ) +{ + int numItems = size() / sz; + if ( numItems < 2 ) + return; + cmp_item_size = sz; + qsort( shd->data, numItems, sz, cmp_arr ); +} + +/*! + \internal + + Binary search; assumes sorted array +*/ + +int QGArray::bsearch( const char *d, uint sz ) const +{ + int numItems = size() / sz; + if ( !numItems ) + return -1; + cmp_item_size = sz; + char* r = (char*)::bsearch( d, shd->data, numItems, sz, cmp_arr ); + if ( !r ) + return -1; + while( (r >= shd->data + sz) && (cmp_arr( r - sz, d ) == 0) ) + r -= sz; // search to first of equal elements; bsearch is undef + return (int)(( r - shd->data ) / sz); +} + + +/*! + \fn char *QGArray::at( uint index ) const + \internal + Returns a pointer to the byte at offset \e index in the array. +*/ + +/*! + \internal + Expand the array if necessary, and copies (the first part of) its + contents from the \e index*zx bytes at \e d. + + Returns TRUE if the operation succeeds, FALSE if it runs out of + memory. + + \warning This function disregards the reference count mechanism. If + other QGArrays reference the same data as this, all will be changed. +*/ + +bool QGArray::setExpand( uint index, const char *d, uint sz ) +{ + index *= sz; + if ( index >= shd->len ) { + if ( !resize( index+sz ) ) // no memory + return FALSE; + } + memcpy( data() + index, d, sz ); + return TRUE; +} + + +/*! + \internal + Prints a warning message if at() or [] is given a bad index. +*/ + +void QGArray::msg_index( uint index ) +{ +#if defined(CHECK_RANGE) + qWarning( "QGArray::at: Absolute index %d out of range", index ); +#else + Q_UNUSED( index ) +#endif +} + + +/*! + \internal + Returns a new shared array block. +*/ + +QGArray::array_data * QGArray::newData() +{ + return new array_data; +} + + +/*! + \internal + Deletes the shared array block. +*/ + +void QGArray::deleteData( array_data *p ) +{ + delete p; + p = 0; +} diff --git a/trunk/qtools/qgarray.h b/trunk/qtools/qgarray.h new file mode 100644 index 0000000..12c463b --- /dev/null +++ b/trunk/qtools/qgarray.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** +** Definition of QGArray class +** +** Created : 930906 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGARRAY_H +#define QGARRAY_H + +#ifndef QT_H +#include "qshared.h" +#endif // QT_H + + +class Q_EXPORT QGArray // generic array +{ +friend class QBuffer; +public: + //### DO NOT USE THIS. IT IS PUBLIC BUT DO NOT USE IT IN NEW CODE. + struct array_data : public QShared { // shared array + array_data() { data=0; len=0; } + char *data; // actual array data + uint len; + }; + QGArray(); +protected: + QGArray( int, int ); // dummy; does not alloc + QGArray( int size ); // allocate 'size' bytes + QGArray( const QGArray &a ); // shallow copy + virtual ~QGArray(); + + QGArray &operator=( const QGArray &a ) { return assign( a ); } + + virtual void detach() { duplicate(*this); } + + char *data() const { return shd->data; } + uint nrefs() const { return shd->count; } + uint size() const { return shd->len; } + bool isEqual( const QGArray &a ) const; + + bool resize( uint newsize ); + + bool fill( const char *d, int len, uint sz ); + + QGArray &assign( const QGArray &a ); + QGArray &assign( const char *d, uint len ); + QGArray &duplicate( const QGArray &a ); + QGArray &duplicate( const char *d, uint len ); + void store( const char *d, uint len ); + + array_data *sharedBlock() const { return shd; } + void setSharedBlock( array_data *p ) { shd=(array_data*)p; } + + QGArray &setRawData( const char *d, uint len ); + void resetRawData( const char *d, uint len ); + + int find( const char *d, uint index, uint sz ) const; + int contains( const char *d, uint sz ) const; + + void sort( uint sz ); + int bsearch( const char *d, uint sz ) const; + + char *at( uint index ) const; + + bool setExpand( uint index, const char *d, uint sz ); + +protected: + virtual array_data *newData(); + virtual void deleteData( array_data *p ); + +private: + static void msg_index( uint ); + array_data *shd; +}; + + +inline char *QGArray::at( uint index ) const +{ +#if defined(CHECK_RANGE) + if ( index >= size() ) { + msg_index( index ); + index = 0; + } +#endif + return &shd->data[index]; +} + + +#endif // QGARRAY_H diff --git a/trunk/qtools/qgcache.cpp b/trunk/qtools/qgcache.cpp new file mode 100644 index 0000000..1fd876d --- /dev/null +++ b/trunk/qtools/qgcache.cpp @@ -0,0 +1,868 @@ +/**************************************************************************** +** +** +** Implementation of QGCache and QGCacheIterator classes +** +** Created : 950208 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qgcache.h" +#include "qlist.h" +#include "qdict.h" +#include "qstring.h" + + +// NOT REVISED +/*! + \class QGCache qgcache.h + + \brief The QGCache class is an internal class for implementing QCache template classes. + + QGCache is a strictly internal class that acts as a base class for the + \link collection.html collection classes\endlink QCache and QIntCache. +*/ + + +/***************************************************************************** + QGCacheItem class (internal cache item) + *****************************************************************************/ + +struct QCacheItem +{ + QCacheItem( void *k, QCollection::Item d, int c, short p ) + : priority(p), skipPriority(p), cost(c), key(k), data(d), node(0) {} + short priority; + short skipPriority; + int cost; + void *key; + QCollection::Item data; + QLNode *node; +}; + + +/***************************************************************************** + QCList class (internal list of cache items) + *****************************************************************************/ + +class QCList : private QList<QCacheItem> +{ +friend class QGCacheIterator; +friend class QCListIt; +public: + QCList() {} + ~QCList(); + + void insert( QCacheItem * ); // insert according to priority + void insert( int, QCacheItem * ); + void take( QCacheItem * ); + void reference( QCacheItem * ); + + void setAutoDelete( bool del ) { QCollection::setAutoDelete(del); } + + bool removeFirst() { return QList<QCacheItem>::removeFirst(); } + bool removeLast() { return QList<QCacheItem>::removeLast(); } + + QCacheItem *first() { return QList<QCacheItem>::first(); } + QCacheItem *last() { return QList<QCacheItem>::last(); } + QCacheItem *prev() { return QList<QCacheItem>::prev(); } + QCacheItem *next() { return QList<QCacheItem>::next(); } + +#if defined(DEBUG) + int inserts; // variables for statistics + int insertCosts; + int insertMisses; + int finds; + int hits; + int hitCosts; + int dumps; + int dumpCosts; +#endif +}; + + +QCList::~QCList() +{ +#if defined(DEBUG) + ASSERT( count() == 0 ); +#endif +} + + +void QCList::insert( QCacheItem *ci ) +{ + QCacheItem *item = first(); + while( item && item->skipPriority > ci->priority ) { + item->skipPriority--; + item = next(); + } + if ( item ) + QList<QCacheItem>::insert( at(), ci ); + else + append( ci ); +#if defined(DEBUG) + ASSERT( ci->node == 0 ); +#endif + ci->node = currentNode(); +} + +inline void QCList::insert( int i, QCacheItem *ci ) +{ + QList<QCacheItem>::insert( i, ci ); +#if defined(DEBUG) + ASSERT( ci->node == 0 ); +#endif + ci->node = currentNode(); +} + + +void QCList::take( QCacheItem *ci ) +{ + if ( ci ) { +#if defined(DEBUG) + ASSERT( ci->node != 0 ); +#endif + takeNode( ci->node ); + ci->node = 0; + } +} + + +inline void QCList::reference( QCacheItem *ci ) +{ +#if defined(DEBUG) + ASSERT( ci != 0 && ci->node != 0 ); +#endif + ci->skipPriority = ci->priority; + relinkNode( ci->node ); // relink as first item +} + + +class QCListIt: public QListIterator<QCacheItem> +{ +public: + QCListIt( const QCList *p ): QListIterator<QCacheItem>( *p ) {} + QCListIt( const QCListIt *p ): QListIterator<QCacheItem>( *p ) {} +}; + + +/***************************************************************************** + QCDict class (internal dictionary of cache items) + *****************************************************************************/ + +// +// Since we need to decide if the dictionary should use an int or const +// char * key (the "bool trivial" argument in the constructor below) +// we cannot use the macro/template dict, but inherit directly from QGDict. +// + +class QCDict : public QGDict +{ +public: + QCDict( uint size, uint kt, bool caseSensitive, bool copyKeys ) + : QGDict( size, (KeyType)kt, caseSensitive, copyKeys ) {} + + QCacheItem *find_string(const QString &key) const + { return (QCacheItem*)((QCDict*)this)->look_string(key, 0, 0); } + QCacheItem *find_ascii(const char *key) const + { return (QCacheItem*)((QCDict*)this)->look_ascii(key, 0, 0); } + QCacheItem *find_int(long key) const + { return (QCacheItem*)((QCDict*)this)->look_int(key, 0, 0); } + + QCacheItem *take_string(const QString &key) + { return (QCacheItem*)QGDict::take_string(key); } + QCacheItem *take_ascii(const char *key) + { return (QCacheItem*)QGDict::take_ascii(key); } + QCacheItem *take_int(long key) + { return (QCacheItem*)QGDict::take_int(key); } + + bool insert_string( const QString &key, const QCacheItem *ci ) + { return QGDict::look_string(key,(Item)ci,1)!=0;} + bool insert_ascii( const char *key, const QCacheItem *ci ) + { return QGDict::look_ascii(key,(Item)ci,1)!=0;} + bool insert_int( long key, const QCacheItem *ci ) + { return QGDict::look_int(key,(Item)ci,1)!=0;} + + bool remove_string( QCacheItem *item ) + { return QGDict::remove_string(*((QString*)(item->key)),item); } + bool remove_ascii( QCacheItem *item ) + { return QGDict::remove_ascii((const char *)item->key,item); } + bool remove_int( QCacheItem *item ) + { return QGDict::remove_int((long)item->key,item);} + + void statistics() { QGDict::statistics(); } +}; + + +/***************************************************************************** + QGDict member functions + *****************************************************************************/ + +/*! + \internal + Constructs a cache. +*/ + +QGCache::QGCache( int maxCost, uint size, KeyType kt, bool caseSensitive, + bool copyKeys ) +{ + keytype = kt; + lruList = new QCList; + CHECK_PTR( lruList ); + lruList->setAutoDelete( TRUE ); + copyk = ((keytype == AsciiKey) && copyKeys); + dict = new QCDict( size, kt, caseSensitive, FALSE ); + CHECK_PTR( dict ); + mCost = maxCost; + tCost = 0; +#if defined(DEBUG) + lruList->inserts = 0; + lruList->insertCosts = 0; + lruList->insertMisses = 0; + lruList->finds = 0; + lruList->hits = 0; + lruList->hitCosts = 0; + lruList->dumps = 0; + lruList->dumpCosts = 0; +#endif +} + +/*! + \internal + Cannot copy a cache. +*/ + +QGCache::QGCache( const QGCache & ) + : QCollection() +{ +#if defined(CHECK_NULL) + qFatal( "QGCache::QGCache(QGCache &): Cannot copy a cache" ); +#endif +} + +/*! + \internal + Removes all items from the cache and destroys it. +*/ + +QGCache::~QGCache() +{ + clear(); // delete everything first + delete dict; + delete lruList; +} + +/*! + \internal + Cannot assign a cache. +*/ + +QGCache &QGCache::operator=( const QGCache & ) +{ +#if defined(CHECK_NULL) + qFatal( "QGCache::operator=: Cannot copy a cache" ); +#endif + return *this; // satisfy the compiler +} + + +/*! + \fn uint QGCache::count() const + \internal + Returns the number of items in the cache. +*/ + +/*! + \fn uint QGCache::size() const + \internal + Returns the size of the hash array. +*/ + +/*! + \fn int QGCache::maxCost() const + \internal + Returns the maximum cache cost. +*/ + +/*! + \fn int QGCache::totalCost() const + \internal + Returns the total cache cost. +*/ + +/*! + \internal + Sets the maximum cache cost. +*/ + +void QGCache::setMaxCost( int maxCost ) +{ + if ( maxCost < tCost ) { + if ( !makeRoomFor(tCost - maxCost) ) // remove excess cost + return; + } + mCost = maxCost; +} + + +/*! + \internal + Inserts an item into the cache. + + \warning If this function returns FALSE, you must delete \a data + yourself. Additionally, be very careful about using \a data after + calling this function, as any other insertions into the cache, from + anywhere in the application, or within Qt itself, could cause the + data to be discarded from the cache, and the pointer to become + invalid. +*/ + +bool QGCache::insert_string( const QString &key, QCollection::Item data, + int cost, int priority) +{ + if ( tCost + cost > mCost ) { + if ( !makeRoomFor(tCost + cost - mCost, priority) ) { +#if defined(DEBUG) + lruList->insertMisses++; +#endif + return FALSE; + } + } +#if defined(DEBUG) + ASSERT( keytype == StringKey ); + lruList->inserts++; + lruList->insertCosts += cost; +#endif + if ( priority < -32768 ) + priority = -32768; + else if ( priority > 32767 ) + priority = 32677; + QCacheItem *ci = new QCacheItem( new QString(key), newItem(data), + cost, (short)priority ); + CHECK_PTR( ci ); + lruList->insert( 0, ci ); + dict->insert_string( key, ci ); + tCost += cost; + return TRUE; +} + + +/*! \internal */ + +bool QGCache::insert_other( const char *key, QCollection::Item data, + int cost, int priority) +{ + if ( tCost + cost > mCost ) { + if ( !makeRoomFor(tCost + cost - mCost, priority) ) { +#if defined(DEBUG) + lruList->insertMisses++; +#endif + return FALSE; + } + } +#if defined(DEBUG) + ASSERT( keytype != StringKey ); + lruList->inserts++; + lruList->insertCosts += cost; +#endif + if ( keytype == AsciiKey && copyk ) + key = qstrdup( key ); + if ( priority < -32768 ) + priority = -32768; + else if ( priority > 32767 ) + priority = 32677; + QCacheItem *ci = new QCacheItem( (void*)key, newItem(data), cost, + (short)priority ); + CHECK_PTR( ci ); + lruList->insert( 0, ci ); + if ( keytype == AsciiKey ) + dict->insert_ascii( key, ci ); + else + dict->insert_int( (long)key, ci ); + tCost += cost; + return TRUE; +} + + +/*! + \internal + Removes an item from the cache. +*/ + +bool QGCache::remove_string( const QString &key ) +{ + Item d = take_string( key ); + if ( d ) + deleteItem( d ); + return d != 0; +} + + +/*! \internal */ + +bool QGCache::remove_other( const char *key ) +{ + Item d = take_other( key ); + if ( d ) + deleteItem( d ); + return d != 0; +} + + +/*! + \internal + Takes an item out of the cache (no delete). +*/ + +QCollection::Item QGCache::take_string( const QString &key ) +{ + QCacheItem *ci = dict->take_string( key ); // take from dict + Item d; + if ( ci ) { + d = ci->data; + tCost -= ci->cost; + lruList->take( ci ); // take from list + delete (QString*)ci->key; + delete ci; + } else { + d = 0; + } + return d; +} + +/*! + \internal + Takes an item out of the cache (no delete). +*/ + +QCollection::Item QGCache::take_other( const char *key ) +{ + QCacheItem *ci; + if ( keytype == AsciiKey ) + ci = dict->take_ascii( key ); + else + ci = dict->take_int( (long)key ); + Item d; + if ( ci ) { + d = ci->data; + tCost -= ci->cost; + lruList->take( ci ); // take from list + if ( copyk ) + delete [] (char *)ci->key; + delete ci; + } else { + d = 0; + } + return d; +} + + +/*! + \internal + Clears the cache. +*/ + +void QGCache::clear() +{ + QCacheItem *ci; + while ( (ci = lruList->first()) ) { + switch ( keytype ) { + case StringKey: + dict->remove_string( ci ); + delete (QString*)ci->key; + break; + case AsciiKey: + dict->remove_ascii( ci ); + if ( copyk ) + delete [] (char*)ci->key; + break; + case IntKey: + dict->remove_int( ci ); + break; + case PtrKey: // unused + break; + } + deleteItem( ci->data ); // delete data + lruList->removeFirst(); // remove from list + } + tCost = 0; +} + + +/*! + \internal + Finds an item in the cache. +*/ + +QCollection::Item QGCache::find_string( const QString &key, bool ref ) const +{ + QCacheItem *ci = dict->find_string( key ); +#if defined(DEBUG) + lruList->finds++; +#endif + if ( ci ) { +#if defined(DEBUG) + lruList->hits++; + lruList->hitCosts += ci->cost; +#endif + if ( ref ) + lruList->reference( ci ); + return ci->data; + } + return 0; +} + + +/*! + \internal + Finds an item in the cache. +*/ + +QCollection::Item QGCache::find_other( const char *key, bool ref ) const +{ + QCacheItem *ci = keytype == AsciiKey ? dict->find_ascii(key) + : dict->find_int((long)key); +#if defined(DEBUG) + lruList->finds++; +#endif + if ( ci ) { +#if defined(DEBUG) + lruList->hits++; + lruList->hitCosts += ci->cost; +#endif + if ( ref ) + lruList->reference( ci ); + return ci->data; + } + return 0; +} + + +/*! + \internal + Allocates cache space for one or more items. +*/ + +bool QGCache::makeRoomFor( int cost, int priority ) +{ + if ( cost > mCost ) // cannot make room for more + return FALSE; // than maximum cost + if ( priority == -1 ) + priority = 32767; + register QCacheItem *ci = lruList->last(); + int cntCost = 0; + int dumps = 0; // number of items to dump + while ( cntCost < cost && ci && ci->skipPriority <= priority ) { + cntCost += ci->cost; + ci = lruList->prev(); + dumps++; + } + if ( cntCost < cost ) // can enough cost be dumped? + return FALSE; // no +#if defined(DEBUG) + ASSERT( dumps > 0 ); +#endif + while ( dumps-- ) { + ci = lruList->last(); +#if defined(DEBUG) + lruList->dumps++; + lruList->dumpCosts += ci->cost; +#endif + switch ( keytype ) { + case StringKey: + dict->remove_string( ci ); + delete (QString*)ci->key; + break; + case AsciiKey: + dict->remove_ascii( ci ); + if ( copyk ) + delete [] (char *)ci->key; + break; + case IntKey: + dict->remove_int( ci ); + break; + case PtrKey: // unused + break; + } + deleteItem( ci->data ); // delete data + lruList->removeLast(); // remove from list + } + tCost -= cntCost; + return TRUE; +} + + +/*! + \internal + Outputs debug statistics. +*/ + +void QGCache::statistics() const +{ +#if defined(DEBUG) + QString line; + line.fill( '*', 80 ); + qDebug( line.ascii() ); + qDebug( "CACHE STATISTICS:" ); + qDebug( "cache contains %d item%s, with a total cost of %d", + count(), count() != 1 ? "s" : "", tCost ); + qDebug( "maximum cost is %d, cache is %d%% full.", + mCost, (200*tCost + mCost) / (mCost*2) ); + qDebug( "find() has been called %d time%s", + lruList->finds, lruList->finds != 1 ? "s" : "" ); + qDebug( "%d of these were hits, items found had a total cost of %d.", + lruList->hits,lruList->hitCosts ); + qDebug( "%d item%s %s been inserted with a total cost of %d.", + lruList->inserts,lruList->inserts != 1 ? "s" : "", + lruList->inserts != 1 ? "have" : "has", lruList->insertCosts ); + qDebug( "%d item%s %s too large or had too low priority to be inserted.", + lruList->insertMisses, lruList->insertMisses != 1 ? "s" : "", + lruList->insertMisses != 1 ? "were" : "was" ); + qDebug( "%d item%s %s been thrown away with a total cost of %d.", + lruList->dumps, lruList->dumps != 1 ? "s" : "", + lruList->dumps != 1 ? "have" : "has", lruList->dumpCosts ); + qDebug( "Statistics from internal dictionary class:" ); + dict->statistics(); + qDebug( line.ascii() ); +#endif +} + + +/***************************************************************************** + QGCacheIterator member functions + *****************************************************************************/ + +/*! + \class QGCacheIterator qgcache.h + + \brief An internal class for implementing QCacheIterator and QIntCacheIterator. + + QGCacheIterator is a strictly internal class that does the heavy work for + QCacheIterator and QIntCacheIterator. +*/ + +/*! + \internal + Constructs an iterator that operates on the cache \e c. +*/ + +QGCacheIterator::QGCacheIterator( const QGCache &c ) +{ + it = new QCListIt( c.lruList ); +#if defined(DEBUG) + ASSERT( it != 0 ); +#endif +} + +/*! + \internal + Constructs an iterator that operates on the same cache as \e ci. +*/ + +QGCacheIterator::QGCacheIterator( const QGCacheIterator &ci ) +{ + it = new QCListIt( ci.it ); +#if defined(DEBUG) + ASSERT( it != 0 ); +#endif +} + +/*! + \internal + Destroys the iterator. +*/ + +QGCacheIterator::~QGCacheIterator() +{ + delete it; +} + +/*! + \internal + Assigns the iterator \e ci to this cache iterator. +*/ + +QGCacheIterator &QGCacheIterator::operator=( const QGCacheIterator &ci ) +{ + *it = *ci.it; + return *this; +} + +/*! + \internal + Returns the number of items in the cache. +*/ + +uint QGCacheIterator::count() const +{ + return it->count(); +} + +/*! + \internal + Returns TRUE if the iterator points to the first item. +*/ + +bool QGCacheIterator::atFirst() const +{ + return it->atFirst(); +} + +/*! + \internal + Returns TRUE if the iterator points to the last item. +*/ + +bool QGCacheIterator::atLast() const +{ + return it->atLast(); +} + +/*! + \internal + Sets the list iterator to point to the first item in the cache. +*/ + +QCollection::Item QGCacheIterator::toFirst() +{ + QCacheItem *item = it->toFirst(); + return item ? item->data : 0; +} + +/*! + \internal + Sets the list iterator to point to the last item in the cache. +*/ + +QCollection::Item QGCacheIterator::toLast() +{ + QCacheItem *item = it->toLast(); + return item ? item->data : 0; +} + +/*! + \internal + Returns the current item. +*/ + +QCollection::Item QGCacheIterator::get() const +{ + QCacheItem *item = it->current(); + return item ? item->data : 0; +} + +/*! + \internal + Returns the key of the current item. +*/ + +QString QGCacheIterator::getKeyString() const +{ + QCacheItem *item = it->current(); + return item ? *((QString*)item->key) : QString::null; +} + +/*! + \internal + Returns the key of the current item, as a \0-terminated C string. +*/ + +const char *QGCacheIterator::getKeyAscii() const +{ + QCacheItem *item = it->current(); + return item ? (const char *)item->key : 0; +} + +/*! + \internal + Returns the key of the current item, as a long. +*/ + +long QGCacheIterator::getKeyInt() const +{ + QCacheItem *item = it->current(); + return item ? (long)item->key : 0; +} + +/*! + \internal + Moves to the next item (postfix). +*/ + +QCollection::Item QGCacheIterator::operator()() +{ + QCacheItem *item = it->operator()(); + return item ? item->data : 0; +} + +/*! + \internal + Moves to the next item (prefix). +*/ + +QCollection::Item QGCacheIterator::operator++() +{ + QCacheItem *item = it->operator++(); + return item ? item->data : 0; +} + +/*! + \internal + Moves \e jumps positions forward. +*/ + +QCollection::Item QGCacheIterator::operator+=( uint jump ) +{ + QCacheItem *item = it->operator+=(jump); + return item ? item->data : 0; +} + +/*! + \internal + Moves to the previous item (prefix). +*/ + +QCollection::Item QGCacheIterator::operator--() +{ + QCacheItem *item = it->operator--(); + return item ? item->data : 0; +} + +/*! + \internal + Moves \e jumps positions backward. +*/ + +QCollection::Item QGCacheIterator::operator-=( uint jump ) +{ + QCacheItem *item = it->operator-=(jump); + return item ? item->data : 0; +} diff --git a/trunk/qtools/qgcache.h b/trunk/qtools/qgcache.h new file mode 100644 index 0000000..5c3e126 --- /dev/null +++ b/trunk/qtools/qgcache.h @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** +** Definition of QGCache and QGCacheIterator classes +** +** Created : 950208 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGCACHE_H +#define QGCACHE_H + +#ifndef QT_H +#include "qcollection.h" +#include "qglist.h" +#include "qgdict.h" +#endif // QT_H + + +class QCList; // internal classes +class QCListIt; +class QCDict; + + +class Q_EXPORT QGCache : public QCollection // generic LRU cache +{ +friend class QGCacheIterator; +protected: + enum KeyType { StringKey, AsciiKey, IntKey, PtrKey }; + // identical to QGDict's, but PtrKey is not used at the moment + + QGCache( int maxCost, uint size, KeyType kt, bool caseSensitive, + bool copyKeys ); + QGCache( const QGCache & ); // not allowed, calls fatal() + ~QGCache(); + QGCache &operator=( const QGCache & ); // not allowed, calls fatal() + + uint count() const { return ((QGDict*)dict)->count(); } + uint size() const { return ((QGDict*)dict)->size(); } + int maxCost() const { return mCost; } + int totalCost() const { return tCost; } + void setMaxCost( int maxCost ); + void clear(); + + bool insert_string( const QString &key, QCollection::Item, + int cost, int priority ); + bool insert_other( const char *key, QCollection::Item, + int cost, int priority ); + bool remove_string( const QString &key ); + bool remove_other( const char *key ); + QCollection::Item take_string( const QString &key ); + QCollection::Item take_other( const char *key ); + + QCollection::Item find_string( const QString &key, bool ref=TRUE ) const; + QCollection::Item find_other( const char *key, bool ref=TRUE ) const; + + void statistics() const; + +private: + bool makeRoomFor( int cost, int priority = -1 ); + KeyType keytype; + QCList *lruList; + QCDict *dict; + int mCost; + int tCost; + bool copyk; +}; + + +class Q_EXPORT QGCacheIterator // generic cache iterator +{ +protected: + QGCacheIterator( const QGCache & ); + QGCacheIterator( const QGCacheIterator & ); + ~QGCacheIterator(); + QGCacheIterator &operator=( const QGCacheIterator & ); + + uint count() const; + bool atFirst() const; + bool atLast() const; + QCollection::Item toFirst(); + QCollection::Item toLast(); + + QCollection::Item get() const; + QString getKeyString() const; + const char *getKeyAscii() const; + long getKeyInt() const; + + QCollection::Item operator()(); + QCollection::Item operator++(); + QCollection::Item operator+=( uint ); + QCollection::Item operator--(); + QCollection::Item operator-=( uint ); + +protected: + QCListIt *it; // iterator on cache list +}; + + +#endif // QGCACHE_H diff --git a/trunk/qtools/qgdict.cpp b/trunk/qtools/qgdict.cpp new file mode 100644 index 0000000..e55d059 --- /dev/null +++ b/trunk/qtools/qgdict.cpp @@ -0,0 +1,1218 @@ +/**************************************************************************** +** +** +** Implementation of QGDict and QGDictIterator classes +** +** Created : 920529 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qgdict.h" +#include "qlist.h" +#include "qstring.h" +#include "qdatastream.h" +#include <ctype.h> + +// NOT REVISED +/*! + \class QGDict qgdict.h + \brief The QGDict class is an internal class for implementing QDict template classes. + + QGDict is a strictly internal class that acts as a base class for the + \link collection.html collection classes\endlink QDict and QIntDict. + + QGDict has some virtual functions that can be reimplemented to customize + the subclasses. + <ul> + <li> read() reads a collection/dictionary item from a QDataStream. + <li> write() writes a collection/dictionary item to a QDataStream. + </ul> + Normally, you do not have to reimplement any of these functions. +*/ + +static const int op_find = 0; +static const int op_insert = 1; +static const int op_replace = 2; + + +class QGDItList : public QList<QGDictIterator> +{ +public: + QGDItList() : QList<QGDictIterator>() {} + QGDItList( const QGDItList &list ) : QList<QGDictIterator>(list) {} + ~QGDItList() { clear(); } + QGDItList &operator=(const QGDItList &list) + { return (QGDItList&)QList<QGDictIterator>::operator=(list); } +}; + + +/***************************************************************************** + Default implementation of special and virtual functions + *****************************************************************************/ + +/*! + \internal + Returns the hash key for \e key, when key is a string. +*/ + +int QGDict::hashKeyString( const QString &key ) +{ +#if defined(CHECK_NULL) + if ( key.isNull() ) + qWarning( "QGDict::hashStringKey: Invalid null key" ); +#endif + int i; + register uint h=0; + uint g; + int len = key.length(); + const QChar *p = key.unicode(); + if ( cases ) { // case sensitive + for ( i=0; i<len; i++ ) { + h = (h<<4) + p[i].cell(); + if ( (g = h & 0xf0000000) ) + h ^= g >> 24; + h &= ~g; + } + } else { // case insensitive + for ( i=0; i<len; i++ ) { + h = (h<<4) + p[i].lower().cell(); + if ( (g = h & 0xf0000000) ) + h ^= g >> 24; + h &= ~g; + } + } + int index = h; + if ( index < 0 ) // adjust index to table size + index = -index; + return index; +} + +/*! + \internal + Returns the hash key for \a key, which is a C string. +*/ + +int QGDict::hashKeyAscii( const char *key ) +{ +#if defined(CHECK_NULL) + if ( key == 0 ) + { + qWarning( "QGDict::hashAsciiKey: Invalid null key" ); + return 0; + } +#endif + register const char *k = key; + register uint h=0; + uint g; + if ( cases ) { // case sensitive + while ( *k ) { + h = (h<<4) + *k++; + if ( (g = h & 0xf0000000) ) + h ^= g >> 24; + h &= ~g; + } + } else { // case insensitive + while ( *k ) { + h = (h<<4) + tolower(*k); + if ( (g = h & 0xf0000000) ) + h ^= g >> 24; + h &= ~g; + k++; + } + } + int index = h; + if ( index < 0 ) // adjust index to table size + index = -index; + return index; +} + +#ifndef QT_NO_DATASTREAM + +/*! + Reads a collection/dictionary item from the stream \e s and returns a + reference to the stream. + + The default implementation sets \e item to 0. + + \sa write() +*/ + +QDataStream& QGDict::read( QDataStream &s, QCollection::Item &item ) +{ + item = 0; + return s; +} + +/*! + Writes a collection/dictionary item to the stream \e s and returns a + reference to the stream. + + \sa read() +*/ + +QDataStream& QGDict::write( QDataStream &s, QCollection::Item ) const +{ + return s; +} +#endif //QT_NO_DATASTREAM + +/***************************************************************************** + QGDict member functions + *****************************************************************************/ + +/*! + \internal + Constructs a dictionary. +*/ + +QGDict::QGDict( uint len, KeyType kt, bool caseSensitive, bool copyKeys ) +{ + init( len, kt, caseSensitive, copyKeys ); +} + + +void QGDict::init( uint len, KeyType kt, bool caseSensitive, bool copyKeys ) +{ + vec = new QBaseBucket *[vlen = len]; // allocate hash table + CHECK_PTR( vec ); + memset( (char*)vec, 0, vlen*sizeof(QBaseBucket*) ); + numItems = 0; + iterators = 0; + // The caseSensitive and copyKey options don't make sense for + // all dict types. + switch ( (keytype = (uint)kt) ) { + case StringKey: + cases = caseSensitive; + copyk = FALSE; + break; + case AsciiKey: + cases = caseSensitive; + copyk = copyKeys; + break; + default: + cases = FALSE; + copyk = FALSE; + break; + } +} + + +/*! + \internal + Constructs a copy of \e dict. +*/ + +QGDict::QGDict( const QGDict & dict ) + : QCollection( dict ) +{ + init( dict.vlen, (KeyType)dict.keytype, dict.cases, dict.copyk ); + QGDictIterator it( dict ); + while ( it.get() ) { // copy from other dict + switch ( keytype ) { + case StringKey: + look_string( it.getKeyString(), it.get(), op_insert ); + break; + case AsciiKey: + look_ascii( it.getKeyAscii(), it.get(), op_insert ); + break; + case IntKey: + look_int( it.getKeyInt(), it.get(), op_insert ); + break; + case PtrKey: + look_ptr( it.getKeyPtr(), it.get(), op_insert ); + break; + } + ++it; + } +} + + +/*! + \internal + Removes all items from the dictionary and destroys it. +*/ + +QGDict::~QGDict() +{ + clear(); // delete everything + delete [] vec; + if ( !iterators ) // no iterators for this dict + return; + QGDictIterator *i = iterators->first(); + while ( i ) { // notify all iterators that + i->dict = 0; // this dict is deleted + i = iterators->next(); + } + delete iterators; +} + + +/*! + \internal + Assigns \e dict to this dictionary. +*/ + +QGDict &QGDict::operator=( const QGDict &dict ) +{ + clear(); + QGDictIterator it( dict ); + while ( it.get() ) { // copy from other dict + switch ( keytype ) { + case StringKey: + look_string( it.getKeyString(), it.get(), op_insert ); + break; + case AsciiKey: + look_ascii( it.getKeyAscii(), it.get(), op_insert ); + break; + case IntKey: + look_int( it.getKeyInt(), it.get(), op_insert ); + break; + case PtrKey: + look_ptr( it.getKeyPtr(), it.get(), op_insert ); + break; + } + ++it; + } + return *this; +} + + +/*! \fn QCollection::Item QGDictIterator::get() const + + \internal +*/ + + +/*! \fn QString QGDictIterator::getKeyString() const + + \internal +*/ + + +/*! \fn const char * QGDictIterator::getKeyAscii() const + + \internal +*/ + + +/*! \fn void * QGDictIterator::getKeyPtr() const + + \internal +*/ + + +/*! \fn long QGDictIterator::getKeyInt() const + + \internal +*/ + + +/*! + \fn uint QGDict::count() const + \internal + Returns the number of items in the dictionary. +*/ + +/*! + \fn uint QGDict::size() const + \internal + Returns the size of the hash array. +*/ + + +/*! + \internal + The do-it-all function; op is one of op_find, op_insert, op_replace +*/ + +QCollection::Item QGDict::look_string( const QString &key, QCollection::Item d, int op ) +{ + QStringBucket *n; + int index = hashKeyString(key) % vlen; + if ( op == op_find ) { // find + if ( cases ) { + for ( n=(QStringBucket*)vec[index]; n; + n=(QStringBucket*)n->getNext() ) { + if ( key == n->getKey() ) + return n->getData(); // item found + } + } else { + QString k = key.lower(); + for ( n=(QStringBucket*)vec[index]; n; + n=(QStringBucket*)n->getNext() ) { + if ( k == n->getKey().lower() ) + return n->getData(); // item found + } + } + return 0; // not found + } + if ( op == op_replace ) { // replace + if ( vec[index] != 0 ) // maybe something there + remove_string( key ); + } + // op_insert or op_replace + n = new QStringBucket(key,newItem(d),vec[index]); + CHECK_PTR( n ); +#if defined(CHECK_NULL) + if ( n->getData() == 0 ) + qWarning( "QDict: Cannot insert null item" ); +#endif + vec[index] = n; + numItems++; + return n->getData(); +} + + +/*! \internal */ + +QCollection::Item QGDict::look_ascii( const char *key, QCollection::Item d, int op ) +{ + QAsciiBucket *n; + int index = hashKeyAscii(key) % vlen; + if ( op == op_find ) { // find + if ( cases ) { + for ( n=(QAsciiBucket*)vec[index]; n; + n=(QAsciiBucket*)n->getNext() ) { + if ( qstrcmp(n->getKey(),key) == 0 ) + return n->getData(); // item found + } + } else { + for ( n=(QAsciiBucket*)vec[index]; n; + n=(QAsciiBucket*)n->getNext() ) { + if ( qstricmp(n->getKey(),key) == 0 ) + return n->getData(); // item found + } + } + return 0; // not found + } + if ( op == op_replace ) { // replace + if ( vec[index] != 0 ) // maybe something there + remove_ascii( key ); + } + // op_insert or op_replace + n = new QAsciiBucket(copyk ? qstrdup(key) : key,newItem(d),vec[index]); + CHECK_PTR( n ); +#if defined(CHECK_NULL) + if ( n->getData() == 0 ) + qWarning( "QAsciiDict: Cannot insert null item" ); +#endif + vec[index] = n; + numItems++; + return n->getData(); +} + + +/*! \internal */ + +QCollection::Item QGDict::look_int( long key, QCollection::Item d, int op ) +{ + QIntBucket *n; + int index = (int)((ulong)key % vlen); // simple hash + if ( op == op_find ) { // find + for ( n=(QIntBucket*)vec[index]; n; + n=(QIntBucket*)n->getNext() ) { + if ( n->getKey() == key ) + return n->getData(); // item found + } + return 0; // not found + } + if ( op == op_replace ) { // replace + if ( vec[index] != 0 ) // maybe something there + remove_int( key ); + } + // op_insert or op_replace + n = new QIntBucket(key,newItem(d),vec[index]); + CHECK_PTR( n ); +#if defined(CHECK_NULL) + if ( n->getData() == 0 ) + qWarning( "QIntDict: Cannot insert null item" ); +#endif + vec[index] = n; + numItems++; + return n->getData(); +} + + +/*! \internal */ + +QCollection::Item QGDict::look_ptr( void *key, QCollection::Item d, int op ) +{ + QPtrBucket *n; + int index = (int)((ulong)key % vlen); // simple hash + if ( op == op_find ) { // find + for ( n=(QPtrBucket*)vec[index]; n; + n=(QPtrBucket*)n->getNext() ) { + if ( n->getKey() == key ) + return n->getData(); // item found + } + return 0; // not found + } + if ( op == op_replace ) { // replace + if ( vec[index] != 0 ) // maybe something there + remove_ptr( key ); + } + // op_insert or op_replace + n = new QPtrBucket(key,newItem(d),vec[index]); + CHECK_PTR( n ); +#if defined(CHECK_NULL) + if ( n->getData() == 0 ) + qWarning( "QPtrDict: Cannot insert null item" ); +#endif + vec[index] = n; + numItems++; + return n->getData(); +} + + +/*! + \internal + Changes the size of the hashtable. + The contents of the dictionary are preserved, + but all iterators on the dictionary become invalid. +*/ +void QGDict::resize( uint newsize ) +{ + // Save old information + QBaseBucket **old_vec = vec; + uint old_vlen = vlen; + bool old_copyk = copyk; + + vec = new QBaseBucket *[vlen = newsize]; + CHECK_PTR( vec ); + memset( (char*)vec, 0, vlen*sizeof(QBaseBucket*) ); + numItems = 0; + copyk = FALSE; + + // Reinsert every item from vec, deleting vec as we go + for ( uint index = 0; index < old_vlen; index++ ) { + switch ( keytype ) { + case StringKey: + { + QStringBucket *n=(QStringBucket *)old_vec[index]; + while ( n ) { + look_string( n->getKey(), n->getData(), op_insert ); + QStringBucket *t=(QStringBucket *)n->getNext(); + delete n; + n = t; + } + } + break; + case AsciiKey: + { + QAsciiBucket *n=(QAsciiBucket *)old_vec[index]; + while ( n ) { + look_ascii( n->getKey(), n->getData(), op_insert ); + QAsciiBucket *t=(QAsciiBucket *)n->getNext(); + delete n; + n = t; + } + } + break; + case IntKey: + { + QIntBucket *n=(QIntBucket *)old_vec[index]; + while ( n ) { + look_int( n->getKey(), n->getData(), op_insert ); + QIntBucket *t=(QIntBucket *)n->getNext(); + delete n; + n = t; + } + } + break; + case PtrKey: + { + QPtrBucket *n=(QPtrBucket *)old_vec[index]; + while ( n ) { + look_ptr( n->getKey(), n->getData(), op_insert ); + QPtrBucket *t=(QPtrBucket *)n->getNext(); + delete n; + n = t; + } + } + break; + } + } + delete [] old_vec; + + // Restore state + copyk = old_copyk; + + // Invalidate all iterators, since order is lost + if ( iterators && iterators->count() ) { + QGDictIterator *i = iterators->first(); + while ( i ) { + i->toFirst(); + i = iterators->next(); + } + } +} + +/*! + \internal + Unlinks the bucket with the specified key (and specified data pointer, + if it is set). +*/ + +void QGDict::unlink_common( int index, QBaseBucket *node, QBaseBucket *prev ) +{ + if ( iterators && iterators->count() ) { // update iterators + QGDictIterator *i = iterators->first(); + while ( i ) { // invalidate all iterators + if ( i->curNode == node ) // referring to pending node + i->operator++(); + i = iterators->next(); + } + } + if ( prev ) // unlink node + prev->setNext( node->getNext() ); + else + vec[index] = node->getNext(); + numItems--; +} + +QStringBucket *QGDict::unlink_string( const QString &key, QCollection::Item d ) +{ + if ( numItems == 0 ) // nothing in dictionary + return 0; + QStringBucket *n; + QStringBucket *prev = 0; + int index = hashKeyString(key) % vlen; + if ( cases ) { + for ( n=(QStringBucket*)vec[index]; n; + n=(QStringBucket*)n->getNext() ) { + bool found = (key == n->getKey()); + if ( found && d ) + found = (n->getData() == d); + if ( found ) { + unlink_common(index,n,prev); + return n; + } + prev = n; + } + } else { + QString k = key.lower(); + for ( n=(QStringBucket*)vec[index]; n; + n=(QStringBucket*)n->getNext() ) { + bool found = (k == n->getKey().lower()); + if ( found && d ) + found = (n->getData() == d); + if ( found ) { + unlink_common(index,n,prev); + return n; + } + prev = n; + } + } + return 0; +} + +QAsciiBucket *QGDict::unlink_ascii( const char *key, QCollection::Item d ) +{ + if ( numItems == 0 ) // nothing in dictionary + return 0; + QAsciiBucket *n; + QAsciiBucket *prev = 0; + int index = hashKeyAscii(key) % vlen; + for ( n=(QAsciiBucket *)vec[index]; n; n=(QAsciiBucket *)n->getNext() ) { + bool found = (cases ? qstrcmp(n->getKey(),key) + : qstricmp(n->getKey(),key)) == 0; + if ( found && d ) + found = (n->getData() == d); + if ( found ) { + unlink_common(index,n,prev); + return n; + } + prev = n; + } + return 0; +} + +QIntBucket *QGDict::unlink_int( long key, QCollection::Item d ) +{ + if ( numItems == 0 ) // nothing in dictionary + return 0; + QIntBucket *n; + QIntBucket *prev = 0; + int index = (int)((ulong)key % vlen); + for ( n=(QIntBucket *)vec[index]; n; n=(QIntBucket *)n->getNext() ) { + bool found = (n->getKey() == key); + if ( found && d ) + found = (n->getData() == d); + if ( found ) { + unlink_common(index,n,prev); + return n; + } + prev = n; + } + return 0; +} + +QPtrBucket *QGDict::unlink_ptr( void *key, QCollection::Item d ) +{ + if ( numItems == 0 ) // nothing in dictionary + return 0; + QPtrBucket *n; + QPtrBucket *prev = 0; + int index = (int)((ulong)key % vlen); + for ( n=(QPtrBucket *)vec[index]; n; n=(QPtrBucket *)n->getNext() ) { + bool found = (n->getKey() == key); + if ( found && d ) + found = (n->getData() == d); + if ( found ) { + unlink_common(index,n,prev); + return n; + } + prev = n; + } + return 0; +} + + +/*! + \internal + Removes the item with the specified key. If item is non-null, + the remove will match the \a item as well (used to remove an + item when several items have the same key). +*/ + +bool QGDict::remove_string( const QString &key, QCollection::Item item ) +{ + QStringBucket *n = unlink_string( key, item ); + if ( n ) { + deleteItem( n->getData() ); + delete n; + return TRUE; + } else { + return FALSE; + } +} + + +/*! \internal */ + +bool QGDict::remove_ascii( const char *key, QCollection::Item item ) +{ + QAsciiBucket *n = unlink_ascii( key, item ); + if ( n ) { + if ( copyk ) + delete [] (char *)n->getKey(); + deleteItem( n->getData() ); + delete n; + } + return n != 0; +} + + +/*! \internal */ + +bool QGDict::remove_int( long key, QCollection::Item item ) +{ + QIntBucket *n = unlink_int( key, item ); + if ( n ) { + deleteItem( n->getData() ); + delete n; + } + return n != 0; +} + + +/*! \internal */ + +bool QGDict::remove_ptr( void *key, QCollection::Item item ) +{ + QPtrBucket *n = unlink_ptr( key, item ); + if ( n ) { + deleteItem( n->getData() ); + delete n; + } + return n != 0; +} + + +/*! \internal */ + +QCollection::Item QGDict::take_string( const QString &key ) +{ + QStringBucket *n = unlink_string( key ); + Item d; + if ( n ) { + d = n->getData(); + delete n; + } else { + d = 0; + } + return d; +} + + +/*! \internal */ + +QCollection::Item QGDict::take_ascii( const char *key ) +{ + QAsciiBucket *n = unlink_ascii( key ); + Item d; + if ( n ) { + if ( copyk ) + delete [] (char *)n->getKey(); + d = n->getData(); + delete n; + } else { + d = 0; + } + return d; +} + + +/*! \internal */ + +QCollection::Item QGDict::take_int( long key ) +{ + QIntBucket *n = unlink_int( key ); + Item d; + if ( n ) { + d = n->getData(); + delete n; + } else { + d = 0; + } + return d; +} + + +/*! \internal */ + +QCollection::Item QGDict::take_ptr( void *key ) +{ + QPtrBucket *n = unlink_ptr( key ); + Item d; + if ( n ) { + d = n->getData(); + delete n; + } else { + d = 0; + } + return d; +} + + +/*! + \internal + Removes all items from the dictionary. +*/ + +void QGDict::clear() +{ + if ( !numItems ) + return; + numItems = 0; // disable remove() function + for ( uint j=0; j<vlen; j++ ) { // destroy hash table + if ( vec[j] ) { + switch ( keytype ) { + case StringKey: + { + QStringBucket *n=(QStringBucket *)vec[j]; + while ( n ) { + QStringBucket *next = (QStringBucket*)n->getNext(); + deleteItem( n->getData() ); + delete n; + n = next; + } + } + break; + case AsciiKey: + { + QAsciiBucket *n=(QAsciiBucket *)vec[j]; + while ( n ) { + QAsciiBucket *next = (QAsciiBucket*)n->getNext(); + if ( copyk ) + delete [] (char *)n->getKey(); + deleteItem( n->getData() ); + delete n; + n = next; + } + } + break; + case IntKey: + { + QIntBucket *n=(QIntBucket *)vec[j]; + while ( n ) { + QIntBucket *next = (QIntBucket*)n->getNext(); + deleteItem( n->getData() ); + delete n; + n = next; + } + } + break; + case PtrKey: + { + QPtrBucket *n=(QPtrBucket *)vec[j]; + while ( n ) { + QPtrBucket *next = (QPtrBucket*)n->getNext(); + deleteItem( n->getData() ); + delete n; + n = next; + } + } + break; + } + vec[j] = 0; // detach list of buckets + } + } + if ( iterators && iterators->count() ) { // invalidate all iterators + QGDictIterator *i = iterators->first(); + while ( i ) { + i->curNode = 0; + i = iterators->next(); + } + } +} + + +/*! + \internal + Outputs debug statistics. +*/ + +void QGDict::statistics() const +{ +#if defined(DEBUG) + QString line; + line.fill( '-', 60 ); + double real, ideal; + qDebug( line.ascii() ); + qDebug( "DICTIONARY STATISTICS:" ); + if ( count() == 0 ) { + qDebug( "Empty!" ); + qDebug( line.ascii() ); + return; + } + real = 0.0; + ideal = (float)count()/(2.0*size())*(count()+2.0*size()-1); + uint i = 0; + while ( i<size() ) { + QBaseBucket *n = vec[i]; + int b = 0; + while ( n ) { // count number of buckets + b++; + n = n->getNext(); + } + real = real + (double)b * ((double)b+1.0)/2.0; + char buf[80], *pbuf; + if ( b > 78 ) + b = 78; + pbuf = buf; + while ( b-- ) + *pbuf++ = '*'; + *pbuf = '\0'; + qDebug( buf ); + i++; + } + qDebug( "Array size = %d", size() ); + qDebug( "# items = %d", count() ); + qDebug( "Real dist = %g", real ); + qDebug( "Rand dist = %g", ideal ); + qDebug( "Real/Rand = %g", real/ideal ); + qDebug( line.ascii() ); +#endif // DEBUG +} + + +/***************************************************************************** + QGDict stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +QDataStream &operator>>( QDataStream &s, QGDict &dict ) +{ + return dict.read( s ); +} + +QDataStream &operator<<( QDataStream &s, const QGDict &dict ) +{ + return dict.write( s ); +} + +#if defined(_CC_DEC_) && defined(__alpha) && (__DECCXX_VER >= 50190001) +#pragma message disable narrowptr +#endif + +/*! + \internal + Reads a dictionary from the stream \e s. +*/ + +QDataStream &QGDict::read( QDataStream &s ) +{ + uint num; + s >> num; // read number of items + clear(); // clear dict + while ( num-- ) { // read all items + Item d; + switch ( keytype ) { + case StringKey: + { + QString k; + s >> k; + read( s, d ); + look_string( k, d, op_insert ); + } + break; + case AsciiKey: + { + char *k; + s >> k; + read( s, d ); + look_ascii( k, d, op_insert ); + if ( copyk ) + delete [] k; + } + break; + case IntKey: + { + Q_UINT32 k; + s >> k; + read( s, d ); + look_int( k, d, op_insert ); + } + break; + case PtrKey: + { + Q_UINT32 k; + s >> k; + read( s, d ); + // ### cannot insert 0 - this renders the thing + // useless since all pointers are written as 0, + // but hey, serializing pointers? can it be done + // at all, ever? + if ( k ) + look_ptr( (void *)k, d, op_insert ); + } + break; + } + } + return s; +} + +/*! + \internal + Writes the dictionary to the stream \e s. +*/ + +QDataStream& QGDict::write( QDataStream &s ) const +{ + s << count(); // write number of items + uint i = 0; + while ( i<size() ) { + QBaseBucket *n = vec[i]; + while ( n ) { // write all buckets + switch ( keytype ) { + case StringKey: + s << ((QStringBucket*)n)->getKey(); + break; + case AsciiKey: + s << ((QAsciiBucket*)n)->getKey(); + break; + case IntKey: + s << (Q_UINT32)((QIntBucket*)n)->getKey(); + break; + case PtrKey: + s << (Q_UINT32)0; // ### cannot serialize a pointer + break; + } + write( s, n->getData() ); // write data + n = n->getNext(); + } + i++; + } + return s; +} +#endif //QT_NO_DATASTREAM + +/***************************************************************************** + QGDictIterator member functions + *****************************************************************************/ + +/*! + \class QGDictIterator qgdict.h + \brief An internal class for implementing QDictIterator and QIntDictIterator. + + QGDictIterator is a strictly internal class that does the heavy work for + QDictIterator and QIntDictIterator. +*/ + +/*! + \internal + Constructs an iterator that operates on the dictionary \e d. +*/ + +QGDictIterator::QGDictIterator( const QGDict &d ) +{ + dict = (QGDict *)&d; // get reference to dict + toFirst(); // set to first noe + if ( !dict->iterators ) { + dict->iterators = new QGDItList; // create iterator list + CHECK_PTR( dict->iterators ); + } + dict->iterators->append( this ); // attach iterator to dict +} + +/*! + \internal + Constructs a copy of the iterator \e it. +*/ + +QGDictIterator::QGDictIterator( const QGDictIterator &it ) +{ + dict = it.dict; + curNode = it.curNode; + curIndex = it.curIndex; + if ( dict ) + dict->iterators->append( this ); // attach iterator to dict +} + +/*! + \internal + Assigns a copy of the iterator \e it and returns a reference to this + iterator. +*/ + +QGDictIterator &QGDictIterator::operator=( const QGDictIterator &it ) +{ + if ( dict ) // detach from old dict + dict->iterators->removeRef( this ); + dict = it.dict; + curNode = it.curNode; + curIndex = it.curIndex; + if ( dict ) + dict->iterators->append( this ); // attach to new list + return *this; +} + +/*! + \internal + Destroys the iterator. +*/ + +QGDictIterator::~QGDictIterator() +{ + if ( dict ) // detach iterator from dict + dict->iterators->removeRef( this ); +} + + +/*! + \internal + Sets the iterator to point to the first item in the dictionary. +*/ + +QCollection::Item QGDictIterator::toFirst() +{ + if ( !dict ) { +#if defined(CHECK_NULL) + qWarning( "QGDictIterator::toFirst: Dictionary has been deleted" ); +#endif + return 0; + } + if ( dict->count() == 0 ) { // empty dictionary + curNode = 0; + return 0; + } + register uint i = 0; + register QBaseBucket **v = dict->vec; + while ( !(*v++) ) + i++; + curNode = dict->vec[i]; + curIndex = i; + return curNode->getData(); +} + + +/*! + \internal + Moves to the next item (postfix). +*/ + +QCollection::Item QGDictIterator::operator()() +{ + if ( !dict ) { +#if defined(CHECK_NULL) + qWarning( "QGDictIterator::operator(): Dictionary has been deleted" ); +#endif + return 0; + } + if ( !curNode ) + return 0; + QCollection::Item d = curNode->getData(); + this->operator++(); + return d; +} + +/*! + \internal + Moves to the next item (prefix). +*/ + +QCollection::Item QGDictIterator::operator++() +{ + if ( !dict ) { +#if defined(CHECK_NULL) + qWarning( "QGDictIterator::operator++: Dictionary has been deleted" ); +#endif + return 0; + } + if ( !curNode ) + return 0; + curNode = curNode->getNext(); + if ( !curNode ) { // no next bucket + register uint i = curIndex + 1; // look from next vec element + register QBaseBucket **v = &dict->vec[i]; + while ( i < dict->size() && !(*v++) ) + i++; + if ( i == dict->size() ) { // nothing found + curNode = 0; + return 0; + } + curNode = dict->vec[i]; + curIndex = i; + } + return curNode->getData(); +} + +/*! + \internal + Moves \e jumps positions forward. +*/ + +QCollection::Item QGDictIterator::operator+=( uint jumps ) +{ + while ( curNode && jumps-- ) + operator++(); + return curNode ? curNode->getData() : 0; +} diff --git a/trunk/qtools/qgdict.h b/trunk/qtools/qgdict.h new file mode 100644 index 0000000..6243364 --- /dev/null +++ b/trunk/qtools/qgdict.h @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** +** Definition of QGDict and QGDictIterator classes +** +** Created : 920529 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGDICT_H +#define QGDICT_H + +#ifndef QT_H +#include "qcollection.h" +#include "qstring.h" +#endif // QT_H + +class QGDictIterator; +class QGDItList; + + +class QBaseBucket // internal dict node +{ +public: + QCollection::Item getData() { return data; } + QCollection::Item setData( QCollection::Item d ) { return data = d; } + QBaseBucket *getNext() { return next; } + void setNext( QBaseBucket *n) { next = n; } +protected: + QBaseBucket( QCollection::Item d, QBaseBucket *n ) : data(d), next(n) {} + QCollection::Item data; + QBaseBucket *next; +}; + +class QStringBucket : public QBaseBucket +{ +public: + QStringBucket( const QString &k, QCollection::Item d, QBaseBucket *n ) + : QBaseBucket(d,n), key(k) {} + const QString &getKey() const { return key; } +private: + QString key; +}; + +class QAsciiBucket : public QBaseBucket +{ +public: + QAsciiBucket( const char *k, QCollection::Item d, QBaseBucket *n ) + : QBaseBucket(d,n), key(k) {} + const char *getKey() const { return key; } +private: + const char *key; +}; + +class QIntBucket : public QBaseBucket +{ +public: + QIntBucket( long k, QCollection::Item d, QBaseBucket *n ) + : QBaseBucket(d,n), key(k) {} + long getKey() const { return key; } +private: + long key; +}; + +class QPtrBucket : public QBaseBucket +{ +public: + QPtrBucket( void *k, QCollection::Item d, QBaseBucket *n ) + : QBaseBucket(d,n), key(k) {} + void *getKey() const { return key; } +private: + void *key; +}; + + +class Q_EXPORT QGDict : public QCollection // generic dictionary class +{ +public: + uint count() const { return numItems; } + uint size() const { return vlen; } + QCollection::Item look_string( const QString& key, QCollection::Item, + int ); + QCollection::Item look_ascii( const char *key, QCollection::Item, int ); + QCollection::Item look_int( long key, QCollection::Item, int ); + QCollection::Item look_ptr( void *key, QCollection::Item, int ); +#ifndef QT_NO_DATASTREAM + QDataStream &read( QDataStream & ); + QDataStream &write( QDataStream & ) const; +#endif +protected: + enum KeyType { StringKey, AsciiKey, IntKey, PtrKey }; + + QGDict( uint len, KeyType kt, bool cs, bool ck ); + QGDict( const QGDict & ); + ~QGDict(); + + QGDict &operator=( const QGDict & ); + + bool remove_string( const QString &key, QCollection::Item item=0 ); + bool remove_ascii( const char *key, QCollection::Item item=0 ); + bool remove_int( long key, QCollection::Item item=0 ); + bool remove_ptr( void *key, QCollection::Item item=0 ); + QCollection::Item take_string( const QString &key ); + QCollection::Item take_ascii( const char *key ); + QCollection::Item take_int( long key ); + QCollection::Item take_ptr( void *key ); + + void clear(); + void resize( uint ); + + int hashKeyString( const QString & ); + int hashKeyAscii( const char * ); + + void statistics() const; + +#ifndef QT_NO_DATASTREAM + virtual QDataStream &read( QDataStream &, QCollection::Item & ); + virtual QDataStream &write( QDataStream &, QCollection::Item ) const; +#endif +private: + QBaseBucket **vec; + uint vlen; + uint numItems; + uint keytype : 2; + uint cases : 1; + uint copyk : 1; + QGDItList *iterators; + void unlink_common( int, QBaseBucket *, QBaseBucket * ); + QStringBucket *unlink_string( const QString &, + QCollection::Item item = 0 ); + QAsciiBucket *unlink_ascii( const char *, QCollection::Item item = 0 ); + QIntBucket *unlink_int( long, QCollection::Item item = 0 ); + QPtrBucket *unlink_ptr( void *, QCollection::Item item = 0 ); + void init( uint, KeyType, bool, bool ); + friend class QGDictIterator; +}; + + +class Q_EXPORT QGDictIterator // generic dictionary iterator +{ +friend class QGDict; +public: + QGDictIterator( const QGDict & ); + QGDictIterator( const QGDictIterator & ); + QGDictIterator &operator=( const QGDictIterator & ); + ~QGDictIterator(); + + QCollection::Item toFirst(); + + QCollection::Item get() const; + QString getKeyString() const; + const char *getKeyAscii() const; + long getKeyInt() const; + void *getKeyPtr() const; + + QCollection::Item operator()(); + QCollection::Item operator++(); + QCollection::Item operator+=(uint); + +protected: + QGDict *dict; + +private: + QBaseBucket *curNode; + uint curIndex; +}; + +inline QCollection::Item QGDictIterator::get() const +{ + return curNode ? curNode->getData() : 0; +} + +inline QString QGDictIterator::getKeyString() const +{ + return curNode ? ((QStringBucket*)curNode)->getKey() : QString::null; +} + +inline const char *QGDictIterator::getKeyAscii() const +{ + return curNode ? ((QAsciiBucket*)curNode)->getKey() : 0; +} + +inline long QGDictIterator::getKeyInt() const +{ + return curNode ? ((QIntBucket*)curNode)->getKey() : 0; +} + +inline void *QGDictIterator::getKeyPtr() const +{ + return curNode ? ((QPtrBucket*)curNode)->getKey() : 0; +} + + +#endif // QGDICT_H diff --git a/trunk/qtools/qgeneric.h b/trunk/qtools/qgeneric.h new file mode 100644 index 0000000..c2892a0 --- /dev/null +++ b/trunk/qtools/qgeneric.h @@ -0,0 +1,43 @@ +/**************************************************************************** +** +** +** Macros for pasting tokens; utilized by our generic classes +** +** Created : 920529 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGENERIC_H +#define QGENERIC_H + +#error "do not include qgeneric.h any more" + +#endif // QGENERIC_H diff --git a/trunk/qtools/qglist.cpp b/trunk/qtools/qglist.cpp new file mode 100644 index 0000000..f464a73 --- /dev/null +++ b/trunk/qtools/qglist.cpp @@ -0,0 +1,1223 @@ +/**************************************************************************** +** +** +** Implementation of QGList and QGListIterator classes +** +** Created : 920624 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglist.h" +#include "qgvector.h" +#include "qdatastream.h" + + +// NOT REVISED +/*! + \class QLNode qglist.h + \brief The QLNode class is an internal class for the QList template collection. + + QLNode is a doubly linked list node; it has three pointers: + <ol> + <li> Pointer to the previous node. + <li> Pointer to the next node. + <li> Pointer to the actual data. + </ol> + + Sometimes it might be practical to have direct access to the list nodes + in a QList, but it is seldom required. + + \warning Be very careful if you want to access the list nodes. The heap + can easily get corrupted if you make a mistake. + + \sa QList::currentNode(), QList::removeNode(), QList::takeNode() +*/ + +/*! + \fn QCollection::Item QLNode::getData() + Returns a pointer (\c void*) to the actual data in the list node. +*/ + + +/*! + \class QGList qglist.h + \brief The QGList class is an internal class for implementing Qt collection classes. + + QGList is a strictly internal class that acts as a base class for several + \link collection.html collection classes\endlink; QList, QQueue and + QStack. + + QGList has some virtual functions that can be reimplemented to customize + the subclasses. + <ul> + <li> compareItems() compares two collection/list items. + <li> read() reads a collection/list item from a QDataStream. + <li> write() writes a collection/list item to a QDataStream. + </ul> + Normally, you do not have to reimplement any of these functions. + If you still want to reimplement them, see the QStrList class (qstrlist.h), + which is a good example. +*/ + + +/***************************************************************************** + Default implementation of virtual functions + *****************************************************************************/ + +/*! + This virtual function compares two list items. + + Returns: + <ul> + <li> 0 if \e item1 == \e item2 + <li> non-zero if \e item1 != \e item2 + </ul> + + This function returns \e int rather than \e bool so that + reimplementations can return three values and use it to sort by: + + <ul> + <li> 0 if \e item1 == \e item2 + <li> \> 0 (positive integer) if \e item1 \> \e item2 + <li> \< 0 (negative integer) if \e item1 \< \e item2 + </ul> + + The QList::inSort() function requires that compareItems() is implemented + as described here. + + This function should not modify the list because some const functions + call compareItems(). + + The default implementation compares the pointers: + \code + + \endcode +*/ + +int QGList::compareItems( QCollection::Item item1, QCollection::Item item2 ) +{ + return item1 != item2; // compare pointers +} + +#ifndef QT_NO_DATASTREAM +/*! + Reads a collection/list item from the stream \a s and returns a reference + to the stream. + + The default implementation sets \a item to 0. + + \sa write() +*/ + +QDataStream &QGList::read( QDataStream &s, QCollection::Item &item ) +{ + item = 0; + return s; +} + +/*! + Writes a collection/list item to the stream \a s and returns a reference + to the stream. + + The default implementation does nothing. + + \sa read() +*/ + +QDataStream &QGList::write( QDataStream &s, QCollection::Item ) const +{ + return s; +} +#endif // QT_NO_DATASTREAM + +/***************************************************************************** + QGList member functions + *****************************************************************************/ + +/*! + \internal + Constructs an empty list. +*/ + +QGList::QGList() +{ + firstNode = lastNode = curNode = 0; // initialize list + numNodes = 0; + curIndex = -1; + iterators = 0; // initialize iterator list +} + +/*! + \internal + Constructs a copy of \e list. +*/ + +QGList::QGList( const QGList & list ) + : QCollection( list ) +{ + firstNode = lastNode = curNode = 0; // initialize list + numNodes = 0; + curIndex = -1; + iterators = 0; // initialize iterator list + QLNode *n = list.firstNode; + while ( n ) { // copy all items from list + append( n->data ); + n = n->next; + } +} + +/*! + \internal + Removes all items from the list and destroys the list. +*/ + +QGList::~QGList() +{ + clear(); + if ( !iterators ) // no iterators for this list + return; + QGListIterator *i = (QGListIterator*)iterators->first(); + while ( i ) { // notify all iterators that + i->list = 0; // this list is deleted + i->curNode = 0; + i = (QGListIterator*)iterators->next(); + } + delete iterators; +} + + +/*! + \internal + Assigns \e list to this list. +*/ + +QGList& QGList::operator=( const QGList &list ) +{ + clear(); + if ( list.count() > 0 ) { + QLNode *n = list.firstNode; + while ( n ) { // copy all items from list + append( n->data ); + n = n->next; + } + curNode = firstNode; + curIndex = 0; + } + return *this; +} + +/*! + Compares this list with \a list. Retruns TRUE if the lists + contain the same data, else FALSE. +*/ + +bool QGList::operator==( const QGList &list ) const +{ + if ( count() != list.count() ) + return FALSE; + + if ( count() == 0 ) + return TRUE; + + QLNode *n1 = firstNode; + QLNode *n2 = list.firstNode; + while ( n1 && n2 ) { + // should be mutable + if ( ( (QGList*)this )->compareItems( n1->data, n2->data ) != 0 ) + return FALSE; + n1 = n1->next; + n2 = n2->next; + } + + return TRUE; +} + +/*! + \fn uint QGList::count() const + \internal + Returns the number of items in the list. +*/ + + +/*! + \internal + Returns the node at position \e index. Sets this node to current. +*/ + +QLNode *QGList::locate( uint index ) +{ + if ( index == (uint)curIndex ) // current node ? + return curNode; + if ( !curNode && firstNode ) { // set current node + curNode = firstNode; + curIndex = 0; + } + register QLNode *node; + int distance = index - curIndex; // node distance to cur node + bool forward; // direction to traverse + + if ( index >= numNodes ) { +#if defined(CHECK_RANGE) + qWarning( "QGList::locate: Index %d out of range", index ); +#endif + return 0; + } + + if ( distance < 0 ) + distance = -distance; + if ( (uint)distance < index && (uint)distance < numNodes - index ) { + node = curNode; // start from current node + forward = index > (uint)curIndex; + } else if ( index < numNodes - index ) { // start from first node + node = firstNode; + distance = index; + forward = TRUE; + } else { // start from last node + node = lastNode; + distance = numNodes - index - 1; + if ( distance < 0 ) + distance = 0; + forward = FALSE; + } + if ( forward ) { // now run through nodes + while ( distance-- ) + node = node->next; + } else { + while ( distance-- ) + node = node->prev; + } + curIndex = index; // must update index + return curNode = node; +} + + +/*! + \internal + Inserts an item at its sorted position in the list. +*/ + +void QGList::inSort( QCollection::Item d ) +{ + int index = 0; + register QLNode *n = firstNode; + while ( n && compareItems(n->data,d) < 0 ){ // find position in list + n = n->next; + index++; + } + insertAt( index, d ); +} + + +/*! + \internal + Inserts an item at the start of the list. +*/ + +void QGList::prepend( QCollection::Item d ) +{ + register QLNode *n = new QLNode( newItem(d) ); + CHECK_PTR( n ); + n->prev = 0; + if ( (n->next = firstNode) ) // list is not empty + firstNode->prev = n; + else // initialize list + lastNode = n; + firstNode = curNode = n; // curNode affected + numNodes++; + curIndex = 0; +} + + +/*! + \internal + Inserts an item at the end of the list. +*/ + +void QGList::append( QCollection::Item d ) +{ + register QLNode *n = new QLNode( newItem(d) ); + CHECK_PTR( n ); + n->next = 0; + if ( (n->prev = lastNode) ) // list is not empty + lastNode->next = n; + else // initialize list + firstNode = n; + lastNode = curNode = n; // curNode affected + curIndex = numNodes; + numNodes++; +} + + +/*! + \internal + Inserts an item at position \e index in the list. +*/ + +bool QGList::insertAt( uint index, QCollection::Item d ) +{ + if ( index == 0 ) { // insert at head of list + prepend( d ); + return TRUE; + } else if ( index == numNodes ) { // append at tail of list + append( d ); + return TRUE; + } + QLNode *nextNode = locate( index ); + if ( !nextNode ) // illegal position + return FALSE; + QLNode *prevNode = nextNode->prev; + register QLNode *n = new QLNode( newItem(d) ); + CHECK_PTR( n ); + nextNode->prev = n; + prevNode->next = n; + n->prev = prevNode; // link new node into list + n->next = nextNode; + curNode = n; // curIndex set by locate() + numNodes++; + return TRUE; +} + + +/*! + \internal + Relinks node \e n and makes it the first node in the list. +*/ + +void QGList::relinkNode( QLNode *n ) +{ + if ( n == firstNode ) // already first + return; + curNode = n; + unlink(); + n->prev = 0; + if ( (n->next = firstNode) ) // list is not empty + firstNode->prev = n; + else // initialize list + lastNode = n; + firstNode = curNode = n; // curNode affected + numNodes++; + curIndex = 0; +} + + +/*! + \internal + Unlinks the current list node and returns a pointer to this node. +*/ + +QLNode *QGList::unlink() +{ + if ( curNode == 0 ) // null current node + return 0; + register QLNode *n = curNode; // unlink this node + if ( n == firstNode ) { // removing first node ? + if ( (firstNode = n->next) ) { + firstNode->prev = 0; + } else { + lastNode = curNode = 0; // list becomes empty + curIndex = -1; + } + } else { + if ( n == lastNode ) { // removing last node ? + lastNode = n->prev; + lastNode->next = 0; + } else { // neither last nor first node + n->prev->next = n->next; + n->next->prev = n->prev; + } + } + if ( n->next ) { // change current node + curNode = n->next; + } else if ( n->prev ) { + curNode = n->prev; + curIndex--; + } + if ( iterators && iterators->count() ) { // update iterators + QGListIterator *i = (QGListIterator*)iterators->first(); + while ( i ) { // fix all iterators that + if ( i->curNode == n ) // refers to pending node + i->curNode = curNode; + i = (QGListIterator*)iterators->next(); + } + } + numNodes--; + return n; +} + + +/*! + \internal + Removes the node \e n from the list. +*/ + +bool QGList::removeNode( QLNode *n ) +{ +#if defined(CHECK_NULL) + if ( n == 0 || (n->prev && n->prev->next != n) || + (n->next && n->next->prev != n) ) { + qWarning( "QGList::removeNode: Corrupted node" ); + return FALSE; + } +#endif + curNode = n; + unlink(); // unlink node + deleteItem( n->data ); // deallocate this node + delete n; + curNode = firstNode; + curIndex = curNode ? 0 : -1; + return TRUE; +} + +/*! + \internal + Removes the item \e d from the list. Uses compareItems() to find the item. +*/ + +bool QGList::remove( QCollection::Item d ) +{ + if ( d ) { // find the item + if ( find(d) == -1 ) + return FALSE; + } + QLNode *n = unlink(); // unlink node + if ( !n ) + return FALSE; + deleteItem( n->data ); // deallocate this node + delete n; + return TRUE; +} + +/*! + \internal + Removes the item \e d from the list. +*/ + +bool QGList::removeRef( QCollection::Item d ) +{ + if ( d ) { // find the item + if ( findRef(d) == -1 ) + return FALSE; + } + QLNode *n = unlink(); // unlink node + if ( !n ) + return FALSE; + deleteItem( n->data ); // deallocate this node + delete n; + return TRUE; +} + +/*! + \fn bool QGList::removeFirst() + \internal + Removes the first item in the list. +*/ + +/*! + \fn bool QGList::removeLast() + \internal + Removes the last item in the list. +*/ + +/*! + \internal + Removes the item at position \e index from the list. +*/ + +bool QGList::removeAt( uint index ) +{ + if ( !locate(index) ) + return FALSE; + QLNode *n = unlink(); // unlink node + if ( !n ) + return FALSE; + deleteItem( n->data ); // deallocate this node + delete n; + return TRUE; +} + + +/*! + \internal + Takes the node \e n out of the list. +*/ + +QCollection::Item QGList::takeNode( QLNode *n ) +{ +#if defined(CHECK_NULL) + if ( n == 0 || (n->prev && n->prev->next != n) || + (n->next && n->next->prev != n) ) { + qWarning( "QGList::takeNode: Corrupted node" ); + return 0; + } +#endif + curNode = n; + unlink(); // unlink node + Item d = n->data; + delete n; // delete the node, not data + curNode = firstNode; + curIndex = curNode ? 0 : -1; + return d; +} + +/*! + \internal + Takes the current item out of the list. +*/ + +QCollection::Item QGList::take() +{ + QLNode *n = unlink(); // unlink node + Item d = n ? n->data : 0; + delete n; // delete node, keep contents + return d; +} + +/*! + \internal + Takes the item at position \e index out of the list. +*/ + +QCollection::Item QGList::takeAt( uint index ) +{ + if ( !locate(index) ) + return 0; + QLNode *n = unlink(); // unlink node + Item d = n ? n->data : 0; + delete n; // delete node, keep contents + return d; +} + +/*! + \internal + Takes the first item out of the list. +*/ + +QCollection::Item QGList::takeFirst() +{ + first(); + QLNode *n = unlink(); // unlink node + Item d = n ? n->data : 0; + delete n; + return d; +} + +/*! + \internal + Takes the last item out of the list. +*/ + +QCollection::Item QGList::takeLast() +{ + last(); + QLNode *n = unlink(); // unlink node + Item d = n ? n->data : 0; + delete n; + return d; +} + + +/*! + \internal + Removes all items from the list. +*/ + +void QGList::clear() +{ + register QLNode *n = firstNode; + + firstNode = lastNode = curNode = 0; // initialize list + numNodes = 0; + curIndex = -1; + + if ( iterators && iterators->count() ) { + QGListIterator *i = (QGListIterator*)iterators->first(); + while ( i ) { // notify all iterators that + i->curNode = 0; // this list is empty + i = (QGListIterator*)iterators->next(); + } + } + + QLNode *prevNode; + while ( n ) { // for all nodes ... + deleteItem( n->data ); // deallocate data + prevNode = n; + n = n->next; + delete prevNode; // deallocate node + } +} + + +/*! + \internal + Finds an item in the list. +*/ + +int QGList::findRef( QCollection::Item d, bool fromStart ) +{ + register QLNode *n; + int index; + if ( fromStart ) { // start from first node + n = firstNode; + index = 0; + } else { // start from current node + n = curNode; + index = curIndex; + } + while ( n && n->data != d ) { // find exact match + n = n->next; + index++; + } + curNode = n; + curIndex = n ? index : -1; + return curIndex; // return position of item +} + +/*! + \internal + Finds an item in the list. Uses compareItems(). +*/ + +int QGList::find( QCollection::Item d, bool fromStart ) +{ + register QLNode *n; + int index; + if ( fromStart ) { // start from first node + n = firstNode; + index = 0; + } else { // start from current node + n = curNode; + index = curIndex; + } + while ( n && compareItems(n->data,d) ){ // find equal match + n = n->next; + index++; + } + curNode = n; + curIndex = n ? index : -1; + return curIndex; // return position of item +} + + +/*! + \internal + Counts the number an item occurs in the list. +*/ + +uint QGList::containsRef( QCollection::Item d ) const +{ + register QLNode *n = firstNode; + uint count = 0; + while ( n ) { // for all nodes... + if ( n->data == d ) // count # exact matches + count++; + n = n->next; + } + return count; +} + +/*! + \internal + Counts the number an item occurs in the list. Uses compareItems(). +*/ + +uint QGList::contains( QCollection::Item d ) const +{ + register QLNode *n = firstNode; + uint count = 0; + QGList *that = (QGList*)this; // mutable for compareItems() + while ( n ) { // for all nodes... + if ( !that->compareItems(n->data,d) ) // count # equal matches + count++; + n = n->next; + } + return count; +} + + +/*! + \fn QCollection::Item QGList::at( uint index ) + \internal + Sets the item at position \e index to the current item. +*/ + +/*! + \fn int QGList::at() const + \internal + Returns the current index. +*/ + +/*! + \fn QLNode *QGList::currentNode() const + \internal + Returns the current node. +*/ + +/*! + \fn QCollection::Item QGList::get() const + \internal + Returns the current item. +*/ + +/*! + \fn QCollection::Item QGList::cfirst() const + \internal + Returns the first item in the list. +*/ + +/*! + \fn QCollection::Item QGList::clast() const + \internal + Returns the last item in the list. +*/ + + +/*! + \internal + Returns the first list item. Sets this to current. +*/ + +QCollection::Item QGList::first() +{ + if ( firstNode ) { + curIndex = 0; + return (curNode=firstNode)->data; + } + return 0; +} + +/*! + \internal + Returns the last list item. Sets this to current. +*/ + +QCollection::Item QGList::last() +{ + if ( lastNode ) { + curIndex = numNodes-1; + return (curNode=lastNode)->data; + } + return 0; +} + +/*! + \internal + Returns the next list item (after current). Sets this to current. +*/ + +QCollection::Item QGList::next() +{ + if ( curNode ) { + if ( curNode->next ) { + curIndex++; + curNode = curNode->next; + return curNode->data; + } + curIndex = -1; + curNode = 0; + } + return 0; +} + +/*! + \internal + Returns the previous list item (before current). Sets this to current. +*/ + +QCollection::Item QGList::prev() +{ + if ( curNode ) { + if ( curNode->prev ) { + curIndex--; + curNode = curNode->prev; + return curNode->data; + } + curIndex = -1; + curNode = 0; + } + return 0; +} + + +/*! + \internal + Converts the list to a vector. +*/ + +void QGList::toVector( QGVector *vector ) const +{ + vector->clear(); + if ( !vector->resize( count() ) ) + return; + register QLNode *n = firstNode; + uint i = 0; + while ( n ) { + vector->insert( i, n->data ); + n = n->next; + i++; + } +} + +void QGList::heapSortPushDown( QCollection::Item* heap, int first, int last ) +{ + int r = first; + while( r <= last/2 ) { + // Node r has only one child ? + if ( last == 2*r ) { + // Need for swapping ? + if ( compareItems( heap[r], heap[ 2*r ] ) > 0 ) { + QCollection::Item tmp = heap[r]; + heap[ r ] = heap[ 2*r ]; + heap[ 2*r ] = tmp; + } + // That's it ... + r = last; + } else { + // Node has two children + if ( compareItems( heap[r], heap[ 2*r ] ) > 0 && + compareItems( heap[ 2*r ], heap[ 2*r+1 ] ) <= 0 ) { + // Swap with left child + QCollection::Item tmp = heap[r]; + heap[ r ] = heap[ 2*r ]; + heap[ 2*r ] = tmp; + r *= 2; + } else if ( compareItems( heap[r], heap[ 2*r+1 ] ) > 0 && + compareItems( heap[ 2*r+1 ], heap[ 2*r ] ) < 0 ) { + // Swap with right child + QCollection::Item tmp = heap[r]; + heap[ r ] = heap[ 2*r+1 ]; + heap[ 2*r+1 ] = tmp; + r = 2*r+1; + } else { + // We are done + r = last; + } + } + } +} + + +/*! Sorts the list by the result of the virtual compareItems() function. + + The Heap-Sort algorithm is used for sorting. It sorts n items with + O(n*log n) compares. This is the asymptotic optimal solution of the + sorting problem. +*/ + +void QGList::sort() +{ + uint n = count(); + if ( n < 2 ) + return; + + // Create the heap + QCollection::Item* realheap = new QCollection::Item[ n ]; + // Wow, what a fake. But I want the heap to be indexed as 1...n + QCollection::Item* heap = realheap - 1; + int size = 0; + QLNode* insert = firstNode; + for( ; insert != 0; insert = insert->next ) { + heap[++size] = insert->data; + int i = size; + while( i > 1 && compareItems( heap[i], heap[ i / 2 ] ) < 0 ) { + QCollection::Item tmp = heap[ i ]; + heap[ i ] = heap[ i/2 ]; + heap[ i/2 ] = tmp; + i /= 2; + } + } + + insert = firstNode; + // Now do the sorting + for ( int i = n; i > 0; i-- ) { + insert->data = heap[1]; + insert = insert->next; + if ( i > 1 ) { + heap[1] = heap[i]; + heapSortPushDown( heap, 1, i - 1 ); + } + } + + delete [] realheap; +} + + +/***************************************************************************** + QGList stream functions + *****************************************************************************/ + +#ifndef QT_NO_DATASTREAM +QDataStream &operator>>( QDataStream &s, QGList &list ) +{ // read list + return list.read( s ); +} + +QDataStream &operator<<( QDataStream &s, const QGList &list ) +{ // write list + return list.write( s ); +} + +/*! + \internal + Reads a list from the stream \e s. +*/ + +QDataStream &QGList::read( QDataStream &s ) +{ + uint num; + s >> num; // read number of items + clear(); // clear list + while ( num-- ) { // read all items + Item d; + read( s, d ); + CHECK_PTR( d ); + if ( !d ) // no memory + break; + QLNode *n = new QLNode( d ); + CHECK_PTR( n ); + if ( !n ) // no memory + break; + n->next = 0; + if ( (n->prev = lastNode) ) // list is not empty + lastNode->next = n; + else // initialize list + firstNode = n; + lastNode = n; + numNodes++; + } + curNode = firstNode; + curIndex = curNode ? 0 : -1; + return s; +} + +/*! + \internal + Writes the list to the stream \e s. +*/ + +QDataStream &QGList::write( QDataStream &s ) const +{ + s << count(); // write number of items + QLNode *n = firstNode; + while ( n ) { // write all items + write( s, n->data ); + n = n->next; + } + return s; +} + +#endif // QT_NO_DATASTREAM + +/***************************************************************************** + QGListIterator member functions + *****************************************************************************/ + +/*! + \class QGListIterator qglist.h + \brief The QGListIterator class is an internal class for implementing QListIterator. + + QGListIterator is a strictly internal class that does the heavy work for + QListIterator. +*/ + +/*! + \internal + Constructs an iterator that operates on the list \e l. +*/ + +QGListIterator::QGListIterator( const QGList &l ) +{ + list = (QGList *)&l; // get reference to list + curNode = list->firstNode; // set to first node + if ( !list->iterators ) { + list->iterators = new QGList; // create iterator list + CHECK_PTR( list->iterators ); + } + list->iterators->append( this ); // attach iterator to list +} + +/*! + \internal + Constructs a copy of the iterator \e it. +*/ + +QGListIterator::QGListIterator( const QGListIterator &it ) +{ + list = it.list; + curNode = it.curNode; + if ( list ) + list->iterators->append( this ); // attach iterator to list +} + +/*! + \internal + Assigns a copy of the iterator \e it and returns a reference to this + iterator. +*/ + +QGListIterator &QGListIterator::operator=( const QGListIterator &it ) +{ + if ( list ) // detach from old list + list->iterators->removeRef( this ); + list = it.list; + curNode = it.curNode; + if ( list ) + list->iterators->append( this ); // attach to new list + return *this; +} + +/*! + \internal + Destroys the iterator. +*/ + +QGListIterator::~QGListIterator() +{ + if ( list ) // detach iterator from list + list->iterators->removeRef(this); +} + + +/*! + \fn bool QGListIterator::atFirst() const + \internal + Returns TRUE if the iterator points to the first item, otherwise FALSE. +*/ + +/*! + \fn bool QGListIterator::atLast() const + \internal + Returns TRUE if the iterator points to the last item, otherwise FALSE. +*/ + + +/*! + \internal + Sets the list iterator to point to the first item in the list. +*/ + +QCollection::Item QGListIterator::toFirst() +{ + if ( !list ) { +#if defined(CHECK_NULL) + qWarning( "QGListIterator::toFirst: List has been deleted" ); +#endif + return 0; + } + return list->firstNode ? (curNode = list->firstNode)->getData() : 0; +} + +/*! + \internal + Sets the list iterator to point to the last item in the list. +*/ + +QCollection::Item QGListIterator::toLast() +{ + if ( !list ) { +#if defined(CHECK_NULL) + qWarning( "QGListIterator::toLast: List has been deleted" ); +#endif + return 0; + } + return list->lastNode ? (curNode = list->lastNode)->getData() : 0; +} + + +/*! + \fn QCollection::Item QGListIterator::get() const + \internal + Returns the iterator item. +*/ + + +/*! + \internal + Moves to the next item (postfix). +*/ + +QCollection::Item QGListIterator::operator()() +{ + if ( !curNode ) + return 0; + QCollection::Item d = curNode->getData(); + curNode = curNode->next; + return d; +} + +/*! + \internal + Moves to the next item (prefix). +*/ + +QCollection::Item QGListIterator::operator++() +{ + if ( !curNode ) + return 0; + curNode = curNode->next; + return curNode ? curNode->getData() : 0; +} + +/*! + \internal + Moves \e jumps positions forward. +*/ + +QCollection::Item QGListIterator::operator+=( uint jumps ) +{ + while ( curNode && jumps-- ) + curNode = curNode->next; + return curNode ? curNode->getData() : 0; +} + +/*! + \internal + Moves to the previous item (prefix). +*/ + +QCollection::Item QGListIterator::operator--() +{ + if ( !curNode ) + return 0; + curNode = curNode->prev; + return curNode ? curNode->getData() : 0; +} + +/*! + \internal + Moves \e jumps positions backward. +*/ + +QCollection::Item QGListIterator::operator-=( uint jumps ) +{ + while ( curNode && jumps-- ) + curNode = curNode->prev; + return curNode ? curNode->getData() : 0; +} diff --git a/trunk/qtools/qglist.h b/trunk/qtools/qglist.h new file mode 100644 index 0000000..f400b64 --- /dev/null +++ b/trunk/qtools/qglist.h @@ -0,0 +1,257 @@ +/**************************************************************************** +** +** +** Definition of QGList and QGListIterator classes +** +** Created : 920624 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGLIST_H +#define QGLIST_H + +#ifndef QT_H +#include "qcollection.h" +#endif // QT_H + + +/***************************************************************************** + QLNode class (internal doubly linked list node) + *****************************************************************************/ + +class Q_EXPORT QLNode +{ +friend class QGList; +friend class QGListIterator; +public: + QCollection::Item getData() { return data; } +private: + QCollection::Item data; + QLNode *prev; + QLNode *next; + QLNode( QCollection::Item d ) { data = d; } +}; + + +/***************************************************************************** + QGList class + *****************************************************************************/ + +class Q_EXPORT QGList : public QCollection // doubly linked generic list +{ +friend class QGListIterator; +friend class QGVector; // needed by QGVector::toList +public: + uint count() const; // return number of nodes + +#ifndef QT_NO_DATASTREAM + QDataStream &read( QDataStream & ); // read list from stream + QDataStream &write( QDataStream & ) const; // write list to stream +#endif +protected: + QGList(); // create empty list + QGList( const QGList & ); // make copy of other list + virtual ~QGList(); + + QGList &operator=( const QGList & ); // assign from other list + bool operator==( const QGList& ) const; + + void inSort( QCollection::Item ); // add item sorted in list + void append( QCollection::Item ); // add item at end of list + bool insertAt( uint index, QCollection::Item ); // add item at i'th position + void relinkNode( QLNode * ); // relink as first item + bool removeNode( QLNode * ); // remove node + bool remove( QCollection::Item = 0 ); // remove item (0=current) + bool removeRef( QCollection::Item = 0 ); // remove item (0=current) + bool removeFirst(); // remove first item + bool removeLast(); // remove last item + bool removeAt( uint index ); // remove item at i'th position + QCollection::Item takeNode( QLNode * ); // take out node + QCollection::Item take(); // take out current item + QCollection::Item takeAt( uint index ); // take out item at i'th pos + QCollection::Item takeFirst(); // take out first item + QCollection::Item takeLast(); // take out last item + + void sort(); // sort all items; + void clear(); // remove all items + + int findRef( QCollection::Item, bool = TRUE ); // find exact item in list + int find( QCollection::Item, bool = TRUE ); // find equal item in list + + uint containsRef( QCollection::Item ) const; // get number of exact matches + uint contains( QCollection::Item ) const; // get number of equal matches + + QCollection::Item at( uint index ); // access item at i'th pos + int at() const; // get current index + QLNode *currentNode() const; // get current node + + QCollection::Item get() const; // get current item + + QCollection::Item cfirst() const; // get ptr to first list item + QCollection::Item clast() const; // get ptr to last list item + QCollection::Item first(); // set first item in list curr + QCollection::Item last(); // set last item in list curr + QCollection::Item next(); // set next item in list curr + QCollection::Item prev(); // set prev item in list curr + + void toVector( QGVector * ) const; // put items in vector + + virtual int compareItems( QCollection::Item, QCollection::Item ); + +#ifndef QT_NO_DATASTREAM + virtual QDataStream &read( QDataStream &, QCollection::Item & ); + virtual QDataStream &write( QDataStream &, QCollection::Item ) const; +#endif +private: + void prepend( QCollection::Item ); // add item at start of list + + void heapSortPushDown( QCollection::Item* heap, int first, int last ); + + QLNode *firstNode; // first node + QLNode *lastNode; // last node + QLNode *curNode; // current node + int curIndex; // current index + uint numNodes; // number of nodes + QGList *iterators; // list of iterators + + QLNode *locate( uint ); // get node at i'th pos + QLNode *unlink(); // unlink node +}; + + +inline uint QGList::count() const +{ + return numNodes; +} + +inline bool QGList::removeFirst() +{ + first(); + return remove(); +} + +inline bool QGList::removeLast() +{ + last(); + return remove(); +} + +inline int QGList::at() const +{ + return curIndex; +} + +inline QCollection::Item QGList::at( uint index ) +{ + QLNode *n = locate( index ); + return n ? n->data : 0; +} + +inline QLNode *QGList::currentNode() const +{ + return curNode; +} + +inline QCollection::Item QGList::get() const +{ + return curNode ? curNode->data : 0; +} + +inline QCollection::Item QGList::cfirst() const +{ + return firstNode ? firstNode->data : 0; +} + +inline QCollection::Item QGList::clast() const +{ + return lastNode ? lastNode->data : 0; +} + + +/***************************************************************************** + QGList stream functions + *****************************************************************************/ + +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator>>( QDataStream &, QGList & ); +Q_EXPORT QDataStream &operator<<( QDataStream &, const QGList & ); +#endif + +/***************************************************************************** + QGListIterator class + *****************************************************************************/ + +class Q_EXPORT QGListIterator // QGList iterator +{ +friend class QGList; +protected: + QGListIterator( const QGList & ); + QGListIterator( const QGListIterator & ); + QGListIterator &operator=( const QGListIterator & ); + ~QGListIterator(); + + bool atFirst() const; // test if at first item + bool atLast() const; // test if at last item + QCollection::Item toFirst(); // move to first item + QCollection::Item toLast(); // move to last item + + QCollection::Item get() const; // get current item + QCollection::Item operator()(); // get current and move to next + QCollection::Item operator++(); // move to next item (prefix) + QCollection::Item operator+=(uint); // move n positions forward + QCollection::Item operator--(); // move to prev item (prefix) + QCollection::Item operator-=(uint); // move n positions backward + +protected: + QGList *list; // reference to list + +private: + QLNode *curNode; // current node in list +}; + + +inline bool QGListIterator::atFirst() const +{ + return curNode == list->firstNode; +} + +inline bool QGListIterator::atLast() const +{ + return curNode == list->lastNode; +} + +inline QCollection::Item QGListIterator::get() const +{ + return curNode ? curNode->data : 0; +} + + +#endif // QGLIST_H diff --git a/trunk/qtools/qglobal.cpp b/trunk/qtools/qglobal.cpp new file mode 100644 index 0000000..50f5202 --- /dev/null +++ b/trunk/qtools/qglobal.cpp @@ -0,0 +1,685 @@ +/**************************************************************************** +** +** +** Global functions +** +** Created : 920604 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qglobal.h" +#include "qasciidict.h" +#include "qstring.h" +#include <stdio.h> +#include <stdarg.h> +#include <stdlib.h> + +// NOT REVISED + +/*! + \relates QApplication + Returns the Qt version number for the library, typically "1.30" + or "2.1.0". +*/ + +const char *qVersion() +{ + return QT_VERSION_STR; +} + + +/***************************************************************************** + System detection routines + *****************************************************************************/ + +static bool si_alreadyDone = FALSE; +static int si_wordSize; +static bool si_bigEndian; + +/*! + \relates QApplication + Obtains information about the system. + + The system's word size in bits (typically 32) is returned in \e *wordSize. + The \e *bigEndian is set to TRUE if this is a big-endian machine, + or to FALSE if this is a little-endian machine. + + This function calls qFatal() with a message if the computer is truly weird + (i.e. different endianness for 16 bit and 32 bit integers). +*/ + +bool qSysInfo( int *wordSize, bool *bigEndian ) +{ +#if defined(CHECK_NULL) + ASSERT( wordSize != 0 ); + ASSERT( bigEndian != 0 ); +#endif + + if ( si_alreadyDone ) { // run it only once + *wordSize = si_wordSize; + *bigEndian = si_bigEndian; + return TRUE; + } + si_alreadyDone = TRUE; + + si_wordSize = 0; + uint n = (uint)(~0); + while ( n ) { // detect word size + si_wordSize++; + n /= 2; + } + *wordSize = si_wordSize; + + if ( *wordSize != 64 && + *wordSize != 32 && + *wordSize != 16 ) { // word size: 16, 32 or 64 +#if defined(CHECK_RANGE) + qFatal( "qSysInfo: Unsupported system word size %d", *wordSize ); +#endif + return FALSE; + } + if ( sizeof(Q_INT8) != 1 || sizeof(Q_INT16) != 2 || sizeof(Q_INT32) != 4 || + sizeof(float) != 4 || sizeof(double) != 8 ) { +#if defined(CHECK_RANGE) + qFatal( "qSysInfo: Unsupported system data type size" ); +#endif + return FALSE; + } + + bool be16, be32; // determine byte ordering + short ns = 0x1234; + int nl = 0x12345678; + + unsigned char *p = (unsigned char *)(&ns); // 16-bit integer + be16 = *p == 0x12; + + p = (unsigned char *)(&nl); // 32-bit integer + if ( p[0] == 0x12 && p[1] == 0x34 && p[2] == 0x56 && p[3] == 0x78 ) + be32 = TRUE; + else + if ( p[0] == 0x78 && p[1] == 0x56 && p[2] == 0x34 && p[3] == 0x12 ) + be32 = FALSE; + else + be32 = !be16; + + if ( be16 != be32 ) { // strange machine! +#if defined(CHECK_RANGE) + qFatal( "qSysInfo: Inconsistent system byte order" ); +#endif + return FALSE; + } + + *bigEndian = si_bigEndian = be32; + return TRUE; +} + + +/***************************************************************************** + Debug output routines + *****************************************************************************/ + +/*! + \fn void qDebug( const char *msg, ... ) + + \relates QApplication + Prints a debug message, or calls the message handler (if it has been + installed). + + This function takes a format string and a list of arguments, similar to + the C printf() function. + + Example: + \code + qDebug( "my window handle = %x", myWidget->id() ); + \endcode + + Under X11, the text is printed to stderr. Under Windows, the text is + sent to the debugger. + + \warning The internal buffer is limited to 8196 bytes (including the + 0-terminator). + + \sa qWarning(), qFatal(), qInstallMsgHandler(), + \link debug.html Debugging\endlink +*/ + +/*! + \fn void qWarning( const char *msg, ... ) + + \relates QApplication + Prints a warning message, or calls the message handler (if it has been + installed). + + This function takes a format string and a list of arguments, similar to + the C printf() function. + + Example: + \code + void f( int c ) + { + if ( c > 200 ) + qWarning( "f: bad argument, c == %d", c ); + } + \endcode + + Under X11, the text is printed to stderr. Under Windows, the text is + sent to the debugger. + + \warning The internal buffer is limited to 8196 bytes (including the + 0-terminator). + + \sa qDebug(), qFatal(), qInstallMsgHandler(), + \link debug.html Debugging\endlink +*/ + +/*! + \fn void qFatal( const char *msg, ... ) + + \relates QApplication + Prints a fatal error message and exits, or calls the message handler (if it + has been installed). + + This function takes a format string and a list of arguments, similar to + the C printf() function. + + Example: + \code + int divide( int a, int b ) + { + if ( b == 0 ) // program error + qFatal( "divide: cannot divide by zero" ); + return a/b; + } + \endcode + + Under X11, the text is printed to stderr. Under Windows, the text is + sent to the debugger. + + \warning The internal buffer is limited to 8196 bytes (including the + 0-terminator). + + \sa qDebug(), qWarning(), qInstallMsgHandler(), + \link debug.html Debugging\endlink +*/ + + +static msg_handler handler = 0; // pointer to debug handler + + +#ifdef _OS_MAC_ + +static FILE * mac_debug=0; + +void qDebug( const char *msg, ... ) +{ + mac_debug=fopen( "debug.txt", "a+" ); + if(mac_debug) { + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( mac_debug, msg, ap ); + va_end( ap ); + fprintf( mac_debug, "\n" ); // add newline + fflush( mac_debug ); + } + fclose(mac_debug); + } else { + exit(0); + } +} + +// copied... this looks really bad. +void debug( const char *msg, ... ) +{ + mac_debug=fopen( "debug.txt", "a+" ); + if(mac_debug) { + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( mac_debug, msg, ap ); + va_end( ap ); + fprintf( mac_debug, "\n" ); // add newline + fflush( mac_debug ); + } + fclose(mac_debug); + } +} + +void qWarning( const char *msg, ... ) +{ + mac_debug=fopen( "debug.txt", "a+" ); + if(mac_debug) { + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( mac_debug, msg, ap ); + va_end( ap ); + fprintf( mac_debug, "\n" ); // add newline + fflush( mac_debug ); + } + fclose(mac_debug); + } +} + +// copied... this looks really bad. +void warning( const char *msg, ... ) +{ + mac_debug=fopen( "debug.txt", "a+" ); + if(mac_debug) { + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( mac_debug, msg, ap ); + va_end( ap ); + fprintf( mac_debug, "\n" ); // add newline + fflush( mac_debug ); + } + fclose(mac_debug); + } +} + +void qFatal( const char *msg, ... ) +{ + mac_debug=fopen( "debug.txt", "a+"); + if(mac_debug) { + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( mac_debug, msg, ap ); + va_end( ap ); + fprintf( mac_debug, "\n" ); // add newline + fflush( mac_debug ); + } + fclose(mac_debug); + } + exit(0); +} + +// copied... this looks really bad. +void fatal( const char *msg, ... ) +{ + mac_debug=fopen( "debug.txt", "a+" ); + if(mac_debug) { + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( mac_debug, msg, ap ); + va_end( ap ); + fprintf( mac_debug, "\n" ); // add newline + fflush( mac_debug ); + } + fclose(mac_debug); + } + exit(0); +} + +#else + +void qDebug( const char *msg, ... ) +{ + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); // ### vsnprintf would be great here + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( stderr, msg, ap ); + va_end( ap ); + fprintf( stderr, "\n" ); // add newline + } +} + +// copied... this looks really bad. +void debug( const char *msg, ... ) +{ + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtDebugMsg, buf ); + } else { + vfprintf( stderr, msg, ap ); + va_end( ap ); + fprintf( stderr, "\n" ); // add newline + } +} + +void qWarning( const char *msg, ... ) +{ + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtWarningMsg, buf ); + } else { + vfprintf( stderr, msg, ap ); + va_end( ap ); + fprintf( stderr, "\n" ); // add newline + } +} + + +// again, copied +void warning( const char *msg, ... ) +{ + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtWarningMsg, buf ); + } else { + vfprintf( stderr, msg, ap ); + va_end( ap ); + fprintf( stderr, "\n" ); // add newline + } +} + +void qFatal( const char *msg, ... ) +{ + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtFatalMsg, buf ); + } else { + vfprintf( stderr, msg, ap ); + va_end( ap ); + fprintf( stderr, "\n" ); // add newline +#if defined(_OS_UNIX_) && defined(DEBUG) + abort(); // trap; generates core dump +#else + exit( 1 ); // goodbye cruel world +#endif + } +} + +// yet again, copied +void fatal( const char *msg, ... ) +{ + char buf[8196]; + va_list ap; + va_start( ap, msg ); // use variable arg list + if ( handler ) { + vsprintf( buf, msg, ap ); + va_end( ap ); + (*handler)( QtFatalMsg, buf ); + } else { + vfprintf( stderr, msg, ap ); + va_end( ap ); + fprintf( stderr, "\n" ); // add newline +#if defined(_OS_UNIX_) && defined(DEBUG) + abort(); // trap; generates core dump +#else + exit( 1 ); // goodbye cruel world +#endif + } +} + +#endif + + +/*! + \fn void ASSERT( bool test ) + \relates QApplication + Prints a warning message containing the source code file name and line number + if \e test is FALSE. + + This is really a macro defined in qglobal.h. + + ASSERT is useful for testing required conditions in your program. + + Example: + \code + // + // File: div.cpp + // + + #include <qglobal.h> + + int divide( int a, int b ) + { + ASSERT( b != 0 ); // this is line 9 + return a/b; + } + \endcode + + If \c b is zero, the ASSERT statement will output the following message + using the qWarning() function: + \code + ASSERT: "b == 0" in div.cpp (9) + \endcode + + \sa qWarning(), \link debug.html Debugging\endlink +*/ + + +/*! + \fn void CHECK_PTR( void *p ) + \relates QApplication + If \e p is null, a fatal messages says that the program ran out of memory + and exits. If \e p is not null, nothing happens. + + This is really a macro defined in qglobal.h. + + Example: + \code + int *a; + CHECK_PTR( a = new int[80] ); // never do this! + // do this instead: + a = new int[80]; + CHECK_PTR( a ); // this is fine + \endcode + + \sa qFatal(), \link debug.html Debugging\endlink +*/ + + +// +// The CHECK_PTR macro calls this function to check if an allocation went ok. +// + +bool qt_check_pointer( bool c, const char *n, int l ) +{ + if ( c ) + qFatal( "In file %s, line %d: Out of memory", n, l ); + return TRUE; +} + + +static bool firstObsoleteWarning(const char *obj, const char *oldfunc ) +{ + static QAsciiDict<int> *obsoleteDict = 0; + if ( !obsoleteDict ) { // first time func is called + obsoleteDict = new QAsciiDict<int>; +#if defined(DEBUG) + qDebug( + "You are using obsolete functions in the Qt library. Call the function\n" + "qSuppressObsoleteWarnings() to suppress obsolete warnings.\n" + ); +#endif + } + QCString s( obj ); + s += "::"; + s += oldfunc; + if ( obsoleteDict->find(s.data()) == 0 ) { + obsoleteDict->insert( s.data(), (int*)1 ); // anything different from 0 + return TRUE; + } + return FALSE; +} + +static bool suppressObsolete = FALSE; + +void qSuppressObsoleteWarnings( bool suppress ) +{ + suppressObsolete = suppress; +} + +void qObsolete( const char *obj, const char *oldfunc, const char *newfunc ) +{ + if ( suppressObsolete ) + return; + if ( !firstObsoleteWarning(obj, oldfunc) ) + return; + if ( obj ) + qDebug( "%s::%s: This function is obsolete, use %s instead.", + obj, oldfunc, newfunc ); + else + qDebug( "%s: This function is obsolete, use %s instead.", + oldfunc, newfunc ); +} + +void qObsolete( const char *obj, const char *oldfunc ) +{ + if ( suppressObsolete ) + return; + if ( !firstObsoleteWarning(obj, oldfunc) ) + return; + if ( obj ) + qDebug( "%s::%s: This function is obsolete.", obj, oldfunc ); + else + qDebug( "%s: This function is obsolete.", oldfunc ); +} + +void qObsolete( const char *message ) +{ + if ( suppressObsolete ) + return; + if ( !firstObsoleteWarning( "Qt", message) ) + return; + qDebug( "%s", message ); +} + + +/*! + \relates QApplication + Installs a Qt message handler. Returns a pointer to the message handler + previously defined. + + The message handler is a function that prints out debug messages, + warnings and fatal error messages. The Qt library (debug version) + contains hundreds of warning messages that are printed when internal + errors (usually invalid function arguments) occur. If you implement + your own message handler, you get total control of these messages. + + The default message handler prints the message to the standard output + under X11 or to the debugger under Windows. If it is a fatal message, + the application aborts immediately. + + Only one message handler can be defined, since this is usually done on + an application-wide basis to control debug output. + + To restore the message handler, call \c qInstallMsgHandler(0). + + Example: + \code + #include <qapplication.h> + #include <stdio.h> + #include <stdlib.h> + + void myMessageOutput( QtMsgType type, const char *msg ) + { + switch ( type ) { + case QtDebugMsg: + fprintf( stderr, "Debug: %s\n", msg ); + break; + case QtWarningMsg: + fprintf( stderr, "Warning: %s\n", msg ); + break; + case QtFatalMsg: + fprintf( stderr, "Fatal: %s\n", msg ); + abort(); // dump core on purpose + } + } + + int main( int argc, char **argv ) + { + qInstallMsgHandler( myMessageOutput ); + QApplication a( argc, argv ); + ... + return a.exec(); + } + \endcode + + \sa qDebug(), qWarning(), qFatal(), \link debug.html Debugging\endlink +*/ + +msg_handler qInstallMsgHandler( msg_handler h ) +{ + msg_handler old = handler; + handler = h; + return old; +} + + +#ifdef _WS_WIN_ +bool qt_winunicode=FALSE; +#endif diff --git a/trunk/qtools/qglobal.h b/trunk/qtools/qglobal.h new file mode 100644 index 0000000..5417861 --- /dev/null +++ b/trunk/qtools/qglobal.h @@ -0,0 +1,638 @@ +/**************************************************************************** +** +** +** Global type declarations and definitions +** +** Created : 920529 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGLOBAL_H +#define QGLOBAL_H + + +#define QT_VERSION 223 +#define QT_VERSION_STR "2.2.3" + + +// +// The operating system, must be one of: (_OS_x_) +// +// MAC - Macintosh +// MSDOS - MS-DOS and Windows +// OS2 - OS/2 +// OS2EMX - XFree86 on OS/2 (not PM) +// WIN32 - Win32 (Windows 95/98 and Windows NT) +// SUN - SunOS +// SOLARIS - Sun Solaris +// HPUX - HP-UX +// ULTRIX - DEC Ultrix +// LINUX - Linux +// FREEBSD - FreeBSD +// NETBSD - NetBSD +// OPENBSD - OpenBSD +// IRIX - SGI Irix +// OSF - OSF Unix +// BSDI - BSDI Unix +// SCO - SCO of some sort +// AIX - AIX Unix +// UNIXWARE - SCO UnixWare +// GNU - GNU Hurd +// DGUX - DG Unix +// UNIX - Any UNIX bsd/sysv system +// + +#if defined(__APPLE__) || defined(macintosh) +#define _OS_MAC_ +# ifdef MAC_OS_X_VERSION_MIN_REQUIRED +# undef MAC_OS_X_VERSION_MIN_REQUIRED +# endif +# define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_3 +# include <AvailabilityMacros.h> +# if !defined(MAC_OS_X_VERSION_10_3) +# define MAC_OS_X_VERSION_10_3 MAC_OS_X_VERSION_10_2 + 1 +# endif +# if !defined(MAC_OS_X_VERSION_10_4) +# define MAC_OS_X_VERSION_10_4 MAC_OS_X_VERSION_10_3 + 1 +# endif +# if !defined(MAC_OS_X_VERSION_10_5) +# define MAC_OS_X_VERSION_10_5 MAC_OS_X_VERSION_10_4 + 1 +# endif +# if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5) +# error "This version of Mac OS X is unsupported" +# endif +#elif defined(MSDOS) || defined(_MSDOS) || defined(__MSDOS__) +#define _OS_MSDOS_ +#elif defined(OS2) || defined(_OS2) || defined(__OS2__) +#if defined(__EMX__) +#define _OS_OS2EMX_ +#else +#define _OS_OS2_ +#endif +#elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) +#define _OS_WIN32_ +#elif defined(__MWERKS__) && defined(__INTEL__) +#define _OS_WIN32_ +#elif defined(sun) || defined(__sun) || defined(__sun__) +#if defined(__SVR4) +#define _OS_SOLARIS_ +#else +#define _OS_SUN_ +#endif +#elif defined(hpux) || defined(__hpux) || defined(__hpux__) +#define _OS_HPUX_ +#elif defined(ultrix) || defined(__ultrix) || defined(__ultrix__) +#define _OS_ULTRIX_ +#elif defined(reliantunix) +#define _OS_RELIANTUNIX_ +#elif defined(linux) || defined(__linux) || defined(__linux__) || defined(__GNU__) || defined(__GLIBC__) +#define _OS_LINUX_ +#elif defined(__FreeBSD__) +#define _OS_FREEBSD_ +#elif defined(__NetBSD__) +#define _OS_NETBSD_ +#elif defined(__OpenBSD__) +#define _OS_OPENBSD_ +#elif defined(sgi) || defined(__sgi) +#define _OS_IRIX_ +#elif defined(__osf__) +#define _OS_OSF_ +#elif defined(bsdi) || defined(__bsdi__) +#define _OS_BSDI_ +#elif defined(_AIX) +#define _OS_AIX_ +#elif defined(__Lynx__) +#define _OS_LYNXOS_ +#elif defined(_UNIXWARE) +#define _OS_UNIXWARE_ +#elif defined(DGUX) +#define _OS_DGUX_ +#elif defined(__QNX__) +#define _OS_QNX_ +#elif defined(_SCO_DS) || defined(M_UNIX) || defined(M_XENIX) +#define _OS_SCO_ +#elif defined(sco) || defined(_UNIXWARE7) +#define _OS_UNIXWARE7_ +#elif !defined(_SCO_DS) && defined(__USLC__) && defined(__SCO_VERSION__) +#define _OS_UNIXWARE7_ +#elif defined(__CYGWIN__) +#define _OS_CYGWIN_ +#elif defined(__BEOS__) +#define _OS_BEOS_ +#elif defined(__MINT__) +#define _OS_MINT_ +#else +#error "Qt has not been ported to this OS - talk to qt-bugs@trolltech.com" +#endif + +#if defined(_OS_MAC_) || defined(_OS_MSDOS_) || defined(_OS_OS2_) || defined(_OS_WIN32_) +#undef _OS_UNIX_ +#elif !defined(_OS_UNIX_) +#define _OS_UNIX_ +// QT_CLEAN_NAMESPACE is not defined by default; it would break too +// much code. +#if !defined(QT_CLEAN_NAMESPACE) && !defined(UNIX) +// ### remove 3.0 +#define UNIX +#endif +#endif + + +// +// The compiler, must be one of: (_CC_x_) +// +// SYM - Symantec C++ for both PC and Macintosh +// MPW - MPW C++ +// MWERKS - Metrowerks CodeWarrior +// MSVC - Microsoft Visual C/C++ +// BOR - Borland/Turbo C++ +// WAT - Watcom C++ +// GNU - GNU C++ +// COMEAU - Comeau C++ +// EDG - Edison Design Group C++ +// OC - CenterLine C++ +// SUN - Sun C++ +// DEC - DEC C++ +// HP - HPUX C++ +// USLC - SCO UnixWare7 C++ +// CDS - Reliant C++ +// KAI - KAI C++ +// + + +// Should be sorted most-authorative to least-authorative + +#if defined(__SC__) +#define _CC_SYM_ +#elif defined( __KCC ) +#define _CC_KAI_ +#define _CC_EDG_ +#define Q_HAS_BOOL_TYPE +#elif defined(applec) +#define _CC_MPW_ +#elif defined(__MWERKS__) +#define _CC_MWERKS_ +#define Q_HAS_BOOL_TYPE +#elif defined(_MSC_VER) +#define _CC_MSVC_ +#elif defined(__BORLANDC__) || defined(__TURBOC__) +#define _CC_BOR_ +#elif defined(__WATCOMC__) +#define _CC_WAT_ +#define Q_HAS_BOOL_TYPE +#elif defined(__GNUC__) +#define _CC_GNU_ +#if __GNUC__ == 2 && __GNUC_MINOR__ <= 7 +#define Q_FULL_TEMPLATE_INSTANTIATION +#define Q_TEMPLATE_NEEDS_CLASS_DECLARATION +#define Q_TEMPLATE_NEEDS_EXPLICIT_CONVERSION +#define Q_SPURIOUS_NON_VOID_WARNING +#endif +#if __GNUC__ == 2 && __GNUC_MINOR__ >= 95 +#define Q_DELETING_VOID_UNDEFINED +#endif +#if (defined(__arm__) || defined(__ARMEL__)) && !defined(QT_MOC_CPP) +#define Q_PACKED __attribute__ ((packed)) +#endif +#elif defined(__xlC__) +#define _CC_XLC_ +#define Q_FULL_TEMPLATE_INSTANTIATION +#if __xlC__ >= 0x400 +#define Q_HAS_BOOL_TYPE +#endif +#if __xlC__ <= 0x0306 +#define Q_TEMPLATE_NEEDS_EXPLICIT_CONVERSION +#endif +#elif defined(como40) +#define _CC_EDG_ +#define _CC_COMEAU_ +#define Q_HAS_BOOL_TYPE +#define Q_C_CALLBACKS +#elif defined(__USLC__) +#define _CC_USLC_ +#ifdef __EDG__ // UnixWare7 +#define Q_HAS_BOOL_TYPE +#endif +#elif defined(__DECCXX) +#define _CC_DEC_ +#if __DECCXX_VER >= 60060005 +#define Q_HAS_BOOL_TYPE +#endif +#elif defined(__EDG) || defined(__EDG__) +// one observed on SGI DCC, the other documented +#define _CC_EDG_ +#elif defined(OBJECTCENTER) || defined(CENTERLINE_CLPP) +#define _CC_OC_ +#if defined(_BOOL) +#define Q_HAS_BOOL_TYPE +#endif +#elif defined(__SUNPRO_CC) +#define _CC_SUN_ +#if __SUNPRO_CC >= 0x500 +#define Q_HAS_BOOL_TYPE +#define Q_C_CALLBACKS +#endif +#elif defined(__CDS__) +#define _CC_CDS_ +#define Q_HAS_BOOL_TYPE +#elif defined(_OS_HPUX_) +// this test is from aCC online help +#if defined(__HP_aCC) || __cplusplus >= 199707L +// this is the aCC +#define _CC_HP_ACC_ +#define Q_HAS_BOOL_TYPE +#else +// this is the CC +#define _CC_HP_ +#define Q_FULL_TEMPLATE_INSTANTIATION +#define Q_TEMPLATE_NEEDS_EXPLICIT_CONVERSION +#endif // __HP_aCC +#else +#error "Qt has not been tested with this compiler - talk to qt-bugs@trolltech.com" +#endif + +// detect Microsoft compiler version +#ifdef _CC_MSVC_ +#if _MSC_VER >= 1400 +#define _CC_V2005 +#elif _MSC_VER >= 1310 +#define _CC_V2003 +#elif _MSC_VER > 1300 +#define _CC_V2002 +#else +#define _CC_V1998 +#endif +#endif + +#ifndef Q_PACKED +#define Q_PACKED +#endif + +// Window system setting + +#if defined(_OS_MAC_) +#define _WS_MAC_ +#elif defined(_OS_MSDOS_) +#define _WS_WIN16_ +#error "Qt requires Win32 and does not work with Windows 3.x" +#elif defined(_WIN32_X11_) +#define _WS_X11_ +#elif defined(_OS_WIN32_) +#define _WS_WIN32_ +#elif defined(_OS_OS2_) +#error "Qt does not work with OS/2 Presentation Manager or Workplace Shell" +#elif defined(_OS_UNIX_) +#ifdef QWS +#define _WS_QWS_ +#else +#define _WS_X11_ +#endif +#endif + +#if defined(_WS_WIN16_) || defined(_WS_WIN32_) +#define _WS_WIN_ +#endif + + +// +// Some classes do not permit copies to be made of an object. +// These classes contains a private copy constructor and operator= +// to disable copying (the compiler gives an error message). +// Undefine Q_DISABLE_COPY to turn off this checking. +// + +#define Q_DISABLE_COPY + + +// +// Useful type definitions for Qt +// + +#if defined(bool) +#define Q_HAS_BOOL_TYPE +#elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 6) +#define Q_HAS_BOOL_TYPE +#elif _MSC_VER >= 1100 || __BORLANDC__ >= 0x500 +#define Q_HAS_BOOL_TYPE +#elif defined(sgi) && defined(_BOOL) +#define Q_HAS_BOOL_TYPE +#endif + +#if (QT_VERSION >= 300) +#error "Use an enum for bool" +#endif + +#if !defined(Q_HAS_BOOL_TYPE) +#if defined(_CC_MSVC_) +#define _CC_BOOL_DEF_ +#define bool int +#else +typedef int bool; +#endif +#endif + +typedef unsigned char uchar; +typedef unsigned short ushort; +typedef unsigned uint; +typedef unsigned long ulong; +typedef char *pchar; +typedef uchar *puchar; +typedef const char *pcchar; +#if defined(_OS_WIN32_) && !defined(_CC_GNU_) +typedef __int64 int64; +typedef unsigned __int64 uint64; +#else +typedef long long int64; +typedef unsigned long long uint64; +#endif + + +// +// Constant bool values +// + +#ifndef TRUE +const bool FALSE = 0; +const bool TRUE = !0; +#endif + + +#if defined(_CC_MSVC_) +// Workaround for static const members. +#define QT_STATIC_CONST static +#define QT_STATIC_CONST_IMPL +#else +#define QT_STATIC_CONST static const +#define QT_STATIC_CONST_IMPL const +#endif + + + +// +// Utility macros and inline functions +// + +#define QMAX(a,b) ((a) > (b) ? (a) : (b)) +#define QMIN(a,b) ((a) < (b) ? (a) : (b)) +#define QABS(a) ((a) >= 0 ? (a) : -(a)) + +inline int qRound( double d ) +{ + return d > 0.0 ? int(d+0.5) : int(d-0.5); +} + + +// +// Size-dependent types (architechture-dependent byte order) +// + +// QT_CLEAN_NAMESPACE is not defined by default; it would break too +// much code. +#if !defined(QT_CLEAN_NAMESPACE) +typedef signed char INT8; // 8 bit signed +typedef unsigned char UINT8; // 8 bit unsigned +typedef short INT16; // 16 bit signed +typedef unsigned short UINT16; // 16 bit unsigned +typedef int INT32; // 32 bit signed +typedef unsigned int UINT32; // 32 bit unsigned +#endif + +typedef signed char Q_INT8; // 8 bit signed +typedef unsigned char Q_UINT8; // 8 bit unsigned +typedef short Q_INT16; // 16 bit signed +typedef unsigned short Q_UINT16; // 16 bit unsigned +typedef int Q_INT32; // 32 bit signed +typedef unsigned int Q_UINT32; // 32 bit unsigned +typedef long Q_INT64; // up to 64 bit signed +typedef unsigned long Q_UINT64; // up to 64 bit unsigned + +// +// Data stream functions is provided by many classes (defined in qdatastream.h) +// + +class QDataStream; + + + +#ifdef _WS_WIN_ +extern bool qt_winunicode; +#endif + +#ifndef QT_H +#include <qfeatures.h> +#endif // QT_H + +// +// Create Qt DLL if QT_DLL is defined (Windows only) +// + +#if defined(_OS_WIN32_) +#if defined(QT_NODLL) +#undef QT_MAKEDLL +#undef QT_DLL +#endif +#ifdef QT_DLL +#if defined(QT_MAKEDLL) /* create a Qt DLL library */ +#undef QT_DLL +#define Q_EXPORT __declspec(dllexport) +#define Q_TEMPLATEDLL +#undef Q_DISABLE_COPY /* avoid unresolved externals */ +#endif +#endif +#if defined(QT_DLL) /* use a Qt DLL library */ +#define Q_EXPORT __declspec(dllimport) +#define Q_TEMPLATEDLL +#undef Q_DISABLE_COPY /* avoid unresolved externals */ +#endif +#else // ! _OS_WIN32_ +#undef QT_MAKEDLL /* ignore these for other platforms */ +#undef QT_DLL +#endif + +#ifndef Q_EXPORT +#define Q_EXPORT +#endif + +// +// System information +// + +Q_EXPORT const char *qVersion(); +Q_EXPORT bool qSysInfo( int *wordSize, bool *bigEndian ); + + +// +// Debugging and error handling +// + +#if !defined(NO_CHECK) +#define CHECK_STATE // check state of objects etc. +#define CHECK_RANGE // check range of indexes etc. +#define CHECK_NULL // check null pointers +#define CHECK_MATH // check math functions +#endif + +#if !defined(NO_DEBUG) && !defined(DEBUG) +#define DEBUG // display debug messages +#endif + +// +// Avoid some particularly useless warnings from some stupid compilers. +// To get ALL C++ compiler warnings, define CC_WARNINGS or comment out +// the line "#define Q_NO_WARNINGS" +// + +#if !defined(CC_WARNINGS) +#define Q_NO_WARNINGS +#endif +#if defined(Q_NO_WARNINGS) +#if defined(_CC_MSVC_) +#pragma warning(disable: 4244) +#pragma warning(disable: 4275) +#pragma warning(disable: 4514) +#pragma warning(disable: 4800) +#pragma warning(disable: 4097) +#pragma warning(disable: 4706) +#elif defined(_CC_BOR_) +#pragma option -w-inl +#pragma option -w-aus +#pragma warn -inl +#pragma warn -pia +#pragma warn -ccc +#pragma warn -rch +#pragma warn -sig +#elif defined(_CC_MWERKS_) +#pragma warn_possunwant off +#endif +#endif // Q_NO_WARNINGS + +// +// Avoid dead code +// + +#if defined(_CC_EDG_) || defined(_CC_WAT_) +#define Q_NO_DEAD_CODE +#endif + +// +// Use to avoid "unused parameter" warnings +// + +#define Q_UNUSED(x) x=x; +#define Q_CONST_UNUSED(x) (void)x; + +Q_EXPORT void qDebug( const char *, ... ) // print debug message +#if defined(_CC_GNU_) && !defined(__INSURE__) + __attribute__ ((format (printf, 1, 2))) +#endif +; + +Q_EXPORT void qWarning( const char *, ... ) // print warning message +#if defined(_CC_GNU_) && !defined(__INSURE__) + __attribute__ ((format (printf, 1, 2))) +#endif +; + +Q_EXPORT void qFatal( const char *, ... ) // print fatal message and exit +#if defined(_CC_GNU_) + __attribute__ ((format (printf, 1, 2))) +#endif +; + + +// QT_CLEAN_NAMESPACE is not defined by default; it would break too +// much code. +#if !defined(QT_CLEAN_NAMESPACE) +// in that case, also define the old ones... + +Q_EXPORT void debug( const char *, ... ) // print debug message +#if defined(_CC_GNU_) && !defined(__INSURE__) + __attribute__ ((format (printf, 1, 2))) +#endif +; + +Q_EXPORT void warning( const char *, ... ) // print warning message +#if defined(_CC_GNU_) && !defined(__INSURE__) + __attribute__ ((format (printf, 1, 2))) +#endif +; + +Q_EXPORT void fatal( const char *, ... ) // print fatal message and exit +#if defined(_CC_GNU_) && !defined(__INSURE__) + __attribute__ ((format (printf, 1, 2))) +#endif +; + +// okay, that was debug()/warning()/fatal() +#endif + +#if !defined(ASSERT) +#if defined(CHECK_STATE) +#if defined(QT_FATAL_ASSERT) +#define ASSERT(x) if ( !(x) )\ + qFatal("ASSERT: \"%s\" in %s (%d)",#x,__FILE__,__LINE__) +#else +#define ASSERT(x) if ( !(x) )\ + qWarning("ASSERT: \"%s\" in %s (%d)",#x,__FILE__,__LINE__) +#endif +#else +#define ASSERT(x) +#endif +#endif + +Q_EXPORT bool qt_check_pointer( bool c, const char *, int ); + +#if defined(CHECK_NULL) +#define CHECK_PTR(p) (qt_check_pointer((p)==0,__FILE__,__LINE__)) +#else +#define CHECK_PTR(p) +#endif + +enum QtMsgType { QtDebugMsg, QtWarningMsg, QtFatalMsg }; + +typedef void (*msg_handler)(QtMsgType, const char *); +Q_EXPORT msg_handler qInstallMsgHandler( msg_handler ); + + +Q_EXPORT void qSuppressObsoleteWarnings( bool = TRUE ); + +#if !defined(QT_REJECT_OBSOLETE) +#define QT_OBSOLETE +Q_EXPORT void qObsolete( const char *obj, const char *oldfunc, + const char *newfunc ); +Q_EXPORT void qObsolete( const char *obj, const char *oldfunc ); +Q_EXPORT void qObsolete( const char *message ); +#endif + +// DvH: added to avoid warnings on recent gcc versions +#define Q_DELETING_VOID_UNDEFINED + +#endif // QGLOBAL_H diff --git a/trunk/qtools/qgstring.cpp b/trunk/qtools/qgstring.cpp new file mode 100644 index 0000000..f43cd6b --- /dev/null +++ b/trunk/qtools/qgstring.cpp @@ -0,0 +1,223 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2004 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + +#include <stdio.h> +#include "qgstring.h" + +#include <assert.h> + +#define BLOCK_SIZE 64 +#define ROUND_SIZE(x) ((x)+BLOCK_SIZE-1)&~(BLOCK_SIZE-1) + +#define DBG_STR(x) do { } while(0) + +QGString::QGString() // make null string + : m_data(0), m_len(0), m_memSize(0) +{ + DBG_STR(("%p: QGString::QGString() %d:%s\n",this,m_len,m_data?m_data:"<none>")); +} + +QGString::QGString(uint size) +{ + if (size==0) + { + m_data=0; + m_len=0; + } + else + { + m_memSize = ROUND_SIZE(size+1); + m_data = (char*)malloc(m_memSize); + memset(m_data,' ',size); + m_data[size]='\0'; + m_len=size; + } + DBG_STR(("%p: QGString::QGString(uint size=%d) %d:%s\n", + this,size,m_len,m_data?m_data:"<none>")); +} + +QGString::QGString( const QGString &s ) +{ + if (s.m_memSize==0) + { + m_data = 0; + m_len = 0; + m_memSize = 0; + } + else + { + m_data = (char *)malloc(s.m_memSize); + m_len = s.m_len; + m_memSize = s.m_memSize; + qstrcpy(m_data,s.m_data); + } + DBG_STR(("%p: QGString::QGString(const QGString &) %d:%s\n",this,m_len,m_data?m_data:"<none>")); +} + +QGString::QGString( const char *str ) +{ + if (str==0) + { + m_data=0; + m_len=0; + m_memSize=0; + } + else + { + m_len = qstrlen(str); + m_memSize = ROUND_SIZE(m_len+1); + assert(m_memSize>=m_len+1); + m_data = (char *)malloc(m_memSize); + qstrcpy(m_data,str); + } + DBG_STR(("%p: QGString::QGString(const char *) %d:%s\n",this,m_len,m_data?m_data:"<none>")); +} + +QGString::~QGString() +{ + free(m_data); + m_data=0; + DBG_STR(("%p: QGString::~QGString() %d:%s\n",this,m_len,m_data?m_data:"<none>")); +} + +bool QGString::resize( uint newlen ) +{ + m_len = 0; + if (newlen==0) + { + if (m_data) { free(m_data); m_data=0; } + m_memSize=0; + DBG_STR(("%p: 1.QGString::resize() %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return TRUE; + } + m_memSize = ROUND_SIZE(newlen+1); + assert(m_memSize>=newlen+1); + if (m_data==0) + { + m_data = (char *)malloc(m_memSize); + } + else + { + m_data = (char *)realloc(m_data,m_memSize); + } + if (m_data==0) + { + DBG_STR(("%p: 2.QGString::resize() %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return FALSE; + } + m_data[newlen-1]='\0'; + m_len = qstrlen(m_data); + DBG_STR(("%p: 3.QGString::resize() %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return TRUE; +} + +QGString &QGString::operator=( const QGString &s ) +{ + if (m_data) free(m_data); + if (s.m_memSize==0) // null string + { + m_data = 0; + m_len = 0; + m_memSize = 0; + } + else + { + m_len = s.m_len; + m_memSize = s.m_memSize; + m_data = (char*)malloc(m_memSize); + qstrcpy(m_data,s.m_data); + } + DBG_STR(("%p: QGString::operator=(const QGString &%p) %d:%s\n", + this,&s,m_len,m_data?m_data:"<none>")); + return *this; +} + +QGString &QGString::operator=( const char *str ) +{ + if (m_data) free(m_data); + if (str==0) // null string + { + m_data = 0; + m_len = 0; + m_memSize = 0; + } + else + { + m_len = qstrlen(str); + m_memSize = ROUND_SIZE(m_len+1); + assert(m_memSize>=m_len+1); + m_data = (char*)malloc(m_memSize); + qstrcpy(m_data,str); + } + DBG_STR(("%p: QGString::operator=(const char *) %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return *this; +} + +QGString &QGString::operator+=( const QGString &s ) +{ + if (s.m_memSize==0) return *this; + uint len1 = length(); + uint len2 = s.length(); + uint memSize = ROUND_SIZE(len1 + len2 + 1); + assert(memSize>=len1+len2+1); + char *newData = memSize!=m_memSize ? (char*)realloc( m_data, memSize ) : m_data; + m_memSize = memSize; + if (m_data) + { + m_data = newData; + memcpy( m_data + len1, s, len2 + 1 ); + } + m_len = len1+len2; + DBG_STR(("%p: QGString::operator+=(const QGString &) %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return *this; +} + +QGString &QGString::operator+=( const char *str ) +{ + if (!str) return *this; + uint len1 = length(); + uint len2 = qstrlen(str); + uint memSize = ROUND_SIZE(len1 + len2 + 1); + assert(memSize>=len1+len2+1); + char *newData = memSize!=m_memSize ? (char *)realloc( m_data, memSize ) : m_data; + m_memSize = memSize; + if (newData) + { + m_data = newData; + memcpy( m_data + len1, str, len2 + 1 ); + } + m_len+=len2; + DBG_STR(("%p: QGString::operator+=(const char *) %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return *this; +} + +QGString &QGString::operator+=( char c ) +{ + uint len = m_len; + uint memSize = ROUND_SIZE(len+2); + assert(memSize>=len+2); + char *newData = memSize!=m_memSize ? (char *)realloc( m_data, memSize ) : m_data; + m_memSize = memSize; + if (newData) + { + m_data = newData; + m_data[len] = c; + m_data[len+1] = '\0'; + } + m_len++; + DBG_STR(("%p: QGString::operator+=(char s) %d:%s\n",this,m_len,m_data?m_data:"<none>")); + return *this; +} + diff --git a/trunk/qtools/qgstring.h b/trunk/qtools/qgstring.h new file mode 100644 index 0000000..d3b997f --- /dev/null +++ b/trunk/qtools/qgstring.h @@ -0,0 +1,137 @@ +#ifndef QGSTRING_H +#define QGSTRING_H + +#include <stdlib.h> +#include <string.h> + +#if defined(_OS_SUN_) && defined(_CC_GNU_) +#include <strings.h> +#endif + +#include "qcstring.h" + +/***************************************************************************** + Fixes and workarounds for some platforms + *****************************************************************************/ + +/** This is an alternative implementation of QCString. + */ +class QGString +{ + public: + QGString(); // make null string + QGString(uint size); + QGString( const QGString &s ); + QGString( const char *str ); + ~QGString() ; + + bool resize( uint newlen ); + + QGString &operator=( const QGString &s ); + QGString &operator=( const char *str ); + QGString &operator+=( const QGString &s ); + QGString &operator+=( const char *str ); + QGString &operator+=( char c ); + + bool isNull() const { return m_data==0; } + bool isEmpty() const { return m_len==0; } + uint length() const { return m_len; } + uint size() const { return m_memSize; } + char * data() const { return m_data; } + bool truncate( uint pos ) { return resize(pos+1); } + operator const char *() const { return (const char *)data(); } + char &at( uint index ) const { return m_data[index]; } + char &operator[]( int i ) const { return at(i); } + + private: + char * m_data; + uint m_len; + uint m_memSize; +}; + +/***************************************************************************** + QGString non-member operators + *****************************************************************************/ + +Q_EXPORT inline bool operator==( const QGString &s1, const QGString &s2 ) +{ return qstrcmp(s1.data(),s2.data()) == 0; } + +Q_EXPORT inline bool operator==( const QGString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) == 0; } + +Q_EXPORT inline bool operator==( const char *s1, const QGString &s2 ) +{ return qstrcmp(s1,s2.data()) == 0; } + +Q_EXPORT inline bool operator!=( const QGString &s1, const QGString &s2 ) +{ return qstrcmp(s1.data(),s2.data()) != 0; } + +Q_EXPORT inline bool operator!=( const QGString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) != 0; } + +Q_EXPORT inline bool operator!=( const char *s1, const QGString &s2 ) +{ return qstrcmp(s1,s2.data()) != 0; } + +Q_EXPORT inline bool operator<( const QGString &s1, const QGString& s2 ) +{ return qstrcmp(s1.data(),s2.data()) < 0; } + +Q_EXPORT inline bool operator<( const QGString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) < 0; } + +Q_EXPORT inline bool operator<( const char *s1, const QGString &s2 ) +{ return qstrcmp(s1,s2.data()) < 0; } + +Q_EXPORT inline bool operator<=( const QGString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) <= 0; } + +Q_EXPORT inline bool operator<=( const char *s1, const QGString &s2 ) +{ return qstrcmp(s1,s2.data()) <= 0; } + +Q_EXPORT inline bool operator>( const QGString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) > 0; } + +Q_EXPORT inline bool operator>( const char *s1, const QGString &s2 ) +{ return qstrcmp(s1,s2.data()) > 0; } + +Q_EXPORT inline bool operator>=( const QGString &s1, const char *s2 ) +{ return qstrcmp(s1.data(),s2) >= 0; } + +Q_EXPORT inline bool operator>=( const char *s1, const QGString &s2 ) +{ return qstrcmp(s1,s2.data()) >= 0; } + +Q_EXPORT inline QGString operator+( const QGString &s1, const QGString &s2 ) +{ + QGString tmp( s1.data() ); + tmp += s2; + return tmp; +} + +Q_EXPORT inline QGString operator+( const QGString &s1, const char *s2 ) +{ + QGString tmp( s1.data() ); + tmp += s2; + return tmp; +} + +Q_EXPORT inline QGString operator+( const char *s1, const QGString &s2 ) +{ + QGString tmp( s1 ); + tmp += s2; + return tmp; +} + +Q_EXPORT inline QGString operator+( const QGString &s1, char c2 ) +{ + QGString tmp( s1.data() ); + tmp += c2; + return tmp; +} + +Q_EXPORT inline QGString operator+( char c1, const QGString &s2 ) +{ + QGString tmp; + tmp += c1; + tmp += s2; + return tmp; +} + +#endif // QGSTRING_H diff --git a/trunk/qtools/qgvector.cpp b/trunk/qtools/qgvector.cpp new file mode 100644 index 0000000..88409ce --- /dev/null +++ b/trunk/qtools/qgvector.cpp @@ -0,0 +1,638 @@ +/**************************************************************************** +** +** +** Implementation of QGVector class +** +** Created : 930907 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#define QGVECTOR_CPP +#include "qgvector.h" +#include "qglist.h" +#include "qstring.h" +#include "qdatastream.h" +#include <stdlib.h> + +#define USE_MALLOC // comment to use new/delete + +#undef NEW +#undef DELETE + +#if defined(USE_MALLOC) +#define NEW(type,size) ((type*)malloc(size*sizeof(type))) +#define DELETE(array) (free((char*)array)) +#else +#define NEW(type,size) (new type[size]) +#define DELETE(array) (delete[] array) +#define DONT_USE_REALLOC // comment to use realloc() +#endif + +// NOT REVISED + +/*! + \class QGVector qgvector.h + + \brief The QGVector class is an internal class for implementing Qt + collection classes. + + QGVector is a strictly internal class that acts as a base class for + the QVector collection class. + + QGVector has some virtual functions that may be reimplemented in + subclasses to to customize behavior. + + <ul> + <li> compareItems() compares two collection/vector items. + <li> read() reads a collection/vector item from a QDataStream. + <li> write() writes a collection/vector item to a QDataStream. + </ul> +*/ + +/***************************************************************************** + Default implementation of virtual functions + *****************************************************************************/ + +/*! + This virtual function compares two list items. + + Returns: + <ul> + <li> 0 if \a item1 == \a item2 + <li> non-zero if \a item1 != \a item2 + </ul> + + This function returns \e int rather than \e bool so that + reimplementations can return one of three values and use it to sort + by: + + <ul> + <li> 0 if \e item1 == \e item2 + <li> \> 0 (positive integer) if \a item1 \> \a item2 + <li> \< 0 (negative integer) if \a item1 \< \a item2 + </ul> + + The QVector::sort() and QVector::bsearch() functions require that + compareItems() is implemented as described here. + + This function should not modify the vector because some const + functions call compareItems(). +*/ + +int QGVector::compareItems( Item d1, Item d2 ) +{ + return d1 != d2; // compare pointers +} + +#ifndef QT_NO_DATASTREAM +/*! + Reads a collection/vector item from the stream \a s and returns a reference + to the stream. + + The default implementation sets \e item to 0. + + \sa write() +*/ + +QDataStream &QGVector::read( QDataStream &s, Item &d ) +{ // read item from stream + d = 0; + return s; +} + +/*! + Writes a collection/vector item to the stream \a s and returns a reference + to the stream. + + The default implementation does nothing. + + \sa read() +*/ + +QDataStream &QGVector::write( QDataStream &s, Item ) const +{ // write item to stream + return s; +} +#endif // QT_NO_DATASTREAM + +/***************************************************************************** + QGVector member functions + *****************************************************************************/ + +/*! + \internal +*/ + +QGVector::QGVector() // create empty vector +{ + vec = 0; + len = numItems = 0; +} + +/*! + \internal +*/ +QGVector::QGVector( uint size ) // create vectors with nullptrs +{ + len = size; + numItems = 0; + if ( len == 0 ) { // zero length + vec = 0; + return; + } + vec = NEW(Item,len); + CHECK_PTR( vec ); + memset( (void*)vec, 0, len*sizeof(Item) ); // fill with nulls +} + +/*! + \internal +*/ + +QGVector::QGVector( const QGVector &a ) // make copy of other vector + : QCollection( a ) +{ + len = a.len; + numItems = a.numItems; + vec = NEW(Item,len); + CHECK_PTR( vec ); + for ( uint i=0; i<len; i++ ) { + vec[i] = a.vec[i] ? newItem( a.vec[i] ) : 0; + CHECK_PTR( vec[i] ); + } +} + +/*! + \internal +*/ + +QGVector::~QGVector() +{ + clear(); +} + + +/*! + \internal +*/ + +QGVector& QGVector::operator=( const QGVector &v ) +{ // assign from other vector + clear(); // first delete old vector + len = v.len; + numItems = v.numItems; + vec = NEW(Item,len); // create new vector + CHECK_PTR( vec ); + for ( uint i=0; i<len; i++ ) { // copy elements + vec[i] = v.vec[i] ? newItem( v.vec[i] ) : 0; + CHECK_PTR( vec[i] ); + } + return *this; +} + + +/*! + \fn Item *QGVector::data() const + \internal +*/ + +/*! + \fn uint QGVector::size() const + \internal +*/ + +/*! + \fn uint QGVector::count() const + \internal +*/ + +/*! + \fn Item QGVector::at( uint index ) const + \internal +*/ + +/*! + \internal +*/ + +bool QGVector::insert( uint index, Item d ) // insert item at index +{ +#if defined(CHECK_RANGE) + if ( index >= len ) { // range error + qWarning( "QGVector::insert: Index %d out of range", index ); + return FALSE; + } +#endif + if ( vec[index] ) { // remove old item + deleteItem( vec[index] ); + numItems--; + } + if ( d ) { + vec[index] = newItem( d ); + CHECK_PTR( vec[index] ); + numItems++; + return vec[index] != 0; + } else { + vec[index] = 0; // reset item + } + return TRUE; +} + +/*! + \internal +*/ + +bool QGVector::remove( uint index ) // remove item at index +{ +#if defined(CHECK_RANGE) + if ( index >= len ) { // range error + qWarning( "QGVector::remove: Index %d out of range", index ); + return FALSE; + } +#endif + if ( vec[index] ) { // valid item + deleteItem( vec[index] ); // delete it + vec[index] = 0; // reset pointer + numItems--; + } + return TRUE; +} + +/*! + \internal +*/ + +QCollection::Item QGVector::take( uint index ) // take out item +{ +#if defined(CHECK_RANGE) + if ( index >= len ) { // range error + qWarning( "QGVector::take: Index %d out of range", index ); + return 0; + } +#endif + Item d = vec[index]; // don't delete item + if ( d ) + numItems--; + vec[index] = 0; + return d; +} + + +/*! + \internal +*/ + +void QGVector::clear() // clear vector +{ + if ( vec ) { + for ( uint i=0; i<len; i++ ) { // delete each item + if ( vec[i] ) + deleteItem( vec[i] ); + } + DELETE(vec); + vec = 0; + len = numItems = 0; + } +} + +/*! + \internal +*/ + +bool QGVector::resize( uint newsize ) // resize array +{ + if ( newsize == len ) // nothing to do + return TRUE; + if ( vec ) { // existing data + if ( newsize < len ) { // shrink vector + uint i = newsize; + while ( i < len ) { // delete lost items + if ( vec[i] ) { + deleteItem( vec[i] ); + numItems--; + } + i++; + } + } + if ( newsize == 0 ) { // vector becomes empty + DELETE(vec); + vec = 0; + len = numItems = 0; + return TRUE; + } +#if defined(DONT_USE_REALLOC) + Item *newvec = NEW(Item,newsize); // manual realloc + memcpy( newvec, vec, (len < newsize ? len : newsize)*sizeof(Item) ); + DELETE(vec); + vec = newvec; +#else + vec = (Item*)realloc( (char *)vec, newsize*sizeof(Item) ); +#endif + } else { // create new vector + vec = NEW(Item,newsize); + len = numItems = 0; + } + CHECK_PTR( vec ); + if ( !vec ) // no memory + return FALSE; + if ( newsize > len ) // init extra space added + memset( (void*)&vec[len], 0, (newsize-len)*sizeof(Item) ); + len = newsize; + return TRUE; +} + + +/*! + \internal +*/ + +bool QGVector::fill( Item d, int flen ) // resize and fill vector +{ + if ( flen < 0 ) + flen = len; // default: use vector length + else if ( !resize( flen ) ) + return FALSE; + for ( uint i=0; i<(uint)flen; i++ ) // insert d at every index + insert( i, d ); + return TRUE; +} + + +static QGVector *sort_vec=0; // current sort vector + + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +static int cmp_vec( const void *n1, const void *n2 ) +{ + return sort_vec->compareItems( *((QCollection::Item*)n1), *((QCollection::Item*)n2) ); +} + +#if defined(Q_C_CALLBACKS) +} +#endif + + +/*! + \internal +*/ + +void QGVector::sort() // sort vector +{ + if ( count() == 0 ) // no elements + return; + register Item *start = &vec[0]; + register Item *end = &vec[len-1]; + Item tmp; + while ( TRUE ) { // put all zero elements behind + while ( start < end && *start != 0 ) + start++; + while ( end > start && *end == 0 ) + end--; + if ( start < end ) { + tmp = *start; + *start = *end; + *end = tmp; + } else { + break; + } + } + sort_vec = (QGVector*)this; + qsort( vec, count(), sizeof(Item), cmp_vec ); + sort_vec = 0; +} + +/*! + \internal +*/ + +int QGVector::bsearch( Item d ) const // binary search; when sorted +{ + if ( !len ) + return -1; + if ( !d ) { +#if defined(CHECK_NULL) + qWarning( "QGVector::bsearch: Cannot search for null object" ); +#endif + return -1; + } + int n1 = 0; + int n2 = len - 1; + int mid = 0; + bool found = FALSE; + while ( n1 <= n2 ) { + int res; + mid = (n1 + n2)/2; + if ( vec[mid] == 0 ) // null item greater + res = -1; + else + res = ((QGVector*)this)->compareItems( d, vec[mid] ); + if ( res < 0 ) + n2 = mid - 1; + else if ( res > 0 ) + n1 = mid + 1; + else { // found it + found = TRUE; + break; + } + } + if ( !found ) + return -1; + // search to first of equal items + while ( (mid - 1 >= 0) && !((QGVector*)this)->compareItems(d, vec[mid-1]) ) + mid--; + return mid; +} + + +/*! + \internal +*/ + +int QGVector::findRef( Item d, uint index) const // find exact item in vector +{ +#if defined(CHECK_RANGE) + if ( index >= len ) { // range error + qWarning( "QGVector::findRef: Index %d out of range", index ); + return -1; + } +#endif + for ( uint i=index; i<len; i++ ) { + if ( vec[i] == d ) + return i; + } + return -1; +} + +/*! + \internal +*/ + +int QGVector::find( Item d, uint index ) const // find equal item in vector +{ +#if defined(CHECK_RANGE) + if ( index >= len ) { // range error + qWarning( "QGVector::find: Index %d out of range", index ); + return -1; + } +#endif + for ( uint i=index; i<len; i++ ) { + if ( vec[i] == 0 && d == 0 ) // found null item + return i; + if ( vec[i] && ((QGVector*)this)->compareItems( vec[i], d ) == 0 ) + return i; + } + return -1; +} + +/*! + \internal +*/ + +uint QGVector::containsRef( Item d ) const // get number of exact matches +{ + uint count = 0; + for ( uint i=0; i<len; i++ ) { + if ( vec[i] == d ) + count++; + } + return count; +} + +/*! + \internal +*/ + +uint QGVector::contains( Item d ) const // get number of equal matches +{ + uint count = 0; + for ( uint i=0; i<len; i++ ) { + if ( vec[i] == 0 && d == 0 ) // count null items + count++; + if ( vec[i] && ((QGVector*)this)->compareItems( vec[i], d ) == 0 ) + count++; + } + return count; +} + + +/*! + \internal +*/ + +bool QGVector::insertExpand( uint index, Item d )// insert and grow if necessary +{ + if ( index >= len ) { + if ( !resize( index+1 ) ) // no memory + return FALSE; + } + insert( index, d ); + return TRUE; +} + + +/*! + \internal +*/ + +void QGVector::toList( QGList *list ) const // store items in list +{ + list->clear(); + for ( uint i=0; i<len; i++ ) { + if ( vec[i] ) + list->append( vec[i] ); + } +} + + +void QGVector::warningIndexRange( uint i ) +{ +#if defined(CHECK_RANGE) + qWarning( "QGVector::operator[]: Index %d out of range", i ); +#else + Q_UNUSED( i ) +#endif +} + + +/***************************************************************************** + QGVector stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +QDataStream &operator>>( QDataStream &s, QGVector &vec ) +{ // read vector + return vec.read( s ); +} + +QDataStream &operator<<( QDataStream &s, const QGVector &vec ) +{ // write vector + return vec.write( s ); +} + +/*! + \internal +*/ + +QDataStream &QGVector::read( QDataStream &s ) // read vector from stream +{ + uint num; + s >> num; // read number of items + clear(); // clear vector + resize( num ); + for (uint i=0; i<num; i++) { // read all items + Item d; + read( s, d ); + CHECK_PTR( d ); + if ( !d ) // no memory + break; + vec[i] = d; + } + return s; +} + +/*! + \internal +*/ + +QDataStream &QGVector::write( QDataStream &s ) const +{ // write vector to stream + uint num = count(); + s << num; // number of items to write + num = size(); + for (uint i=0; i<num; i++) { // write non-null items + if ( vec[i] ) + write( s, vec[i] ); + } + return s; +} +#endif // QT_NO_DATASTREAM diff --git a/trunk/qtools/qgvector.h b/trunk/qtools/qgvector.h new file mode 100644 index 0000000..6a7999d --- /dev/null +++ b/trunk/qtools/qgvector.h @@ -0,0 +1,120 @@ +/**************************************************************************** +** +** +** Definition of QGVector class +** +** Created : 930907 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QGVECTOR_H +#define QGVECTOR_H + +#ifndef QT_H +#include "qcollection.h" +#endif // QT_H + + +class Q_EXPORT QGVector : public QCollection // generic vector +{ +friend class QGList; // needed by QGList::toVector +public: +#ifndef QT_NO_DATASTREAM + QDataStream &read( QDataStream & ); // read vector from stream + QDataStream &write( QDataStream & ) const; // write vector to stream +#endif + virtual int compareItems( Item, Item ); + +protected: + QGVector(); // create empty vector + QGVector( uint size ); // create vector with nullptrs + QGVector( const QGVector &v ); // make copy of other vector + ~QGVector(); + + QGVector &operator=( const QGVector &v ); // assign from other vector + + Item *data() const { return vec; } + uint size() const { return len; } + uint count() const { return numItems; } + + bool insert( uint index, Item ); // insert item at index + bool remove( uint index ); // remove item + Item take( uint index ); // take out item + + void clear(); // clear vector + bool resize( uint newsize ); // resize vector + + bool fill( Item, int flen ); // resize and fill vector + + void sort(); // sort vector + int bsearch( Item ) const; // binary search (when sorted) + + int findRef( Item, uint index ) const; // find exact item in vector + int find( Item, uint index ) const; // find equal item in vector + uint containsRef( Item ) const; // get number of exact matches + uint contains( Item ) const; // get number of equal matches + + Item at( uint index ) const // return indexed item + { +#if defined(CHECK_RANGE) + if ( index >= len ) + warningIndexRange( index ); +#endif + return vec[index]; + } + + bool insertExpand( uint index, Item ); // insert, expand if necessary + + void toList( QGList * ) const; // put items in list + +#ifndef QT_NO_DATASTREAM + virtual QDataStream &read( QDataStream &, Item & ); + virtual QDataStream &write( QDataStream &, Item ) const; +#endif +private: + Item *vec; + uint len; + uint numItems; + + static void warningIndexRange( uint ); +}; + + +/***************************************************************************** + QGVector stream functions + *****************************************************************************/ + +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator>>( QDataStream &, QGVector & ); +Q_EXPORT QDataStream &operator<<( QDataStream &, const QGVector & ); +#endif + +#endif // QGVECTOR_H diff --git a/trunk/qtools/qintdict.doc b/trunk/qtools/qintdict.doc new file mode 100644 index 0000000..e027fb2 --- /dev/null +++ b/trunk/qtools/qintdict.doc @@ -0,0 +1,475 @@ +/**************************************************************************** +** +** +** QIntDict and QIntDictIterator class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QIntDict documentation + *****************************************************************************/ + +/*! + \class QIntDict qintdict.h + \brief The QIntDict class is a template class that provides a dictionary based on \c long keys. + + \ingroup collection + \ingroup tools + + QIntDict is implemented as a template class. Define a + template instance QIntDict\<X\> to create a dictionary that operates on + pointers to X, or X*. + + A dictionary is a collection that associates an item with a key. + The key is used for inserting and looking up an item. QIntDict has + \c long keys. + + The dictionary has very fast insertion and lookup. + + Example: + \code + #include <qintdict.h> + #include <stdio.h> + + void main() + { + QIntDict<char> dict; // maps long ==> char* + + dict.insert( 33, "France" ); + dict.insert( 7, "Russia" ); + dict.insert( 49, "Norway" ); + + printf( "%s\n", dict[49] ); + printf( "%s\n", dict[33] ); + printf( "%s\n", dict[7] ); + + if ( !dict[39] ) + printf( "39 not defined\n" ); + } + \endcode + + Program output: + \code + Norway + France + Russia + 39 not defined + \endcode + + The dictionary in our example maps \c long keys to \c char* items. + QIntDict implements the \link operator[] [] operator\endlink to lookup + an item. + + QIntDict is implemented by QGDict as a hash array with a fixed number of + entries. Each array entry points to a singly linked list of buckets, in + which the dictionary items are stored. + + When an item is inserted with a key, the key is converted (hashed) to + an integer index into the hash array using the \c mod operation. The + item is inserted before the first bucket in the list of buckets. + + Looking up an item is normally very fast. The key is again hashed to an + array index. Then QIntDict scans the list of buckets and returns the item + found or null if the item was not found. You cannot insert null pointers + into a dictionary. + + The size of the hash array is very important. In order to get good + performance, you should use a suitably large \link primes.html prime + number\endlink. Suitable means equal to or larger than the maximum + expected number of dictionary items. + + Items with equal keys are allowed. When inserting two items with the + same key, only the last inserted item will be visible (last in, first out) + until it is removed. + + Example: + \code + #include <qintdict.h> + #include <stdio.h> + + void main() + { + QIntDict<char> dict; // maps long ==> char* + + dict.insert( 7, "Russia" ); + dict.insert( 7, "USSR" ); + + printf( "%s\n", dict[7] ); + dict.remove( 7 ); // Gorbie was here + printf( "%s\n", dict[7] ); + } + \endcode + + Program output: + \code + USSR + Russia + \endcode + + The QIntDictIterator class can traverse the dictionary contents, but only + in an arbitrary order. Multiple iterators may independently traverse the + same dictionary. + + Calling setAutoDelete(TRUE) for a dictionary tells it to delete items + that are removed . The default is to not delete items when they are + removed. + + When inserting an item into a dictionary, only the pointer is copied, not + the item itself. This is called a shallow copy. It is possible to make the + dictionary copy all of the item's data (known as a deep copy) when an + item is inserted. insert() calls the virtual function + QCollection::newItem() for the item to be inserted. + Inherit a dictionary and reimplement it if you want deep copies. + + When removing a dictionary item, the virtual function + QCollection::deleteItem() is called. QIntDict's default implementation + is to delete the item if auto-deletion is enabled. + + \sa QIntDictIterator, QDict, QAsciiDict, QPtrDict, + \link collection.html Collection Classes\endlink +*/ + + +/*! + \fn QIntDict::QIntDict( int size ) + Constructs a dictionary using an internal hash array with the size + \e size. + + Setting \e size to a suitably large \link primes.html prime number\endlink + (equal to or greater than the expected number of entries) makes the hash + distribution better and hence the loopup faster. +*/ + +/*! + \fn QIntDict::QIntDict( const QIntDict<type> &dict ) + Constructs a copy of \e dict. + + Each item in \e dict are inserted into this dictionary. + Only the pointers are copied (shallow copy). +*/ + +/*! + \fn QIntDict::~QIntDict() + Removes all items from the dictionary and destroys it. + + All iterators that access this dictionary will be reset. + + \sa setAutoDelete() +*/ + +/*! + \fn QIntDict<type> &QIntDict::operator=(const QIntDict<type> &dict) + Assigns \e dict to this dictionary and returns a reference to this + dictionary. + + This dictionary is first cleared, then each item in \e dict is inserted + into this dictionary. + Only the pointers are copied (shallow copy), unless newItem() has been + reimplemented. +*/ + +/*! + \fn uint QIntDict::count() const + Returns the number of items in the dictionary. + \sa isEmpty() +*/ + +/*! + \fn uint QIntDict::size() const + Returns the size of the internal hash array (as specified in the + constructor). + \sa count() +*/ + +/*! + \fn void QIntDict::resize( uint newsize ) + Changes the size of the hashtable the \a newsize. + The contents of the dictionary are preserved, + but all iterators on the dictionary become invalid. +*/ + +/*! + \fn bool QIntDict::isEmpty() const + Returns TRUE if the dictionary is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn void QIntDict::insert( long key, const type *item ) + Inserts the \e key with the \e item into the dictionary. + + The key does not have to be a unique dictionary key. If multiple items + are inserted with the same key, only the last item will be visible. + + Null items are not allowed. + + \sa replace() +*/ + +/*! + \fn void QIntDict::replace( long key, const type *item ) + Replaces an item which has a key equal to \e key with \e item. + + If the item does not already exist, it will be inserted. + + Null items are not allowed. + + Equivalent to: + \code + QIntDict<char> dict; + ... + if ( dict.find(key) ) + dict.remove( key ); + dict.insert( key, item ); + \endcode + + If there are two or more items with equal keys, then the last inserted + of these will be replaced. + + \sa insert() +*/ + +/*! + \fn bool QIntDict::remove( long key ) + Removes the item associated with \e key from the dictionary. + Returns TRUE if successful, or FALSE if the key does not exist in the + dictionary. + + If there are two or more items with equal keys, then the last inserted + of these will be removed. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All dictionary iterators that refer to the removed item will be set to + point to the next item in the dictionary traversing order. + + \sa take(), clear(), setAutoDelete() +*/ + +/*! + \fn type *QIntDict::take( long key ) + Takes the item associated with \e key out of the dictionary without + deleting it (even if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled). + + If there are two or more items with equal keys, then the last inserted + of these will be taken. + + Returns a pointer to the item taken out, or null if the key does not + exist in the dictionary. + + All dictionary iterators that refer to the taken item will be set to + point to the next item in the dictionary traversing order. + + \sa remove(), clear(), setAutoDelete() +*/ + +/*! + \fn void QIntDict::clear() + Removes all items from the dictionary. + + The removed items are deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All dictionary iterators that access this dictionary will be reset. + + \sa remove(), take(), setAutoDelete() +*/ + +/*! + \fn type *QIntDict::find( long key ) const + Returns the item associated with \e key, or null if the key does not + exist in the dictionary. + + This function uses an internal hashing algorithm to optimize lookup. + + If there are two or more items with equal keys, then the last inserted + of these will be found. + + Equivalent to the [] operator. + + \sa operator[]() +*/ + +/*! + \fn type *QIntDict::operator[]( long key ) const + Returns the item associated with \e key, or null if the key does not + exist in the dictionary. + + This function uses an internal hashing algorithm to optimize lookup. + + If there are two or more items with equal keys, then the last inserted + of these will be found. + + Equivalent to the find() function. + + \sa find() +*/ + +/*! + \fn void QIntDict::statistics() const + Debugging-only function that prints out the dictionary distribution + using qDebug(). +*/ + + +/***************************************************************************** + QIntDictIterator documentation + *****************************************************************************/ + +/*! + \class QIntDictIterator qintdict.h + \brief The QIntDictIterator class provides an iterator for QIntDict collections. + + \ingroup collection + \ingroup tools + + QIntDictIterator is implemented as a template class. + Define a template instance QIntDictIterator\<X\> to create a + dictionary iterator that operates on QIntDict\<X\> (dictionary of X*). + + Example: + \code + #include <qintdict.h> + #include <stdio.h> + + void main() + { + QIntDict<char> dict; // maps long ==> char* + + dict.insert( 33, "France" ); + dict.insert( 7, "Russia" ); + dict.insert( 49, "Norway" ); + + QIntDictIterator<char> it( dict ); // iterator for dict + + while ( it.current() ) { + printf( "%d -> %s\n", it.currentKey(), it.current() ); + ++it; + } + } + \endcode + + Program output: + \code + 7 -> Russia + 49 -> Norway + 33 -> France + \endcode + + Note that the traversal order is arbitrary, you are not guaranteed the + order above. + + Multiple iterators may independently traverse the same dictionary. + A QIntDict knows about all iterators that are operating on the dictionary. + When an item is removed from the dictionary, QIntDict update all + iterators that are referring the removed item to point to the next item + in the traversing order. + + \sa QIntDict, \link collection.html Collection Classes\endlink +*/ + +/*! + \fn QIntDictIterator::QIntDictIterator( const QIntDict<type> &dict ) + Constructs an iterator for \e dict. The current iterator item is + set to point on the first item in the \e dict. +*/ + +/*! + \fn QIntDictIterator::~QIntDictIterator() + Destroys the iterator. +*/ + +/*! + \fn uint QIntDictIterator::count() const + Returns the number of items in the dictionary this iterator operates on. + \sa isEmpty() +*/ + +/*! + \fn bool QIntDictIterator::isEmpty() const + Returns TRUE if the dictionary is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn type *QIntDictIterator::toFirst() + Sets the current iterator item to point to the first item in the + dictionary and returns a pointer to the item. + If the dictionary is empty it sets the current item to null and + returns null. +*/ + +/*! + \fn QIntDictIterator::operator type *() const + Cast operator. Returns a pointer to the current iterator item. + Same as current(). +*/ + +/*! + \fn type *QIntDictIterator::current() const + Returns a pointer to the current iterator item. +*/ + +/*! + \fn long QIntDictIterator::currentKey() const + Returns the key for the current iterator item. +*/ + +/*! + \fn type *QIntDictIterator::operator()() + Makes the succeeding item current and returns the original current item. + + If the current iterator item was the last item in the dictionary or if it + was null, null is returned. +*/ + +/*! + \fn type *QIntDictIterator::operator++() + Prefix ++ makes the succeeding item current and returns the new current + item. + + If the current iterator item was the last item in the dictionary or if it + was null, null is returned. +*/ + +/*! + \fn type *QIntDictIterator::operator+=( uint jump ) + Sets the current item to the item \e jump positions after the current item, + and returns a pointer to that item. + + If that item is beyond the last item or if the dictionary is empty, + it sets the current item to null and returns null. +*/ diff --git a/trunk/qtools/qintdict.h b/trunk/qtools/qintdict.h new file mode 100644 index 0000000..ddc5fdf --- /dev/null +++ b/trunk/qtools/qintdict.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** +** Definition of QIntDict template class +** +** Created : 940624 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QINTDICT_H +#define QINTDICT_H + +#ifndef QT_H +#include "qgdict.h" +#endif // QT_H + + +template<class type> class Q_EXPORT QIntDict : public QGDict +{ +public: + QIntDict(int size=17) : QGDict(size,IntKey,0,0) {} + QIntDict( const QIntDict<type> &d ) : QGDict(d) {} + ~QIntDict() { clear(); } + QIntDict<type> &operator=(const QIntDict<type> &d) + { return (QIntDict<type>&)QGDict::operator=(d); } + uint count() const { return QGDict::count(); } + uint size() const { return QGDict::size(); } + bool isEmpty() const { return QGDict::count() == 0; } + void insert( long k, const type *d ) + { QGDict::look_int(k,(Item)d,1); } + void replace( long k, const type *d ) + { QGDict::look_int(k,(Item)d,2); } + bool remove( long k ) { return QGDict::remove_int(k); } + type *take( long k ) { return (type*)QGDict::take_int(k); } + type *find( long k ) const + { return (type *)((QGDict*)this)->QGDict::look_int(k,0,0); } + type *operator[]( long k ) const + { return (type *)((QGDict*)this)->QGDict::look_int(k,0,0); } + void clear() { QGDict::clear(); } + void resize( uint n ) { QGDict::resize(n); } + void statistics() const { QGDict::statistics(); } +private: + void deleteItem( Item d ); +}; + +#if defined(Q_DELETING_VOID_UNDEFINED) +template<> inline void QIntDict<void>::deleteItem( QCollection::Item ) +{ +} +#endif + +template<class type> inline void QIntDict<type>::deleteItem( QCollection::Item d ) +{ + if ( del_item ) delete (type *)d; +} + +template<class type> class Q_EXPORT QIntDictIterator : public QGDictIterator +{ +public: + QIntDictIterator(const QIntDict<type> &d) :QGDictIterator((QGDict &)d) {} + ~QIntDictIterator() {} + uint count() const { return dict->count(); } + bool isEmpty() const { return dict->count() == 0; } + type *toFirst() { return (type *)QGDictIterator::toFirst(); } + operator type *() const { return (type *)QGDictIterator::get(); } + type *current() const { return (type *)QGDictIterator::get(); } + long currentKey() const { return QGDictIterator::getKeyInt(); } + type *operator()() { return (type *)QGDictIterator::operator()(); } + type *operator++() { return (type *)QGDictIterator::operator++(); } + type *operator+=(uint j) { return (type *)QGDictIterator::operator+=(j);} +}; + + +#endif // QINTDICT_H diff --git a/trunk/qtools/qiodevice.cpp b/trunk/qtools/qiodevice.cpp new file mode 100644 index 0000000..43b2787 --- /dev/null +++ b/trunk/qtools/qiodevice.cpp @@ -0,0 +1,638 @@ +/**************************************************************************** +** +** +** Implementation of QIODevice class +** +** Created : 940913 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qiodevice.h" + +// NOT REVISED +/*! + \class QIODevice qiodevice.h + + \brief The QIODevice class is the base class of I/O devices. + + \ingroup io + + An I/O device represents a medium that one can read bytes from + and/or write bytes to. The QIODevice class is the abstract + superclass of all such devices; classes like QFile, QBuffer and + QSocket inherit QIODevice and implement virtual functions like + write() appropriately. + + While applications sometimes use QIODevice directly, mostly it is + better to go through QTextStream and QDataStream, which provide + stream operations on any QIODevice subclass. QTextStream provides + text-oriented stream functionality (for human-readable ASCII files, + for example), while QDataStream deals with binary data in a totally + platform-independent manner. + + The public member functions in QIODevice roughly fall into two + groups: The action functions and the state access functions. The + most important action functions are: <ul> + + <li> open() opens a device for reading and/or writing, depending on + the argument to open(). + + <li> close() closes the device and tidies up. + + <li> readBlock() reads a block of data from the device. + + <li> writeBlock() writes a block of data to the device. + + <li> readLine() reads a line (of text, usually) from the device. + + <li> flush() ensures that all buffered data are written to the real device. + + </ul>There are also some other, less used, action functions: <ul> + + <li> getch() reads a single character. + + <li> ungetch() forgets the last call to getch(), if possible. + + <li> putch() writes a single character. + + <li> size() returns the size of the device, if there is one. + + <li> at() returns the current read/write pointer, if there is one + for this device, or it moves the pointer. + + <li> atEnd() says whether there is more to read, if that is a + meaningful question for this device. + + <li> reset() moves the read/write pointer to the start of the + device, if that is possible for this device. + + </ul>The state access are all "get" functions. The QIODevice subclass + calls setState() to update the state, and simple access functions + tell the user of the device what the device's state is. Here are + the settings, and their associated access functions: <ul> + + <li> Access type. Some devices are direct access (it is possible to + read/write anywhere) while others are sequential. QIODevice + provides the access functions isDirectAccess(), isSequentialAccess() + and isCombinedAccess() to tell users what a given I/O device + supports. + + <li> Buffering. Some devices are accessed in raw mode while others + are buffered. Buffering usually provides greater efficiency, + particularly for small read/write operations. isBuffered() tells + the user whether a given device is buffered. (This can often be set + by the application in the call to open().) + + <li> Synchronicity. Synchronous devices work there and then, for + example files. When you read from a file, the file delivers its + data right away. Others, such as a socket connected to a HTTP + server, may not deliver the data until seconds after you ask to read + it. isSynchronous() and isAsynchronous() tells the user how this + device operates. + + <li> CR/LF translation. For simplicity, applications often like to + see just a single CR/LF style, and QIODevice subclasses can provide + that. isTranslated() returns TRUE if this object translates CR/LF + to just LF. (This can often be set by the application in the call + to open().) + + <li> Accessibility. Some files cannot be written, for example. + isReadable(), isWritable and isReadWrite() tells the application + whether it can read from and write to a given device. (This can + often be set by the application in the call to open().) + + <li> Finally, isOpen() returns TRUE if the device is open. This can + quite obviously be set using open() :) + + </ul> + + QIODevice provides numerous pure virtual functions you need to + implement when subclassing it. Here is a skeleton subclass with all + the members you are certain to need, and some it's likely that you + will need: + + \code + class YourDevice : public QIODevice + { + public: + YourDevice(); + ~YourDevice(); + + bool open( int mode ); + void close(); + void flush(); + + uint size() const; + int at() const; // not a pure virtual function + bool at( int ); // not a pure virtual function + bool atEnd() const; // not a pure virtual function + + int readBlock( char *data, uint maxlen ); + int writeBlock( const char *data, uint len ); + int readLine( char *data, uint maxlen ); + + int getch(); + int putch( int ); + int ungetch( int ); + }; + \endcode + + The three non-pure virtual functions can be ignored if your device + is sequential (e.g. an RS-232 port). + + \sa QDataStream, QTextStream +*/ + + +/*! + Constructs an I/O device. +*/ + +QIODevice::QIODevice() +{ + ioMode = 0; // initial mode + ioSt = IO_Ok; + ioIndex = 0; +} + +/*! + Destructs the I/O device. +*/ + +QIODevice::~QIODevice() +{ +} + + +/*! + \fn int QIODevice::flags() const + Returns the current I/O device flags setting. + + Flags consists of mode flags and state flags. + + \sa mode(), state() +*/ + +/*! + \fn int QIODevice::mode() const + Returns bits OR'ed together that specify the current operation mode. + + These are the flags that were given to the open() function. + + The flags are: \c IO_ReadOnly, \c IO_WriteOnly, \c IO_ReadWrite, + \c IO_Append, \c IO_Truncate and \c IO_Translate. +*/ + +/*! + \fn int QIODevice::state() const + Returns bits OR'ed together that specify the current state. + + The flags are: \c IO_Open. + + Subclasses may define more flags. +*/ + +/*! + \fn bool QIODevice::isDirectAccess() const + Returns TRUE if the I/O device is a direct access (not sequential) device, + otherwise FALSE. + \sa isSequentialAccess() +*/ + +/*! + \fn bool QIODevice::isSequentialAccess() const + Returns TRUE if the I/O device is a sequential access (not direct) device, + otherwise FALSE. Operations involving size() and at(int) are not valid + on sequential devices. + \sa isDirectAccess() +*/ + +/*! + \fn bool QIODevice::isCombinedAccess() const + Returns TRUE if the I/O device is a combined access (both direct and + sequential) device, otherwise FALSE. + + This access method is currently not in use. +*/ + +/*! + \fn bool QIODevice::isBuffered() const + Returns TRUE if the I/O device is a buffered (not raw) device, otherwise + FALSE. + \sa isRaw() +*/ + +/*! + \fn bool QIODevice::isRaw() const + Returns TRUE if the I/O device is a raw (not buffered) device, otherwise + FALSE. + \sa isBuffered() +*/ + +/*! + \fn bool QIODevice::isSynchronous() const + Returns TRUE if the I/O device is a synchronous device, otherwise + FALSE. + \sa isAsynchronous() +*/ + +/*! + \fn bool QIODevice::isAsynchronous() const + Returns TRUE if the I/O device is a asynchronous device, otherwise + FALSE. + + This mode is currently not in use. + + \sa isSynchronous() +*/ + +/*! + \fn bool QIODevice::isTranslated() const + Returns TRUE if the I/O device translates carriage-return and linefeed + characters. + + A QFile is translated if it is opened with the \c IO_Translate mode + flag. +*/ + +/*! + \fn bool QIODevice::isReadable() const + Returns TRUE if the I/O device was opened using \c IO_ReadOnly or + \c IO_ReadWrite mode. + \sa isWritable(), isReadWrite() +*/ + +/*! + \fn bool QIODevice::isWritable() const + Returns TRUE if the I/O device was opened using \c IO_WriteOnly or + \c IO_ReadWrite mode. + \sa isReadable(), isReadWrite() +*/ + +/*! + \fn bool QIODevice::isReadWrite() const + Returns TRUE if the I/O device was opened using \c IO_ReadWrite mode. + \sa isReadable(), isWritable() +*/ + +/*! + \fn bool QIODevice::isInactive() const + Returns TRUE if the I/O device state is 0, i.e. the device is not open. + \sa isOpen() +*/ + +/*! + \fn bool QIODevice::isOpen() const + Returns TRUE if the I/O device state has been opened, otherwise FALSE. + \sa isInactive() +*/ + + +/*! + \fn int QIODevice::status() const + Returns the I/O device status. + + The I/O device status returns an error code. If open() returns FALSE + or readBlock() or writeBlock() return -1, this function can be called to + get the reason why the operation did not succeed. + + The status codes are: + <ul> + <li>\c IO_Ok The operation was successful. + <li>\c IO_ReadError Could not read from the device. + <li>\c IO_WriteError Could not write to the device. + <li>\c IO_FatalError A fatal unrecoverable error occurred. + <li>\c IO_OpenError Could not open the device. + <li>\c IO_ConnectError Could not connect to the device. + <li>\c IO_AbortError The operation was unexpectedly aborted. + <li>\c IO_TimeOutError The operation timed out. + <li>\c IO_OnCloseError An unspecified error happened on close. + </ul> + + \sa resetStatus() +*/ + +/*! + \fn void QIODevice::resetStatus() + + Sets the I/O device status to \c IO_Ok. + + \sa status() +*/ + + +/*! + \fn void QIODevice::setFlags( int f ) + \internal + Used by subclasses to set the device flags. +*/ + +/*! + \internal + Used by subclasses to set the device type. +*/ + +void QIODevice::setType( int t ) +{ +#if defined(CHECK_RANGE) + if ( (t & IO_TypeMask) != t ) + qWarning( "QIODevice::setType: Specified type out of range" ); +#endif + ioMode &= ~IO_TypeMask; // reset type bits + ioMode |= t; +} + +/*! + \internal + Used by subclasses to set the device mode. +*/ + +void QIODevice::setMode( int m ) +{ +#if defined(CHECK_RANGE) + if ( (m & IO_ModeMask) != m ) + qWarning( "QIODevice::setMode: Specified mode out of range" ); +#endif + ioMode &= ~IO_ModeMask; // reset mode bits + ioMode |= m; +} + +/*! + \internal + Used by subclasses to set the device state. +*/ + +void QIODevice::setState( int s ) +{ +#if defined(CHECK_RANGE) + if ( ((uint)s & IO_StateMask) != (uint)s ) + qWarning( "QIODevice::setState: Specified state out of range" ); +#endif + ioMode &= ~IO_StateMask; // reset state bits + ioMode |= (uint)s; +} + +/*! + \internal + Used by subclasses to set the device status (not state). +*/ + +void QIODevice::setStatus( int s ) +{ + ioSt = s; +} + + +/*! + \fn bool QIODevice::open( int mode ) + Opens the I/O device using the specified \e mode. + Returns TRUE if successful, or FALSE if the device could not be opened. + + The mode parameter \e m must be a combination of the following flags. + <ul> + <li>\c IO_Raw specified raw (unbuffered) file access. + <li>\c IO_ReadOnly opens a file in read-only mode. + <li>\c IO_WriteOnly opens a file in write-only mode. + <li>\c IO_ReadWrite opens a file in read/write mode. + <li>\c IO_Append sets the file index to the end of the file. + <li>\c IO_Truncate truncates the file. + <li>\c IO_Translate enables carriage returns and linefeed translation + for text files under MS-DOS, Window, OS/2 and Macintosh. On Unix systems + this flag has no effect. Use with caution as it will also transform every linefeed + written to the file into a CRLF pair. This is likely to corrupt your file when + writing binary data to it. Cannot be combined with \c IO_Raw. + </ul> + + This virtual function must be reimplemented by all subclasses. + + \sa close() +*/ + +/*! + \fn void QIODevice::close() + Closes the I/O device. + + This virtual function must be reimplemented by all subclasses. + + \sa open() +*/ + +/*! + \fn void QIODevice::flush() + + Flushes an open I/O device. + + This virtual function must be reimplemented by all subclasses. +*/ + + +/*! + \fn uint QIODevice::size() const + Virtual function that returns the size of the I/O device. + \sa at() +*/ + +/*! + Virtual function that returns the current I/O device index. + + This index is the data read/write head of the I/O device. + + \sa size() +*/ + +int QIODevice::at() const +{ + return ioIndex; +} + +/*! + Virtual function that sets the I/O device index to \e pos. + \sa size() +*/ + +bool QIODevice::at( int pos ) +{ +#if defined(CHECK_RANGE) + if ( (uint)pos > size() ) { + qWarning( "QIODevice::at: Index %d out of range", pos ); + return FALSE; + } +#endif + ioIndex = pos; + return TRUE; +} + +/*! + Virtual function that returns TRUE if the I/O device index is at the + end of the input. +*/ + +bool QIODevice::atEnd() const +{ + if ( isSequentialAccess() || isTranslated() ) { + QIODevice* that = (QIODevice*)this; + int c = that->getch(); + bool result = c < 0; + that->ungetch(c); + return result; + } else { + return at() == (int)size(); + } +} + +/*! + \fn bool QIODevice::reset() + Sets the device index to 0. + \sa at() +*/ + + +/*! + \fn int QIODevice::readBlock( char *data, uint maxlen ) + Reads at most \e maxlen bytes from the I/O device into \e data and + returns the number of bytes actually read. + + This virtual function must be reimplemented by all subclasses. + + \sa writeBlock() +*/ + +/*! + This convenience function returns all of the remaining data in the + device. Note that this only works for direct access devices, such + as QFile. + + \sa isDirectAccess() +*/ +QByteArray QIODevice::readAll() +{ + int n = size()-at(); + QByteArray ba(size()-at()); + char* c = ba.data(); + while ( n ) { + int r = readBlock( c, n ); + if ( r < 0 ) + return QByteArray(); + n -= r; + c += r; + } + return ba; +} + +/*! + \fn int QIODevice::writeBlock( const char *data, uint len ) + Writes \e len bytes from \e p to the I/O device and returns the number of + bytes actually written. + + This virtual function must be reimplemented by all subclasses. + + \sa readBlock() +*/ + +/*! + This convenience function is the same as calling + writeBlock( data.data(), data.size() ). +*/ +int QIODevice::writeBlock( const QByteArray& data ) +{ + return writeBlock( data.data(), data.size() ); +} + +/*! + Reads a line of text, up to \e maxlen bytes including a terminating + \0. If there is a newline at the end if the line, it is not stripped. + + Returns the number of bytes read, or -1 in case of error. + + This virtual function can be reimplemented much more efficiently by + the most subclasses. + + \sa readBlock(), QTextStream::readLine() +*/ + +int QIODevice::readLine( char *data, uint maxlen ) +{ + if ( maxlen == 0 ) // application bug? + return 0; + int pos = at(); // get current position + int s = (int)size(); // size of I/O device + char *p = data; + if ( pos >= s ) + return 0; + while ( pos++ < s && --maxlen ) { // read one byte at a time + readBlock( p, 1 ); + if ( *p++ == '\n' ) // end of line + break; + } + *p++ = '\0'; + return (int)((long)p - (long)data); +} + + +/*! + \fn int QIODevice::getch() + + Reads a single byte/character from the I/O device. + + Returns the byte/character read, or -1 if the end of the I/O device has been + reached. + + This virtual function must be reimplemented by all subclasses. + + \sa putch(), ungetch() +*/ + +/*! + \fn int QIODevice::putch( int ch ) + + Writes the character \e ch to the I/O device. + + Returns \e ch, or -1 if some error occurred. + + This virtual function must be reimplemented by all subclasses. + + \sa getch(), ungetch() +*/ + +/*! + \fn int QIODevice::ungetch( int ch ) + + Puts the character \e ch back into the I/O device and decrements the + index if it is not zero. + + This function is normally called to "undo" a getch() operation. + + Returns \e ch, or -1 if some error occurred. + + This virtual function must be reimplemented by all subclasses. + + \sa getch(), putch() +*/ diff --git a/trunk/qtools/qiodevice.h b/trunk/qtools/qiodevice.h new file mode 100644 index 0000000..1c54217 --- /dev/null +++ b/trunk/qtools/qiodevice.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** +** Definition of QIODevice class +** +** Created : 940913 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QIODEVICE_H +#define QIODEVICE_H + +#ifndef QT_H +#include "qglobal.h" +#include "qcstring.h" +#endif // QT_H + + +// IO device access types + +#define IO_Direct 0x0100 // direct access device +#define IO_Sequential 0x0200 // sequential access device +#define IO_Combined 0x0300 // combined direct/sequential +#define IO_TypeMask 0x0f00 + +// IO handling modes + +#define IO_Raw 0x0040 // raw access (not buffered) +#define IO_Async 0x0080 // asynchronous mode + +// IO device open modes + +#define IO_ReadOnly 0x0001 // readable device +#define IO_WriteOnly 0x0002 // writable device +#define IO_ReadWrite 0x0003 // read+write device +#define IO_Append 0x0004 // append +#define IO_Truncate 0x0008 // truncate device +#define IO_Translate 0x0010 // translate CR+LF +#define IO_ModeMask 0x00ff + +// IO device state + +#define IO_Open 0x1000 // device is open +#define IO_StateMask 0xf000 + + +// IO device status + +#define IO_Ok 0 +#define IO_ReadError 1 // read error +#define IO_WriteError 2 // write error +#define IO_FatalError 3 // fatal unrecoverable error +#define IO_ResourceError 4 // resource limitation +#define IO_OpenError 5 // cannot open device +#define IO_ConnectError 5 // cannot connect to device +#define IO_AbortError 6 // abort error +#define IO_TimeOutError 7 // time out +#define IO_UnspecifiedError 8 // unspecified error + +class Q_EXPORT QIODevice // IO device class +{ +public: + QIODevice(); + virtual ~QIODevice(); + + int flags() const { return ioMode; } + int mode() const { return ioMode & IO_ModeMask; } + int state() const { return ioMode & IO_StateMask; } + + bool isDirectAccess() const { return ((ioMode & IO_Direct) == IO_Direct); } + bool isSequentialAccess() const { return ((ioMode & IO_Sequential) == IO_Sequential); } + bool isCombinedAccess() const { return ((ioMode & IO_Combined) == IO_Combined); } + bool isBuffered() const { return ((ioMode & IO_Raw) != IO_Raw); } + bool isRaw() const { return ((ioMode & IO_Raw) == IO_Raw); } + bool isSynchronous() const { return ((ioMode & IO_Async) != IO_Async); } + bool isAsynchronous() const { return ((ioMode & IO_Async) == IO_Async); } + bool isTranslated() const { return ((ioMode & IO_Translate) == IO_Translate); } + bool isReadable() const { return ((ioMode & IO_ReadOnly) == IO_ReadOnly); } + bool isWritable() const { return ((ioMode & IO_WriteOnly) == IO_WriteOnly); } + bool isReadWrite() const { return ((ioMode & IO_ReadWrite) == IO_ReadWrite); } + bool isInactive() const { return state() == 0; } + bool isOpen() const { return state() == IO_Open; } + + int status() const { return ioSt; } + void resetStatus() { ioSt = IO_Ok; } + + virtual bool open( int mode ) = 0; + virtual void close() = 0; + virtual void flush() = 0; + + virtual uint size() const = 0; + virtual int at() const; + virtual bool at( int ); + virtual bool atEnd() const; + bool reset() { return at(0); } + + virtual int readBlock( char *data, uint maxlen ) = 0; + virtual int writeBlock( const char *data, uint len ) = 0; + virtual int readLine( char *data, uint maxlen ); + int writeBlock( const QByteArray& data ); + QByteArray readAll(); + + virtual int getch() = 0; + virtual int putch( int ) = 0; + virtual int ungetch( int ) = 0; + +protected: + void setFlags( int f ) { ioMode = f; } + void setType( int ); + void setMode( int ); + void setState( int ); + void setStatus( int ); + int ioIndex; + +private: + int ioMode; + int ioSt; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QIODevice( const QIODevice & ); + QIODevice &operator=( const QIODevice & ); +#endif +}; + + +#endif // QIODEVICE_H diff --git a/trunk/qtools/qlist.doc b/trunk/qtools/qlist.doc new file mode 100644 index 0000000..98decd1 --- /dev/null +++ b/trunk/qtools/qlist.doc @@ -0,0 +1,1048 @@ +/**************************************************************************** +** +** +** QList and QListIterator class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QList documentation + *****************************************************************************/ + +/*! + \class QList qlist.h + \brief The QList class is a template class that provides doubly linked lists. + + \ingroup collection + \ingroup tools + + In Qt 2.0 QList is only implemented as a template class. Define a + template instance QList\<X\> to create a list that operates on pointers + to X, or X*. + + Example: + \code + #include <qlist.h> + #include <qstring.h> + #include <stdio.h> + + class Employee + { + public: + Employee( const QString& name, int salary ) { n=name; s=salary; } + QString name() const { return n; } + int salary() const { return s; } + private: + QString n; + int s; + }; + + void main() + { + QList<Employee> list; // list of pointers to Employee + list.setAutoDelete( TRUE ); // delete items when they are removed + + list.append( new Employee("Bill", 50000) ); + list.append( new Employee("Steve",80000) ); + list.append( new Employee("Ron", 60000) ); + + Employee *emp; + for ( emp=list.first(); emp != 0; emp=list.next() ) + printf( "%s earns %d\n", emp->name().latin1(), emp->salary() ); + } + \endcode + + Program output: + \code + Bill earns 50000 + Steve earns 80000 + Ron earns 60000 + \endcode + + The list class is indexable and has a \link at() current index\endlink + and a \link current() current item\endlink. The first item corresponds + to index 0. The current index is -1 if the current item is null. + + QList has several member functions for traversing the list, but using + a QListIterator can be more practical. Multiple list iterators may + traverse the same list, independent of each other and independent of + the current list item. + + In the example above, we make the call setAutoDelete(TRUE). + Enabling auto-deletion tells the list to delete items that are removed + from the list. The default is to not delete items when they are + removed, but that would cause a memory leak in our example since we have + no other references to the list items. + + List items are stored as \c void* in an internal QLNode, which also + holds pointers to the next and previous list items. The functions + currentNode(), removeNode() and takeNode() operate directly on the + QLNode, but they should be used with care. + + When inserting an item into a list, only the pointer is copied, not the + item itself. This is called a shallow copy. It is possible to make the + list copy all of the item's data (known as a deep copy) when an item is + inserted. insert(), inSort() and append() call the virtual function + QCollection::newItem() for the item to be inserted. + Inherit a list and reimplement it if you want deep copies. + + When removing an item from a list, the virtual function + QCollection::deleteItem() is called. QList's default implementation + is to delete the item if auto-deletion is enabled. + + The virtual function QGList::compareItems() can be reimplemented to + compare two list items. This function is called from all list functions + that need to compare list items, for instance remove(const type*). + If you only want to deal with pointers, there are functions that + compare pointers instead, for instance removeRef(const type*). + These functions are somewhat faster than those that call compareItems(). + + The QStrList class in qstrlist.h is a list of \c char*. QStrList is + a good example of a list that reimplements newItem(), deleteItem() and + compareItems() + + \sa QListIterator, \link collection.html Collection Classes\endlink +*/ + + +/*! + \fn QList::QList() + Constructs an empty list. +*/ + +/*! + \fn QList::QList( const QList<type> &list ) + Constructs a copy of \e list. + + Each item in \e list is \link append() appended\endlink to this list. + Only the pointers are copied (shallow copy). +*/ + +/*! + \fn QList::~QList() + Removes all items from the list and destroys the list. + + All list iterators that access this list will be reset. + + \sa setAutoDelete() +*/ + +/*! + \fn QList<type> &QList::operator=(const QList<type> &list) + Assigns \e list to this list and returns a reference to this list. + + This list is first cleared, then each item in \e list is + \link append() appended\endlink to this list. Only the pointers are copied + (shallow copy), unless newItem() has been reimplemented(). +*/ + +/*! + \fn bool QList::operator==(const QList<type> &list ) const + + Compares this list with \a list. Retruns TRUE if the lists + contain the same data, else FALSE. +*/ + +/*! + \fn uint QList::count() const + Returns the number of items in the list. + \sa isEmpty() +*/ + +/*! + \fn void QList::sort() + + Sorts the list by the result of the virtual compareItems() function. + + The Heap-Sort algorithm is used for sorting. It sorts n items with + O(n*log n) compares. This is the asymptotic optimal solution of the + sorting problem. + + If the items in your list support operator< and operator== then you + might be better off with QSortedList since it implements the + compareItems() function for you using these two operators. + + \sa inSort() +*/ + +/*! + \fn bool QList::isEmpty() const + Returns TRUE if the list is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn bool QList::insert( uint index, const type *item ) + Inserts the \e item at the position \e index in the list. + + Returns TRUE if successful, or FALSE if \e index is out of range. + The valid range is <code>0 .. count()</code> inclusive. + The item is appended if \e index == count(). + + The inserted item becomes the current list item. + + The \e item must not be a null pointer. + + \sa append(), current() +*/ + +/*! + \fn void QList::inSort( const type *item ) + Inserts the \e item at its sorted position in the list. + + The sort order depends on the virtual QGList::compareItems() function. + All items must be inserted with inSort() to maintain the sorting order. + + The inserted item becomes the current list item. + + The \e item must not be a null pointer. + + Please note that inSort is slow. If you want to insert lots of items + in a list and sort after inserting then you should use sort(). + inSort() takes up to O(n) compares. That means inserting n items in + your list will need O(n^2) compares while sort() only needs O(n*logn) + for the same task. So you inSort() only if you already have a pre-sorted + list and want to insert only few additional items. + + \sa insert(), QGList::compareItems(), current(), sort() +*/ + +/*! + \fn void QList::append( const type *item ) + Inserts the \e item at the end of the list. + + The inserted item becomes the current list item. + This is equivalent to \c insert(count(),item). + + + The \e item must not be a null pointer. + + \sa insert(), current(), prepend() +*/ + +/*! + \fn void QList::prepend( const type *item ) + + Inserts the \e item at the start of the list. + + The inserted item becomes the current list item. + This is equivalent to \c insert(0,item). + + The \e item must not be a null pointer. + + \sa append(), insert(), current() +*/ + +/*! + \fn bool QList::remove( uint index ) + Removes the item at position \e index in the list. + + Returns TRUE if successful, or FALSE if \e index is out of range. + The valid range is <code>0 .. (count() - 1)</code> inclusive. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The item after the removed item becomes the new current list item if + the removed item is not the last item in the list. If the last item + is removed, the new last item becomes the current item in Qt 2.x. + In 3.0, the current item will be set to null. The current item is + set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point + to the new current item. + + \sa take(), clear(), setAutoDelete(), current() removeRef() +*/ + +/*! + \fn bool QList::remove() + Removes the current list item. + + Returns TRUE if successful, or FALSE if the current item is null. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The item after the removed item becomes the new current list item if + the removed item is not the last item in the list. If the last item + is removed, the new last item becomes the current item in Qt 2.x. + In 3.0, the current item will be set to null. The current item is + set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point + to the new current item. + + \sa take(), clear(), setAutoDelete(), current() removeRef() +*/ + +/*! + \fn bool QList::remove( const type *item ) + Removes the first occurrence of \e item from the list. + + Returns TRUE if successful, or FALSE if the item could not be found in the + list. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The compareItems() function is called when searching for the item + in the list. If compareItems() is not reimplemented, it is more + efficient to call removeRef(). + + The item after the removed item becomes the new current list item if + the removed item is not the last item in the list. If the last item + is removed, the new last item becomes the current item in Qt 2.x. + In 3.0, the current item will be set to null. The current item is + set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point + to the new current item. + + \sa removeRef(), take(), clear(), setAutoDelete(), compareItems(), current() +*/ + +/*! + \fn bool QList::removeRef( const type *item ) + Removes the first occurrence of \e item from the list. + + Returns TRUE if successful, or FALSE if the item cannot be found in the + list. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The list is scanned until the pointer \e item is found. It is removed + if it is found. + + Equivalent to: + \code + if ( list.findRef(item) != -1 ) + list.remove(); + \endcode + + The item after the removed item becomes the new current list item if + the removed item is not the last item in the list. If the last item + is removed, the new last item becomes the current item in Qt 2.x. + In 3.0, the current item will be set to null. The current item is + set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point + to the new current item. + + \sa remove(), clear(), setAutoDelete(), current() +*/ + +/*! + \fn void QList::removeNode( QLNode *node ) + Removes the \e node from the list. + + This node must exist in the list, otherwise the program may crash. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The first item in the list will become the new current list item. + The current item is set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point to + the item succeeding this item, or the preceding item if the removed item + was the last item. + + \warning Do not call this function unless you are an expert. + + \sa takeNode(), currentNode() remove() removeRef() +*/ + +/*! + \fn bool QList::removeFirst() + Removes the first item from the list. + Returns TRUE if successful, or FALSE if the list is empty. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The first item in the list becomes the new current list item. + The current item is set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point + to the new current item. + + \sa removeLast(), setAutoDelete(), current() remove() +*/ + +/*! + \fn bool QList::removeLast() + Removes the last item from the list. + Returns TRUE if successful, or FALSE if the list is empty. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + The last item in the list becomes the new current list item. + The current item is set to null if the list becomes empty. + + All list iterators that refer to the removed item will be set to point + to the new current item. + + \sa removeFirst(), setAutoDelete(), current() +*/ + +/*! + \fn type *QList::take( uint index ) + Takes the item at position \e index out of the list without + deleting it (even if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled). + + Returns a pointer to the item taken out of the list, or null if + the index is out of range. + The valid range is <code>0 .. (count() - 1)</code> inclusive. + + The item after the taken item becomes the new current list item if + the taken item is not the last item in the list. If the last item + is taken, the new last item becomes the current item in Qt 2.x. In + 3.0, the current item will be set to null. The current item is set + to null if the list becomes empty. + + All list iterators that refer to the taken item will be set to point to + the new current item. + + \sa remove(), clear(), current() +*/ + +/*! + \fn type *QList::take() + Takes the current item out of the list without deleting it (even if + \link QCollection::setAutoDelete() auto-deletion\endlink is enabled). + Returns a pointer to the item taken out of the list, or null if + the current item is null. + + The item after the taken item becomes the new current list item if + the taken item is not the last item in the list. If the last item + is taken, the new last item becomes the current item in Qt 2.x. In + 3.0, the current item will be set to null. The current item is set + to null if the list becomes empty. + + All list iterators that refer to the taken item will be set to point to + the new current item. + + \sa remove(), clear(), current() +*/ + +/*! + \fn type *QList::takeNode( QLNode *node ) + Takes the \e node out of the list without deleting its item (even if + \link QCollection::setAutoDelete() auto-deletion\endlink is enabled). + Returns a pointer to the item taken out of the list. + + This node must exist in the list, otherwise the program may crash. + + The first item in the list becomes the new current list item. + + All list iterators that refer to the taken item will be set to point to + the item succeeding this item, or the preceding item if the taken item + was the last item. + + \warning Do not call this function unless you are an expert. + + \sa removeNode(), currentNode() +*/ + +/*! + \fn void QList::clear() + Removes all items from the list. + + The removed items are deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All list iterators that access this list will be reset. + + \sa remove(), take(), setAutoDelete() +*/ + +/*! + \fn int QList::find( const type *item ) + Finds the first occurrence of \e item in the list. + + If the item is found, the list sets the current item to point to + the found item and returns the index of this item. + If the item is not found, the list sets the current item to null, + the current index to -1 and returns -1. + + The compareItems() function is called when searching for the item + in the list. If compareItems() is not reimplemented, it is more + efficient to call findRef(). + + \sa findNext(), findRef(), compareItems(), current() +*/ + +/*! + \fn int QList::findNext( const type *item ) + Finds the next occurrence of \e item in the list, starting from + the current list item. + + If the item is found, the list sets the current item to point to + the found item and returns the index of this item. + If the item is not found, the list sets the current item to null, + the current index to -1 and returns -1. + + The compareItems() function is called when searching for the item + in the list. If compareItems() is not reimplemented, it is more + efficient to call findNextRef(). + + \sa find(), findNextRef(), compareItems(), current() +*/ + +/*! + \fn int QList::findRef( const type *item ) + Finds the first occurrence of \e item in the list. + + If the item is found, the list sets the current item to point to + the found item and returns the index of this item. + If the item is not found, the list sets the current item to null, + the current index to -1 and returns -1. + + Calling this function is must faster than find(), because find() + compares \e item with each list item using compareItems(). + This function only compares the pointers. + + \sa findNextRef(), find(), current() +*/ + +/*! + \fn int QList::findNextRef( const type *item ) + Finds the next occurrence of \e item in the list, starting from the + current list item. + + If the item is found, the list sets the current item to point to + the found item and returns the index of this item. + If the item is not found, the list sets the current item to null, + the current index to -1 and returns -1. + + Calling this function is must faster than findNext(), because findNext() + compares \e item with each list item using compareItems(). + This function only compares the pointers. + + \sa findRef(), findNext(), current() +*/ + +/*! + \fn uint QList::contains( const type *item ) const + Counts and returns the number of occurrences of \e item in the list. + + The compareItems() function is called when looking for the \e item + in the list. If compareItems() is not reimplemented, it is more + efficient to call containsRef(). + + Does not affect the current list item. + + \sa containsRef(), compareItems() +*/ + +/*! + \fn uint QList::containsRef( const type *item ) const + Counts and returns the number of occurrences of \e item in the list. + + Calling this function is must faster than contains(), because contains() + compares \e item with each list item using compareItems(). + This function only compares the pointers. + + Does not affect the current list item. + + \sa contains() +*/ + +/*! + \fn type *QList::at( uint index ) + Returns a pointer to the item at position \e index in the list, or + null if the index is out of range. + + Sets the current list item to this item if \e index is valid. + The valid range is <code>0 .. (count() - 1)</code> inclusive. + + This function is very efficient. It starts scanning from the first + item, last item or current item, whichever is closest to \e index. + + \sa current() +*/ + +/*! + \fn int QList::at() const + Returns the index of the current list item. The returned value is -1 + if the current item is null. + \sa current() +*/ + +/*! + \fn type *QList::current() const + Returns a pointer to the current list item. The current item may be + null (implies that the current index is -1). + \sa at() +*/ + +/*! + \fn QLNode *QList::currentNode() const + Returns a pointer to the current list node. + + The node can be kept and removed later using removeNode(). + The advantage is that the item can be removed directly without + searching the list. + + \warning Do not call this function unless you are an expert. + + \sa removeNode(), takeNode(), current() +*/ + +/*! + \fn type *QList::getFirst() const + Returns a pointer to the first item in the list, or null if the + list is empty. + + Does not affect the current list item. + + \sa first(), getLast() +*/ + +/*! + \fn type *QList::getLast() const + Returns a pointer to the last item in the list, or null if the + list is empty. + + Does not affect the current list item. + + \sa last(), getFirst() +*/ + +/*! + \fn type *QList::first() + Returns a pointer to the first item in the list and makes this the + current list item, or null if the list is empty. + \sa getFirst(), last(), next(), prev(), current() +*/ + +/*! + \fn type *QList::last() + Returns a pointer to the last item in the list and makes this the + current list item, or null if the list is empty. + \sa getLast(), first(), next(), prev(), current() +*/ + +/*! + \fn type *QList::next() + Returns a pointer to the item succeeding the current item. + Returns null if the current item is null or equal to the last item. + + Makes the succeeding item current. If the current item before this + function call was the last item, the current item will be set to null. + If the current item was null, this function does nothing. + + \sa first(), last(), prev(), current() +*/ + +/*! + \fn type *QList::prev() + Returns a pointer to the item preceding the current item. + Returns null if the current item is null or equal to the first item. + + Makes the preceding item current. If the current item before this + function call was the first item, the current item will be set to null. + If the current item was null, this function does nothing. + + \sa first(), last(), next(), current() +*/ + +/*! + \fn void QList::toVector( QGVector *vec ) const + Stores all list items in the vector \e vec. + + The vector must be have the same item type, otherwise the result + will be undefined. +*/ + + +/***************************************************************************** + QListIterator documentation + *****************************************************************************/ + +/*! + \class QListIterator qlist.h + \brief The QListIterator class provides an iterator for QList collections. + + \ingroup collection + \ingroup tools + + Define a template instance QListIterator\<X\> to create a list iterator + that operates on QList\<X\> (list of X*). + + Example: + \code + #include <qlist.h> + #include <qstring.h> + #include <stdio.h> + + class Employee + { + public: + Employee( const char *name, int salary ) { n=name; s=salary; } + const char *name() const { return n; } + int salary() const { return s; } + private: + QString n; + int s; + }; + + void main() + { + QList<Employee> list; // list of pointers to Employee + list.setAutoDelete( TRUE ); // delete items when they are removed + + list.append( new Employee("Bill", 50000) ); + list.append( new Employee("Steve",80000) ); + list.append( new Employee("Ron", 60000) ); + + QListIterator<Employee> it(list); // iterator for employee list + for ( ; it.current(); ++it ) { + Employee *emp = it.current(); + printf( "%s earns %d\n", emp->name().latin1(), emp->salary() ); + } + } + \endcode + + Program output: + \code + Bill earns 50000 + Steve earns 80000 + Ron earns 60000 + \endcode + + Although QList has member functions to traverse the doubly linked list + structure, using a list iterator is a much more robust way of traversing + the list, because multiple list iterators can operate on the same list, + independent of each other and independent of the QList's current item. + An iterator has its own current list item and can get the next and + previous list items. It can only traverse the list, never modify it. + + A QList knows about all list iterators that are operating on the list. + When an item is removed from the list, the list update all iterators + that are pointing the removed item to point to the new current list item. + + Example: + \code + #include <qlist.h> + #include <qstring.h> + #include <stdio.h> + + class Employee + { + ... // same as above + }; + + void main() + { + QList<Employee> list; // list of pointers to Employee + list.setAutoDelete( TRUE ); // delete items when they are removed + + list.append( new Employee("Bill", 50000) ); + list.append( new Employee("Steve",80000) ); + list.append( new Employee("Ron", 60000) ); + + QListIterator<Employee> it(list); + + list.at( 1 ); // current list item: "Steve" + it.toLast(); // it: "Ron" + --it; // it: "Steve" + + // Now, both the list and the iterator are referring the same item + + list.remove(); + printf( "%s\n", it.current()->name().latin1() ); + } + \endcode + + Program output: + \code + Ron + \endcode + + \sa QList, \link collection.html collection classes\endlink +*/ + +/*! + \fn QListIterator::QListIterator( const QList<type> &list ) + Constructs an iterator for \e list. The current iterator item is + set to point on the first item in the \e list. +*/ + +/*! + \fn QListIterator::~QListIterator() + Destroys the iterator. +*/ + +/*! + \fn uint QListIterator::count() const + Returns the number of items in the list this iterator operates on. + \sa isEmpty() +*/ + +/*! + \fn bool QListIterator::isEmpty() const + Returns TRUE if the list is empty, i.e. count() == 0, otherwise FALSE. + \sa count() +*/ + +/*! + \fn bool QListIterator::atFirst() const + Returns TRUE if the current iterator item is the first list item, otherwise + FALSE. + \sa toFirst(), atLast() +*/ + +/*! + \fn bool QListIterator::atLast() const + Returns TRUE if the current iterator item is the last list item, otherwise + FALSE. + \sa toLast(), atFirst() +*/ + +/*! + \fn type *QListIterator::toFirst() + Sets the current iterator item to point to the first list item and returns + a pointer to the item. Sets the current item to null and returns null + if the list is empty. + \sa toLast(), atFirst() +*/ + +/*! + \fn type *QListIterator::toLast() + Sets the current iterator item to point to the last list item and returns + a pointer to the item. Sets the current item to null and returns null + if the list is empty. + \sa toFirst(), atLast() +*/ + +/*! + \fn QListIterator::operator type *() const + Cast operator. Returns a pointer to the current iterator item. + Same as current(). +*/ + +/*! + \fn type *QListIterator::operator*() + Asterix operator. Returns a pointer to the current iterator item. + Same as current(). +*/ + +/*! + \fn type *QListIterator::current() const + Returns a pointer to the current iterator item. +*/ + +/*! + \fn type *QListIterator::operator()() + Makes the succeeding item current and returns the original current item. + + If the current iterator item was the last item in the list or if it was + null, null is returned. +*/ + +/*! + \fn char *QStrListIterator::operator()() + Makes the succeeding item current and returns the original current item. + + If the current iterator item was the last item in the list or if it was + null, null is returned. +*/ + +/*! + \fn type *QListIterator::operator++() + Prefix ++ makes the succeeding item current and returns the new current + item. + + If the current iterator item was the last item in the list or if it was + null, null is returned. +*/ + +/*! + \fn type *QListIterator::operator+=( uint jump ) + Sets the current item to the item \e jump positions after the current item, + and returns a pointer to that item. + + If that item is beyond the last item or if the dictionary is empty, + it sets the current item to null and returns null +*/ + +/*! + \fn type *QListIterator::operator--() + Prefix -- makes the preceding item current and returns the new current + item. + + If the current iterator item was the first item in the list or if it was + null, null is returned. +*/ + +/*! + \fn type *QListIterator::operator-=( uint jump ) + Returns the item \e jump positions before the current item, or null if + it is beyond the first item. Makes this the current item. +*/ + +/*! + \fn QListIterator<type>& QListIterator::operator=( const QListIterator<type> &it ) + Assignment. Makes a copy of the iterator \a it and returns a reference + to this iterator. +*/ + + +/***************************************************************************** + QStrList documentation + *****************************************************************************/ + +typedef QList<char> QStrList + +/*! + \class QStrList qstrlist.h + \brief The QStrList class provides a doubly linked list of \c char*. + + \inherit QList + + \ingroup collection + \ingroup tools + + This class is a QList\<char\> instance (a list of char*). + + QStrList can make deep or shallow copies of the strings that are inserted. + + A deep copy means to allocate space for the string and then copy the string + data into it. A shallow copy is just a copy of the pointer value and not + the string data. + + The disadvantage with shallow copies is that since a pointer can only + be deleted once, the program must put all strings in a central place and + know when it is safe to delete them (i.e. when the strings are no longer + referenced by other parts of the program). This can make the program + more complex. The advantage of shallow copies is that shallow copies + consume far less memory than deep copies. It is also much faster + to copy a pointer (typically 4 or 8 bytes) than to copy string data. + + A QStrList that operates on deep copies will by default turn on + auto-deletion (see setAutoDelete()). Thus, by default, QStrList will + deallocate any string copies it allocates. + + The virtual compareItems() function is reimplemented and does a case + sensitive string comparison. The inSort() function will insert + strings in a sorted order. + + The QStrListIterator class is an iterator for QStrList. +*/ + +/*! + \fn QStrList::QStrList( bool deepCopies ) + Constructs an empty list of strings. Will make deep copies of all inserted + strings if \e deepCopies is TRUE, or uses shallow copies if \e deepCopies + is FALSE. +*/ + +/*! + \fn QStrList::QStrList( const QStrList &list ) + Constructs a copy of \e list. + + If \e list has deep copies, this list will also get deep copies. + Only the pointers are copied (shallow copy) if the other list does not + use deep copies. +*/ + +/*! + \fn QStrList::~QStrList() + Destroys the list. All strings are removed. +*/ + +/*! + \fn QStrList& QStrList::operator=( const QStrList& list ) + Assigns \e list to this list and returns a reference to this list. + + If \e list has deep copies, this list will also get deep copies. + Only the pointers are copied (shallow copy) if the other list does not + use deep copies. +*/ + + +/***************************************************************************** + QStrIList documentation + *****************************************************************************/ + +/*! + \class QStrIList qstrlist.h + \brief The QStrIList class provides a doubly linked list of \c char* with +case insensitive compare. + + \ingroup collection + \ingroup tools + + This class is a QList\<char\> instance (a list of char*). + + QStrIList is similar to QStrList except that it is case insensitive. + The virtual compareItems() function is reimplemented and does a + case insensitive string comparison. + The inSort() function will insert strings in a sorted order. + + The QStrListIterator class is an iterator for QStrList. +*/ + +/*! + \fn QStrIList::QStrIList( bool deepCopies ) + Constructs a list of strings. Will make deep copies of all inserted + strings if \e deepCopies is TRUE, or uses shallow copies if \e deepCopies + is FALSE. +*/ + +/*! + \fn QStrIList::~QStrIList() + Destroys the list. All strings are removed. +*/ + + +/***************************************************************************** + QStrListIterator documentation + *****************************************************************************/ + +/*! + \class QStrListIterator qstrlist.h + \brief The QStrListIterator class is an iterator for the QStrList and QStrIList classes. + + \inherit QListIterator + + \ingroup tools + + This class is a QListIterator\<char\> instance. + It can traverse the strings in the QStrList and QStrIList classes. +*/ diff --git a/trunk/qtools/qlist.h b/trunk/qtools/qlist.h new file mode 100644 index 0000000..a4608fb --- /dev/null +++ b/trunk/qtools/qlist.h @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** +** Definition of QList template/macro class +** +** Created : 920701 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QLIST_H +#define QLIST_H + +#ifndef QT_H +#include "qglist.h" +#endif // QT_H + + +template<class type> class Q_EXPORT QList : public QGList +{ +public: + QList() {} + QList( const QList<type> &l ) : QGList(l) {} + ~QList() { clear(); } + QList<type> &operator=(const QList<type> &l) + { return (QList<type>&)QGList::operator=(l); } + bool operator==( const QList<type> &list ) const + { return QGList::operator==( list ); } + uint count() const { return QGList::count(); } + bool isEmpty() const { return QGList::count() == 0; } + bool insert( uint i, const type *d){ return QGList::insertAt(i,(QCollection::Item)d); } + void inSort( const type *d ) { QGList::inSort((QCollection::Item)d); } + void prepend( const type *d ) { QGList::insertAt(0,(QCollection::Item)d); } + void append( const type *d ) { QGList::append((QCollection::Item)d); } + bool remove( uint i ) { return QGList::removeAt(i); } + bool remove() { return QGList::remove((QCollection::Item)0); } + bool remove( const type *d ) { return QGList::remove((QCollection::Item)d); } + bool removeRef( const type *d ) { return QGList::removeRef((QCollection::Item)d); } + void removeNode( QLNode *n ) { QGList::removeNode(n); } + bool removeFirst() { return QGList::removeFirst(); } + bool removeLast() { return QGList::removeLast(); } + type *take( uint i ) { return (type *)QGList::takeAt(i); } + type *take() { return (type *)QGList::take(); } + type *takeNode( QLNode *n ) { return (type *)QGList::takeNode(n); } + void clear() { QGList::clear(); } + void sort() { QGList::sort(); } + int find( const type *d ) { return QGList::find((QCollection::Item)d); } + int findNext( const type *d ) { return QGList::find((QCollection::Item)d,FALSE); } + int findRef( const type *d ) { return QGList::findRef((QCollection::Item)d); } + int findNextRef( const type *d ){ return QGList::findRef((QCollection::Item)d,FALSE);} + uint contains( const type *d ) const { return QGList::contains((QCollection::Item)d); } + uint containsRef( const type *d ) const + { return QGList::containsRef((QCollection::Item)d); } + type *at( uint i ) { return (type *)QGList::at(i); } + int at() const { return QGList::at(); } + type *current() const { return (type *)QGList::get(); } + QLNode *currentNode() const { return QGList::currentNode(); } + type *getFirst() const { return (type *)QGList::cfirst(); } + type *getLast() const { return (type *)QGList::clast(); } + type *first() { return (type *)QGList::first(); } + type *last() { return (type *)QGList::last(); } + type *next() { return (type *)QGList::next(); } + type *prev() { return (type *)QGList::prev(); } + void toVector( QGVector *vec )const{ QGList::toVector(vec); } +private: + void deleteItem( QCollection::Item d ); +}; + +#if defined(Q_DELETING_VOID_UNDEFINED) +template<> inline void QList<void>::deleteItem( QCollection::Item ) +{ +} +#endif + +template<class type> inline void QList<type>::deleteItem( QCollection::Item d ) +{ + if ( del_item ) delete (type *)d; +} + + +template<class type> class Q_EXPORT QListIterator : public QGListIterator +{ +public: + QListIterator(const QList<type> &l) :QGListIterator((QGList &)l) {} + ~QListIterator() {} + uint count() const { return list->count(); } + bool isEmpty() const { return list->count() == 0; } + bool atFirst() const { return QGListIterator::atFirst(); } + bool atLast() const { return QGListIterator::atLast(); } + type *toFirst() { return (type *)QGListIterator::toFirst(); } + type *toLast() { return (type *)QGListIterator::toLast(); } + operator type *() const { return (type *)QGListIterator::get(); } + type *operator*() { return (type *)QGListIterator::get(); } + + // No good, since QList<char> (ie. QStrList fails... + // + // MSVC++ gives warning + // Sunpro C++ 4.1 gives error + // type *operator->() { return (type *)QGListIterator::get(); } + + type *current() const { return (type *)QGListIterator::get(); } + type *operator()() { return (type *)QGListIterator::operator()();} + type *operator++() { return (type *)QGListIterator::operator++(); } + type *operator+=(uint j) { return (type *)QGListIterator::operator+=(j);} + type *operator--() { return (type *)QGListIterator::operator--(); } + type *operator-=(uint j) { return (type *)QGListIterator::operator-=(j);} + QListIterator<type>& operator=(const QListIterator<type>&it) + { QGListIterator::operator=(it); return *this; } +}; + + +#endif // QLIST_H diff --git a/trunk/qtools/qmap.cpp b/trunk/qtools/qmap.cpp new file mode 100644 index 0000000..1d2510a --- /dev/null +++ b/trunk/qtools/qmap.cpp @@ -0,0 +1,254 @@ +/**************************************************************************** +** +** +** Implementation of QMap +** +** Created : 990406 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qmap.h" + +typedef QMapNodeBase* NodePtr; +typedef QMapNodeBase Node; + + +void QMapPrivateBase::rotateLeft( NodePtr x, NodePtr& root) +{ + NodePtr y = x->right; + x->right = y->left; + if (y->left !=0) + y->left->parent = x; + y->parent = x->parent; + if (x == root) + root = y; + else if (x == x->parent->left) + x->parent->left = y; + else + x->parent->right = y; + y->left = x; + x->parent = y; +} + + +void QMapPrivateBase::rotateRight( NodePtr x, NodePtr& root ) +{ + NodePtr y = x->left; + x->left = y->right; + if (y->right != 0) + y->right->parent = x; + y->parent = x->parent; + if (x == root) + root = y; + else if (x == x->parent->right) + x->parent->right = y; + else + x->parent->left = y; + y->right = x; + x->parent = y; +} + + +void QMapPrivateBase::rebalance( NodePtr x, NodePtr& root) +{ + x->color = Node::Red; + while ( x != root && x->parent->color == Node::Red ) { + if ( x->parent == x->parent->parent->left ) { + NodePtr y = x->parent->parent->right; + if (y && y->color == Node::Red) { + x->parent->color = Node::Black; + y->color = Node::Black; + x->parent->parent->color = Node::Red; + x = x->parent->parent; + } else { + if (x == x->parent->right) { + x = x->parent; + rotateLeft( x, root ); + } + x->parent->color = Node::Black; + x->parent->parent->color = Node::Red; + rotateRight (x->parent->parent, root ); + } + } else { + NodePtr y = x->parent->parent->left; + if ( y && y->color == Node::Red ) { + x->parent->color = Node::Black; + y->color = Node::Black; + x->parent->parent->color = Node::Red; + x = x->parent->parent; + } else { + if (x == x->parent->left) { + x = x->parent; + rotateRight( x, root ); + } + x->parent->color = Node::Black; + x->parent->parent->color = Node::Red; + rotateLeft( x->parent->parent, root ); + } + } + } + root->color = Node::Black; +} + + +NodePtr QMapPrivateBase::removeAndRebalance( NodePtr z, NodePtr& root, + NodePtr& leftmost, + NodePtr& rightmost ) +{ + NodePtr y = z; + NodePtr x; + NodePtr x_parent; + if (y->left == 0) { + x = y->right; + } else { + if (y->right == 0) + x = y->left; + else + { + y = y->right; + while (y->left != 0) + y = y->left; + x = y->right; + } + } + if (y != z) { + z->left->parent = y; + y->left = z->left; + if (y != z->right) { + x_parent = y->parent; + if (x) + x->parent = y->parent; + y->parent->left = x; + y->right = z->right; + z->right->parent = y; + } else { + x_parent = y; + } + if (root == z) + root = y; + else if (z->parent->left == z) + z->parent->left = y; + else + z->parent->right = y; + y->parent = z->parent; + // Swap the colors + Node::Color c = y->color; + y->color = z->color; + z->color = c; + y = z; + } else { + x_parent = y->parent; + if (x) + x->parent = y->parent; + if (root == z) + root = x; + else if (z->parent->left == z) + z->parent->left = x; + else + z->parent->right = x; + if ( leftmost == z ) { + if (z->right == 0) + leftmost = z->parent; + else + leftmost = x->minimum(); + } + if (rightmost == z) { + if (z->left == 0) + rightmost = z->parent; + else + rightmost = x->maximum(); + } + } + if (y->color != Node::Red) { + while (x != root && (x == 0 || x->color == Node::Black)) { + if (x == x_parent->left) { + NodePtr w = x_parent->right; + if (w->color == Node::Red) { + w->color = Node::Black; + x_parent->color = Node::Red; + rotateLeft(x_parent, root); + w = x_parent->right; + } + if ((w->left == 0 || w->left->color == Node::Black) && + (w->right == 0 || w->right->color == Node::Black)) { + w->color = Node::Red; + x = x_parent; + x_parent = x_parent->parent; + } else { + if (w->right == 0 || w->right->color == Node::Black) { + if (w->left) + w->left->color = Node::Black; + w->color = Node::Red; + rotateRight(w, root); + w = x_parent->right; + } + w->color = x_parent->color; + x_parent->color = Node::Black; + if (w->right) + w->right->color = Node::Black; + rotateLeft(x_parent, root); + break; + } + } else { + NodePtr w = x_parent->left; + if (w->color == Node::Red) { + w->color = Node::Black; + x_parent->color = Node::Red; + rotateRight(x_parent, root); + w = x_parent->left; + } + if ((w->right == 0 || w->right->color == Node::Black) && + (w->left == 0 || w->left->color == Node::Black)) { + w->color = Node::Red; + x = x_parent; + x_parent = x_parent->parent; + } else { + if (w->left == 0 || w->left->color == Node::Black) { + if (w->right) + w->right->color = Node::Black; + w->color = Node::Red; + rotateLeft(w, root); + w = x_parent->left; + } + w->color = x_parent->color; + x_parent->color = Node::Black; + if (w->left) + w->left->color = Node::Black; + rotateRight(x_parent, root); + break; + } + } + } + if (x) + x->color = Node::Black; + } + return y; +} diff --git a/trunk/qtools/qmap.h b/trunk/qtools/qmap.h new file mode 100644 index 0000000..f384a3d --- /dev/null +++ b/trunk/qtools/qmap.h @@ -0,0 +1,606 @@ +/**************************************************************************** +** +** +** Definition of QMap class +** +** Created : 990406 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QMAP_H +#define QMAP_H + +#ifndef QT_H +#include "qshared.h" +#include "qdatastream.h" +#endif // QT_H + + +struct QMapNodeBase +{ + enum Color { Red, Black }; + + QMapNodeBase* left; + QMapNodeBase* right; + QMapNodeBase* parent; + + Color color; + + QMapNodeBase* minimum() { + QMapNodeBase* x = this; + while ( x->left ) + x = x->left; + return x; + } + + QMapNodeBase* maximum() { + QMapNodeBase* x = this; + while ( x->right ) + x = x->right; + return x; + } +}; + + +template <class K, class T> +struct QMapNode : public QMapNodeBase +{ + QMapNode( const K& _key, const T& _data ) { data = _data; key = _key; } + QMapNode( const K& _key ) { key = _key; } + QMapNode( const QMapNode<K,T>& _n ) { key = _n.key; data = _n.data; } + QMapNode() { } + T data; + K key; +}; + + +template<class K, class T> +class Q_EXPORT QMapIterator +{ + public: + /** + * Typedefs + */ + typedef QMapNode< K, T >* NodePtr; + + /** + * Variables + */ + QMapNode<K,T>* node; + + /** + * Functions + */ + QMapIterator() : node( 0 ) {} + QMapIterator( QMapNode<K,T>* p ) : node( p ) {} + QMapIterator( const QMapIterator<K,T>& it ) : node( it.node ) {} + + bool operator==( const QMapIterator<K,T>& it ) const { return node == it.node; } + bool operator!=( const QMapIterator<K,T>& it ) const { return node != it.node; } + T& operator*() { return node->data; } + const T& operator*() const { return node->data; } + + // Cannot have this - some compilers are too stupid + //T* operator->() const { return &(node->data); } + + const K& key() const { return node->key; } + T& data() { return node->data; } + const T& data() const { return node->data; } + +private: + int inc() { + QMapNodeBase* tmp = node; + if ( tmp->right ) { + tmp = tmp->right; + while ( tmp->left ) + tmp = tmp->left; + } else { + QMapNodeBase* y = tmp->parent; + while (tmp == y->right) { + tmp = y; + y = y->parent; + } + if (tmp->right != y) + tmp = y; + } + node = (NodePtr)tmp; + return 0; + } + + int dec() { + QMapNodeBase* tmp = node; + if (tmp->color == QMapNodeBase::Red && + tmp->parent->parent == tmp ) { + tmp = tmp->right; + } else if (tmp->left != 0) { + QMapNodeBase* y = tmp->left; + while ( y->right ) + y = y->right; + tmp = y; + } else { + QMapNodeBase* y = tmp->parent; + while (tmp == y->left) { + tmp = y; + y = y->parent; + } + tmp = y; + } + node = (NodePtr)tmp; + return 0; + } + +public: + QMapIterator<K,T>& operator++() { + inc(); + return *this; + } + + QMapIterator<K,T> operator++(int) { + QMapIterator<K,T> tmp = *this; + inc(); + return tmp; + } + + QMapIterator<K,T>& operator--() { + dec(); + return *this; + } + + QMapIterator<K,T> operator--(int) { + QMapIterator<K,T> tmp = *this; + dec(); + return tmp; + } +}; + +template<class K, class T> +class Q_EXPORT QMapConstIterator +{ + public: + /** + * Typedefs + */ + typedef QMapNode< K, T >* NodePtr; + + /** + * Variables + */ + QMapNode<K,T>* node; + + /** + * Functions + */ + QMapConstIterator() : node( 0 ) {} + QMapConstIterator( QMapNode<K,T>* p ) : node( p ) {} + QMapConstIterator( const QMapConstIterator<K,T>& it ) : node( it.node ) {} + QMapConstIterator( const QMapIterator<K,T>& it ) : node( it.node ) {} + + bool operator==( const QMapConstIterator<K,T>& it ) const { return node == it.node; } + bool operator!=( const QMapConstIterator<K,T>& it ) const { return node != it.node; } + const T& operator*() const { return node->data; } + + // Cannot have this - some compilers are too stupid + //const T* operator->() const { return &(node->data); } + + const K& key() const { return node->key; } + const T& data() const { return node->data; } + +private: + int inc() { + QMapNodeBase* tmp = node; + if ( tmp->right ) { + tmp = tmp->right; + while ( tmp->left ) + tmp = tmp->left; + } else { + QMapNodeBase* y = tmp->parent; + while (tmp == y->right) { + tmp = y; + y = y->parent; + } + if (tmp->right != y) + tmp = y; + } + node = (NodePtr)tmp; + return 0; + } + + int dec() { + QMapNodeBase* tmp = node; + if (tmp->color == QMapNodeBase::Red && + tmp->parent->parent == tmp ) { + tmp = tmp->right; + } else if (tmp->left != 0) { + QMapNodeBase* y = tmp->left; + while ( y->right ) + y = y->right; + tmp = y; + } else { + QMapNodeBase* y = tmp->parent; + while (tmp == y->left) { + tmp = y; + y = y->parent; + } + tmp = y; + } + node = (NodePtr)tmp; + return 0; + } + +public: + QMapConstIterator<K,T>& operator++() { + inc(); + return *this; + } + + QMapConstIterator<K,T> operator++(int) { + QMapConstIterator<K,T> tmp = *this; + inc(); + return tmp; + } + + QMapConstIterator<K,T>& operator--() { + dec(); + return *this; + } + + QMapConstIterator<K,T> operator--(int) { + QMapConstIterator<K,T> tmp = *this; + dec(); + return tmp; + } +}; + + +class Q_EXPORT QMapPrivateBase : public QShared +{ +public: + QMapPrivateBase() { + node_count = 0; + } + QMapPrivateBase( const QMapPrivateBase* _map) { + node_count = _map->node_count; + } + + /** + * Implementations of basic tree algorithms + */ + void rotateLeft( QMapNodeBase* x, QMapNodeBase*& root); + void rotateRight( QMapNodeBase* x, QMapNodeBase*& root ); + void rebalance( QMapNodeBase* x, QMapNodeBase*& root ); + QMapNodeBase* removeAndRebalance( QMapNodeBase* z, QMapNodeBase*& root, + QMapNodeBase*& leftmost, + QMapNodeBase*& rightmost ); + + /** + * Variables + */ + int node_count; +}; + + +template <class Key, class T> +class QMapPrivate : public QMapPrivateBase +{ +public: + /** + * Typedefs + */ + typedef QMapIterator< Key, T > Iterator; + typedef QMapConstIterator< Key, T > ConstIterator; + typedef QMapNode< Key, T > Node; + typedef QMapNode< Key, T >* NodePtr; + + /** + * Functions + */ + QMapPrivate() { + header = new Node; + header->color = QMapNodeBase::Red; // Mark the header + header->parent = 0; + header->left = header->right = header; + } + QMapPrivate( const QMapPrivate< Key, T >* _map ) : QMapPrivateBase( _map ) { + header = new Node; + header->color = QMapNodeBase::Red; // Mark the header + if ( _map->header->parent == 0 ) { + header->parent = 0; + header->left = header->right = header; + } else { + header->parent = copy( (NodePtr)(_map->header->parent) ); + header->parent->parent = header; + header->left = header->parent->minimum(); + header->right = header->parent->maximum(); + } + } + ~QMapPrivate() { clear(); delete header; } + + NodePtr copy( NodePtr p ) { + if ( !p ) + return 0; + NodePtr n = new Node( *p ); + n->color = p->color; + if ( p->left ) { + n->left = copy( (NodePtr)(p->left) ); + n->left->parent = n; + } else { + n->left = 0; + } + if ( p->right ) { + n->right = copy( (NodePtr)(p->right) ); + n->right->parent = n; + } else { + n->right = 0; + } + return n; + } + + void clear() { + clear( (NodePtr)(header->parent) ); + header->color = QMapNodeBase::Red; + header->parent = 0; + header->left = header->right = header; + node_count = 0; + } + + void clear( NodePtr p ) { + while ( p != 0 ) { + clear( (NodePtr)p->right ); + NodePtr y = (NodePtr)p->left; + delete p; + p = y; + } + } + + Iterator begin() { return Iterator( (NodePtr)(header->left ) ); } + Iterator end() { return Iterator( header ); } + ConstIterator begin() const { return ConstIterator( (NodePtr)(header->left ) ); } + ConstIterator end() const { return ConstIterator( header ); } + + ConstIterator find(const Key& k) const { + QMapNodeBase* y = header; // Last node + QMapNodeBase* x = header->parent; // Root node. + + while ( x != 0 ) { + // If as k <= key(x) go left + if ( !( key(x) < k ) ) { + y = x; + x = x->left; + } else { + x = x->right; + } + } + + // Was k bigger/smaller then the biggest/smallest + // element of the tree ? Return end() + if ( y == header || k < key(y) ) + return ConstIterator( header ); + return ConstIterator( (NodePtr)y ); + } + + void remove( Iterator it ) { + NodePtr del = (NodePtr) removeAndRebalance( it.node, header->parent, header->left, header->right ); + delete del; + --node_count; + } + +#ifdef QT_QMAP_DEBUG + void inorder( QMapNodeBase* x = 0, int level = 0 ){ + if ( !x ) + x = header->parent; + if ( x->left ) + inorder( x->left, level + 1 ); + //cout << level << " Key=" << key(x) << " Value=" << ((NodePtr)x)->data << endl; + if ( x->right ) + inorder( x->right, level + 1 ); + } +#endif + + Iterator insertMulti(const Key& v){ + QMapNodeBase* y = header; + QMapNodeBase* x = header->parent; + while (x != 0){ + y = x; + x = ( v < key(x) ) ? x->left : x->right; + } + return insert(x, y, v); + } + + Iterator insertSingle( const Key& k ) { + // Search correct position in the tree + QMapNodeBase* y = header; + QMapNodeBase* x = header->parent; + bool result = TRUE; + while ( x != 0 ) { + result = ( k < key(x) ); + y = x; + x = result ? x->left : x->right; + } + // Get iterator on the last not empty one + Iterator j( (NodePtr)y ); + if ( result ) { + // Smaller then the leftmost one ? + if ( j == begin() ) { + return insert(x, y, k ); + } else { + // Perhaps daddy is the right one ? + --j; + } + } + // Really bigger ? + if ( (j.node->key) < k ) + return insert(x, y, k ); + // We are going to replace a node + return j; + } + + Iterator insert( QMapNodeBase* x, QMapNodeBase* y, const Key& k ) { + NodePtr z = new Node( k ); + if (y == header || x != 0 || k < key(y) ) { + y->left = z; // also makes leftmost = z when y == header + if ( y == header ) { + header->parent = z; + header->right = z; + } else if ( y == header->left ) + header->left = z; // maintain leftmost pointing to min node + } else { + y->right = z; + if ( y == header->right ) + header->right = z; // maintain rightmost pointing to max node + } + z->parent = y; + z->left = 0; + z->right = 0; + rebalance( z, header->parent ); + ++node_count; + return Iterator(z); + } + +protected: + /** + * Helpers + */ + const Key& key( QMapNodeBase* b ) const { return ((NodePtr)b)->key; } + + /** + * Variables + */ + NodePtr header; +}; + + +template<class Key, class T> +class Q_EXPORT QMap +{ +public: + /** + * Typedefs + */ + typedef QMapIterator< Key, T > Iterator; + typedef QMapConstIterator< Key, T > ConstIterator; + typedef T ValueType; + typedef QMapPrivate< Key, T > Priv; + + /** + * API + */ + QMap() { sh = new QMapPrivate< Key, T >; } + QMap( const QMap<Key,T>& m ) { sh = m.sh; sh->ref(); } + ~QMap() { if ( sh->deref() ) delete sh; } + + QMap<Key,T>& operator= ( const QMap<Key,T>& m ) + { m.sh->ref(); if ( sh->deref() ) delete sh; sh = m.sh; return *this; } + + Iterator begin() { detach(); return sh->begin(); } + Iterator end() { detach(); return sh->end(); } + ConstIterator begin() const { return ((const Priv*)sh)->begin(); } + ConstIterator end() const { return ((const Priv*)sh)->end(); } + + Iterator find ( const Key& k ) + { detach(); return Iterator( sh->find( k ).node ); } + ConstIterator find ( const Key& k ) const + { return sh->find( k ); } + T& operator[] ( const Key& k ) { + detach(); QMapNode<Key,T>* p = sh->find( k ).node; + if ( p != sh->end().node ) return p->data; + return insert( k, T() ).data(); } + const T& operator[] ( const Key& k ) const + { return sh->find( k ).data(); } + bool contains ( const Key& k ) const + { return find( k ) != end(); } + //{ return sh->find( k ) != ((const Priv*)sh)->end(); } + + uint count() const { return sh->node_count; } + + bool isEmpty() const { return sh->node_count == 0; } + + Iterator insert( const Key& key, const T& value ) { + detach(); + Iterator it = sh->insertSingle( key ); + it.data() = value; + return it; + } + + void remove( Iterator it ) { detach(); sh->remove( it ); } + void remove( const Key& k ) { + detach(); + Iterator it( sh->find( k ).node ); + if ( it != end() ) + sh->remove( it ); + } + + Iterator replace( const Key& k, const T& v ) { + remove( k ); + return insert( k, v ); + } + + void clear() { if ( sh->count == 1 ) sh->clear(); else { sh->deref(); sh = new QMapPrivate<Key,T>; } } + +#if defined(Q_FULL_TEMPLATE_INSTANTIATION) + bool operator==( const QMap<Key,T>& ) const { return FALSE; } +#endif + +protected: + /** + * Helpers + */ + void detach() { if ( sh->count > 1 ) { sh->deref(); sh = new QMapPrivate<Key,T>( sh ); } } + + Priv* sh; +}; + + +#ifndef QT_NO_DATASTREAM +template<class Key, class T> +inline QDataStream& operator>>( QDataStream& s, QMap<Key,T>& m ) { + m.clear(); + Q_UINT32 c; + s >> c; + for( Q_UINT32 i = 0; i < c; ++i ) { + Key k; T t; + s >> k >> t; + m.insert( k, t ); + } + return s; +} + + +template<class Key, class T> +inline QDataStream& operator<<( QDataStream& s, const QMap<Key,T>& m ) { + s << (Q_UINT32)m.count(); + QMapConstIterator<Key,T> it = m.begin(); + for( ; it != m.end(); ++it ) + s << it.key() << it.data(); + return s; +} +#endif + +#endif // QMAP_H diff --git a/trunk/qtools/qmodules.h b/trunk/qtools/qmodules.h new file mode 100644 index 0000000..08f0baf --- /dev/null +++ b/trunk/qtools/qmodules.h @@ -0,0 +1,11 @@ +// These modules are licensed to you +#define QT_MODULE_TOOLS +#define QT_MODULE_KERNEL +#define QT_MODULE_WIDGETS +#define QT_MODULE_DIALOGS +#define QT_MODULE_ICONVIEW +#define QT_MODULE_WORKSPACE +#define QT_MODULE_NETWORK +#define QT_MODULE_CANVAS +#define QT_MODULE_TABLE +#define QT_MODULE_XML diff --git a/trunk/qtools/qptrdict.doc b/trunk/qtools/qptrdict.doc new file mode 100644 index 0000000..bff6a15 --- /dev/null +++ b/trunk/qtools/qptrdict.doc @@ -0,0 +1,486 @@ +/**************************************************************************** +** +** +** QPtrDict and QPtrDictIterator class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QPtrDict documentation + *****************************************************************************/ + +/*! + \class QPtrDict qptrdict.h + \brief The QPtrDict class is a template class that provides a dictionary based on \c void* keys. + + \ingroup collection + \ingroup tools + + QPtrDict is implemented as a template class. Define a + template instance QPtrDict\<X\> to create a dictionary that operates on + pointers to X, or X*. + + A dictionary is a collection that associates an item with a key. + The key is used for inserting and looking up an item. QPtrDict has + \c void* keys. + + The dictionary has very fast insertion and lookup. + + Example: + \code + #include <qptrdict.h> + #include <stdio.h> + + void main() + { + int *a = new int[12]; + int *b = new int[10]; + int *c = new int[18]; + int *d = new int[13]; + + QPtrDict<char> dict; // maps void* -> char* + + dict.insert( a, "a is int[12]" ); // describe pointers + dict.insert( b, "b is int[10]" ); + dict.insert( c, "c is int[18]" ); + + printf( "%s\n", dict[a] ); // print descriptions + printf( "%s\n", dict[b] ); + printf( "%s\n", dict[c] ); + + if ( !dict[d] ) + printf( "d not in dictionary\n" ); + } + \endcode + + Program output: + \code + a is int[12] + b is int[10] + c is int[18] + d not in dictionary + \endcode + + The dictionary in our example maps \c int* keys to \c char* items. + QPtrDict implements the \link operator[] [] operator\endlink to lookup + an item. + + QPtrDict is implemented by QGDict as a hash array with a fixed number of + entries. Each array entry points to a singly linked list of buckets, in + which the dictionary items are stored. + + When an item is inserted with a key, the key is converted (hashed) to + an integer index into the hash array using the \c mod operation. The + item is inserted before the first bucket in the list of buckets. + + Looking up an item is normally very fast. The key is again hashed to an + array index. Then QPtrDict scans the list of buckets and returns the item + found or null if the item was not found. You cannot insert null pointers + into a dictionary. + + The size of the hash array is very important. In order to get good + performance, you should use a suitably large \link primes.html prime + number\endlink. Suitable means equal to or larger than the maximum + expected number of dictionary items. + + Items with equal keys are allowed. When inserting two items with the + same key, only the last inserted item will be visible (last in, first out) + until it is removed. + + Example: + \code + #include <qptrdict.h> + #include <stdio.h> + + void main() + { + QPtrDict<char> dict; // maps char* ==> char* + + double *ptr = new double[28]; + dict.insert( ptr, "first" ); + dict.insert( ptr, "second" ); + + printf( "%s\n", dict[ptr] ); + dict.remove( ptr ); + printf( "%s\n", dict[ptr] ); + } + \endcode + + Program output: + \code + second + first + \endcode + + The QPtrDictIterator class can traverse the dictionary contents, but only + in an arbitrary order. Multiple iterators may independently traverse the + same dictionary. + + Calling setAutoDelete(TRUE) for a dictionary tells it to delete items + that are removed . The default is to not delete items when they are + removed. + + When inserting an item into a dictionary, only the pointer is copied, not + the item itself. This is called a shallow copy. It is possible to make the + dictionary copy all of the item's data (known as a deep copy) when an + item is inserted. insert() calls the virtual function + QCollection::newItem() for the item to be inserted. + Inherit a dictionary and reimplement it if you want deep copies. + + When removing a dictionary item, the virtual function + QCollection::deleteItem() is called. QPtrDict's default implementation + is to delete the item if auto-deletion is enabled. + + \sa QPtrDictIterator, QDict, QAsciiDict, QIntDict, + \link collection.html Collection Classes\endlink +*/ + + +/*! + \fn QPtrDict::QPtrDict( int size ) + Constructs a dictionary using an internal hash array with the size + \e size. + + Setting \e size to a suitably large \link primes.html prime number\endlink + (equal to or greater than the expected number of entries) makes the hash + distribution better and hence the loopup faster. +*/ + +/*! + \fn QPtrDict::QPtrDict( const QPtrDict<type> &dict ) + Constructs a copy of \e dict. + + Each item in \e dict are inserted into this dictionary. + Only the pointers are copied (shallow copy). +*/ + +/*! + \fn QPtrDict::~QPtrDict() + Removes all items from the dictionary and destroys it. + + All iterators that access this dictionary will be reset. + + \sa setAutoDelete() +*/ + +/*! + \fn QPtrDict<type> &QPtrDict::operator=(const QPtrDict<type> &dict) + Assigns \e dict to this dictionary and returns a reference to this + dictionary. + + This dictionary is first cleared, then each item in \e dict is inserted + into this dictionary. + Only the pointers are copied (shallow copy), unless newItem() has been + reimplemented(). +*/ + +/*! + \fn uint QPtrDict::count() const + Returns the number of items in the dictionary. + \sa isEmpty() +*/ + +/*! + \fn uint QPtrDict::size() const + Returns the size of the internal hash array (as specified in the + constructor). + \sa count() +*/ + +/*! + \fn void QPtrDict::resize( uint newsize ) + Changes the size of the hashtable the \a newsize. + The contents of the dictionary are preserved, + but all iterators on the dictionary become invalid. +*/ + +/*! + \fn bool QPtrDict::isEmpty() const + Returns TRUE if the dictionary is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn void QPtrDict::insert( void *key, const type *item ) + Inserts the \e key with the \e item into the dictionary. + + The key does not have to be a unique dictionary key. If multiple items + are inserted with the same key, only the last item will be visible. + + Null items are not allowed. + + \sa replace() +*/ + +/*! + \fn void QPtrDict::replace( void *key, const type *item ) + Replaces an item which has a key equal to \e key with \e item. + + If the item does not already exist, it will be inserted. + + Null items are not allowed. + + Equivalent to: + \code + QPtrDict<char> dict; + ... + if ( dict.find(key) ) + dict.remove( key ); + dict.insert( key, item ); + \endcode + + If there are two or more items with equal keys, then the last inserted + of these will be replaced. + + \sa insert() +*/ + +/*! + \fn bool QPtrDict::remove( void *key ) + Removes the item associated with \e key from the dictionary. + Returns TRUE if successful, or FALSE if the key does not exist in the + dictionary. + + If there are two or more items with equal keys, then the last inserted + of these will be removed. + + The removed item is deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All dictionary iterators that refer to the removed item will be set to + point to the next item in the dictionary traversing order. + + \sa take(), clear(), setAutoDelete() +*/ + +/*! + \fn type *QPtrDict::take( void *key ) + Takes the item associated with \e key out of the dictionary without + deleting it (even if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled). + + If there are two or more items with equal keys, then the last inserted + of these will be taken. + + Returns a pointer to the item taken out, or null if the key does not + exist in the dictionary. + + All dictionary iterators that refer to the taken item will be set to + point to the next item in the dictionary traversing order. + + \sa remove(), clear(), setAutoDelete() +*/ + +/*! + \fn void QPtrDict::clear() + Removes all items from the dictionary. + + The removed items are deleted if \link QCollection::setAutoDelete() + auto-deletion\endlink is enabled. + + All dictionary iterators that access this dictionary will be reset. + + \sa remove(), take(), setAutoDelete() +*/ + +/*! + \fn type *QPtrDict::find( void *key ) const + Returns the item associated with \e key, or null if the key does not + exist in the dictionary. + + This function uses an internal hashing algorithm to optimize lookup. + + If there are two or more items with equal keys, then the last inserted + of these will be found. + + Equivalent to the [] operator. + + \sa operator[]() +*/ + +/*! + \fn type *QPtrDict::operator[]( void *key ) const + Returns the item associated with \e key, or null if the key does not + exist in the dictionary. + + This function uses an internal hashing algorithm to optimize lookup. + + If there are two or more items with equal keys, then the last inserted + of these will be found. + + Equivalent to the find() function. + + \sa find() +*/ + +/*! + \fn void QPtrDict::statistics() const + Debugging-only function that prints out the dictionary distribution + using qDebug(). +*/ + + +/***************************************************************************** + QPtrDictIterator documentation + *****************************************************************************/ + +/*! + \class QPtrDictIterator qptrdict.h + \brief The QPtrDictIterator class provides an iterator for QPtrDict collections. + + \ingroup collection + \ingroup tools + + QPtrDictIterator is implemented as a template class. + Define a template instance QPtrDictIterator\<X\> to create a + dictionary iterator that operates on QPtrDict\<X\> (dictionary of X*). + + Example: + \code + #include <qptrdict.h> + #include <stdio.h> + + void main() + { + int *a = new int[12]; + int *b = new int[10]; + int *c = new int[18]; + int *d = new int[13]; + + QPtrDict<char> dict; // maps void* -> char* + + dict.insert( a, "a is int[12]" ); // describe pointers + dict.insert( b, "b is int[10]" ); + dict.insert( c, "c is int[18]" ); + + QPtrDictIterator<char> it( dict ); // iterator for dict + + while ( it.current() ) { + printf( "%x -> %s\n", it.currentKey(), it.current() ); + ++it; + } + } + \endcode + + Program output: + \code + 804a788 -> a is int[12] + 804a7f0 -> c is int[18] + 804a7c0 -> b is int[10] + \endcode + + Note that the traversal order is arbitrary, you are not guaranteed the + order above. + + Multiple iterators may independently traverse the same dictionary. + A QPtrDict knows about all iterators that are operating on the dictionary. + When an item is removed from the dictionary, QPtrDict update all + iterators that are referring the removed item to point to the next item + in the traversing order. + + \sa QPtrDict, \link collection.html Collection Classes\endlink +*/ + +/*! + \fn QPtrDictIterator::QPtrDictIterator( const QPtrDict<type> &dict ) + Constructs an iterator for \e dict. The current iterator item is + set to point on the first item in the \e dict. +*/ + +/*! + \fn QPtrDictIterator::~QPtrDictIterator() + Destroys the iterator. +*/ + +/*! + \fn uint QPtrDictIterator::count() const + Returns the number of items in the dictionary this iterator operates on. + \sa isEmpty() +*/ + +/*! + \fn bool QPtrDictIterator::isEmpty() const + Returns TRUE if the dictionary is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn type *QPtrDictIterator::toFirst() + Sets the current iterator item to point to the first item in the + dictionary and returns a pointer to the item. + If the dictionary is empty it sets the current item to null and + returns null. +*/ + +/*! + \fn QPtrDictIterator::operator type *() const + Cast operator. Returns a pointer to the current iterator item. + Same as current(). +*/ + +/*! + \fn type *QPtrDictIterator::current() const + Returns a pointer to the current iterator item. +*/ + +/*! + \fn void *QPtrDictIterator::currentKey() const + Returns the key for the current iterator item. +*/ + +/*! + \fn type *QPtrDictIterator::operator()() + Makes the succeeding item current and returns the original current item. + + If the current iterator item was the last item in the dictionary or if it + was null, null is returned. +*/ + +/*! + \fn type *QPtrDictIterator::operator++() + Prefix ++ makes the succeeding item current and returns the new current + item. + + If the current iterator item was the last item in the dictionary or if it + was null, null is returned. +*/ + +/*! + \fn type *QPtrDictIterator::operator+=( uint jump ) + Sets the current item to the item \e jump positions after the current item, + and returns a pointer to that item. + + If that item is beyond the last item or if the dictionary is empty, + it sets the current item to null and returns null. +*/ diff --git a/trunk/qtools/qptrdict.h b/trunk/qtools/qptrdict.h new file mode 100644 index 0000000..c075e30 --- /dev/null +++ b/trunk/qtools/qptrdict.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** +** Definition of QPtrDict template class +** +** Created : 970415 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QPTRDICT_H +#define QPTRDICT_H + +#ifndef QT_H +#include "qgdict.h" +#endif // QT_H + + +template<class type> class Q_EXPORT QPtrDict : public QGDict +{ +public: + QPtrDict(int size=17) : QGDict(size,PtrKey,0,0) {} + QPtrDict( const QPtrDict<type> &d ) : QGDict(d) {} + ~QPtrDict() { clear(); } + QPtrDict<type> &operator=(const QPtrDict<type> &d) + { return (QPtrDict<type>&)QGDict::operator=(d); } + uint count() const { return QGDict::count(); } + uint size() const { return QGDict::size(); } + bool isEmpty() const { return QGDict::count() == 0; } + void insert( void *k, const type *d ) + { QGDict::look_ptr(k,(Item)d,1); } + void replace( void *k, const type *d ) + { QGDict::look_ptr(k,(Item)d,2); } + bool remove( void *k ) { return QGDict::remove_ptr(k); } + type *take( void *k ) { return (type*)QGDict::take_ptr(k); } + type *find( void *k ) const + { return (type *)((QGDict*)this)->QGDict::look_ptr(k,0,0); } + type *operator[]( void *k ) const + { return (type *)((QGDict*)this)->QGDict::look_ptr(k,0,0); } + void clear() { QGDict::clear(); } + void resize( uint n ) { QGDict::resize(n); } + void statistics() const { QGDict::statistics(); } +private: + void deleteItem( Item d ); +}; + +#if defined(Q_DELETING_VOID_UNDEFINED) +template<> inline void QPtrDict<void>::deleteItem( QCollection::Item ) +{ +} +#endif + +template<class type> inline void QPtrDict<type>::deleteItem( QCollection::Item d ) +{ + if ( del_item ) delete (type *)d; +} + + +template<class type> class Q_EXPORT QPtrDictIterator : public QGDictIterator +{ +public: + QPtrDictIterator(const QPtrDict<type> &d) :QGDictIterator((QGDict &)d) {} + ~QPtrDictIterator() {} + uint count() const { return dict->count(); } + bool isEmpty() const { return dict->count() == 0; } + type *toFirst() { return (type *)QGDictIterator::toFirst(); } + operator type *() const { return (type *)QGDictIterator::get(); } + type *current() const { return (type *)QGDictIterator::get(); } + void *currentKey() const { return QGDictIterator::getKeyPtr(); } + type *operator()() { return (type *)QGDictIterator::operator()(); } + type *operator++() { return (type *)QGDictIterator::operator++(); } + type *operator+=(uint j) { return (type *)QGDictIterator::operator+=(j);} +}; + + +#endif // QPTRDICT_H diff --git a/trunk/qtools/qqueue.h b/trunk/qtools/qqueue.h new file mode 100644 index 0000000..94bc130 --- /dev/null +++ b/trunk/qtools/qqueue.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** +** Definition of QQueue template/macro class +** +** Created : 920917 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QQUEUE_H +#define QQUEUE_H + +#ifndef QT_H +#include "qglist.h" +#endif // QT_H + + +template<class type> class QQueue : private QGList +{ +public: + QQueue() {} + QQueue( const QQueue<type> &q ) : QGList(q) {} + ~QQueue() { clear(); } + QQueue<type>& operator=(const QQueue<type> &q) + { return (QQueue<type>&)QGList::operator=(q); } + bool autoDelete() const { return QCollection::autoDelete(); } + void setAutoDelete( bool del ) { QCollection::setAutoDelete(del); } + uint count() const { return QGList::count(); } + bool isEmpty() const { return QGList::count() == 0; } + void enqueue( const type *d ) { QGList::append(Item(d)); } + type *dequeue() { return (type *)QGList::takeFirst();} + bool remove() { return QGList::removeFirst(); } + void clear() { QGList::clear(); } + type *head() const { return (type *)QGList::cfirst(); } + operator type *() const { return (type *)QGList::cfirst(); } + type *current() const { return (type *)QGList::cfirst(); } +private: + void deleteItem( Item d ) { if ( del_item ) delete (type *)d; } +}; + + +#endif // QQUEUE_H diff --git a/trunk/qtools/qregexp.cpp b/trunk/qtools/qregexp.cpp new file mode 100644 index 0000000..671867e --- /dev/null +++ b/trunk/qtools/qregexp.cpp @@ -0,0 +1,1091 @@ +/**************************************************************************** +** +** +** Implementation of QRegExp class +** +** Created : 950126 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qregexp.h" +#include <ctype.h> +#include <stdlib.h> + +// NOT REVISED +/*! + \class QRegExp qregexp.h + \ingroup tools + \ingroup misc + \brief The QRegExp class provides pattern matching using regular + expressions or wildcards. + + QRegExp knows these regexp primitives: + <ul plain> + <li><dfn>c</dfn> matches the character 'c' + <li><dfn>.</dfn> matches any character + <li><dfn>^</dfn> matches start of input + <li><dfn>$</dfn> matches end of input + <li><dfn>[]</dfn> matches a defined set of characters - see below. + <li><dfn>a*</dfn> matches a sequence of zero or more a's + <li><dfn>a+</dfn> matches a sequence of one or more a's + <li><dfn>a?</dfn> matches an optional a + <li><dfn>\c</dfn> escape code for matching special characters such + as \, [, *, +, . etc. + <li><dfn>\t</dfn> matches the TAB character (9) + <li><dfn>\n</dfn> matches newline (10) + <li><dfn>\r</dfn> matches return (13) + <li><dfn>\s</dfn> matches a white space (defined as any character + for which QChar::isSpace() returns TRUE. This includes at least + ASCII characters 9 (TAB), 10 (LF), 11 (VT), 12(FF), 13 (CR) and 32 + (Space)). + <li><dfn>\d</dfn> matches a digit (defined as any character for + which QChar::isDigit() returns TRUE. This includes at least ASCII + characters '0'-'9'). + <li><dfn>\x1f6b</dfn> matches the character with unicode point U1f6b + (hexadecimal 1f6b). \x0012 will match the ASCII/Latin1 character + 0x12 (18 decimal, 12 hexadecimal). + <li><dfn>\022</dfn> matches the ASCII/Latin1 character 022 (18 + decimal, 22 octal). + </ul> + + In wildcard mode, it only knows four primitives: + <ul plain> + <li><dfn>c</dfn> matches the character 'c' + <li><dfn>?</dfn> matches any character + <li><dfn>*</dfn> matches any sequence of characters + <li><dfn>[]</dfn> matches a defined set of characters - see below. + </ul> + + QRegExp supports Unicode both in the pattern strings and in the + strings to be matched. + + When writing regular expressions in C++ code, remember that C++ + processes \ characters. So in order to match e.g. a "." character, + you must write "\\." in C++ source, not "\.". + + A character set matches a defined set of characters. For example, + [BSD] matches any of 'B', 'D' and 'S'. Within a character set, the + special characters '.', '*', '?', '^', '$', '+' and '[' lose their + special meanings. The following special characters apply: + <ul plain> + <li><dfn>^</dfn> When placed first in the list, changes the + character set to match any character \e not in the list. To include + the character '^' itself in the set, escape it or place it anywhere + but first. + <li><dfn>-</dfn> Defines a range of characters. To include the + character '-' itself in the set, escape it or place it last. + <li><dfn>]</dfn> Ends the character set definition. To include the + character ']' itself in the set, escape it or place it first (but + after the negation operator '^', if present) + </ul> + Thus, [a-zA-Z0-9.] matches upper and lower case ASCII letters, + digits and dot; and [^\s] matches everything except white space. + + \bug Case insensitive matching is not supported for non-ASCII/Latin1 + (non-8bit) characters. Any character with a non-zero QChar.row() is + matched case sensitively even if the QRegExp is in case insensitive + mode. + + \note In Qt 3.0, the language of regular expressions will contain + five more special characters, namely '(', ')', '{', '|' and '}'. To + ease porting, it's a good idea to escape these characters with a + backslash in all the regular expressions you'll write from now on. +*/ + + +// +// The regexp pattern is internally represented as an array of uints, +// each element containing an 16-bit character or a 32-bit code +// (listed below). User-defined character classes (e.g. [a-zA-Z]) +// are encoded as this: +// uint no: 1 2 3 ... +// value: CCL | n from | to from | to +// +// where n is the (16-bit) number of following range definitions and +// from and to define the ranges inclusive. from <= to is always true, +// otherwise it is a built-in charclass (Pxx, eg \s - PWS). Single +// characters in the class are coded as from==to. Negated classes +// (e.g. [^a-z]) use CCN instead of CCL. + +const uint END = 0x00000000; +const uint PWS = 0x10010000; // predef charclass: whitespace (\s) +const uint PDG = 0x10020000; // predef charclass: digit (\d) +const uint CCL = 0x20010000; // character class [] +const uint CCN = 0x20020000; // neg character class [^] +const uint CHR = 0x40000000; // character +const uint BOL = 0x80010000; // beginning of line ^ +const uint EOL = 0x80020000; // end of line $ +const uint BOW = 0x80030000; // beginning of word \< +const uint EOW = 0x80040000; // end of word \> +const uint ANY = 0x80050000; // any character . +const uint CLO = 0x80070000; // Kleene closure * +const uint OPT = 0x80080000; // Optional closure ? + +const uint MCC = 0x20000000; // character class bitmask +const uint MCD = 0xffff0000; // code mask +const uint MVL = 0x0000ffff; // value mask + +// +// QRegExp::error codes (internal) +// + +const int PatOk = 0; // pattern ok +const int PatNull = 1; // no pattern defined +const int PatSyntax = 2; // pattern syntax error +const int PatOverflow = 4; // pattern too long + + +/***************************************************************************** + QRegExp member functions + *****************************************************************************/ + +/*! + Constructs an empty regular expression. +*/ + +QRegExp::QRegExp() +{ + rxdata = 0; + cs = TRUE; + wc = FALSE; + error = PatOk; +} + +/*! + Constructs a regular expression. + + \arg \e pattern is the regular expression pattern string. + \arg \e caseSensitive specifies whether or not to use case sensitive + matching. + \arg \e wildcard specifies whether the pattern string should be used for + wildcard matching (also called globbing expression), normally used for + matching file names. + + \sa setWildcard() +*/ + +QRegExp::QRegExp( const QString &pattern, bool caseSensitive, bool wildcard ) +{ + rxstring = pattern; + rxdata = 0; + cs = caseSensitive; + wc = wildcard; + compile(); +} + +/*! + Constructs a regular expression which is a copy of \e r. + \sa operator=(const QRegExp&) +*/ + +QRegExp::QRegExp( const QRegExp &r ) +{ + rxstring = r.pattern(); + rxdata = 0; + cs = r.caseSensitive(); + wc = r.wildcard(); + compile(); +} + +/*! + Destructs the regular expression and cleans up its internal data. +*/ + +QRegExp::~QRegExp() +{ + if ( rxdata ) // Avoid purify complaints + delete [] rxdata; +} + +/*! + Copies the regexp \e r and returns a reference to this regexp. + The case sensitivity and wildcard options are copied, as well. +*/ + +QRegExp &QRegExp::operator=( const QRegExp &r ) +{ + rxstring = r.rxstring; + cs = r.cs; + wc = r.wc; + compile(); + return *this; +} + +/*! + \obsolete + Consider using setPattern() instead of this method. + + Sets the pattern string to \e pattern and returns a reference to this regexp. + The case sensitivity or wildcard options do not change. +*/ + +QRegExp &QRegExp::operator=( const QString &pattern ) +{ + rxstring = pattern; + compile(); + return *this; +} + + +/*! + Returns TRUE if this regexp is equal to \e r. + + Two regexp objects are equal if they have equal pattern strings, + case sensitivity options and wildcard options. +*/ + +bool QRegExp::operator==( const QRegExp &r ) const +{ + return rxstring == r.rxstring && cs == r.cs && wc == r.wc; +} + +/*! + \fn bool QRegExp::operator!=( const QRegExp &r ) const + + Returns TRUE if this regexp is \e not equal to \e r. + + \sa operator==() +*/ + +/*! + \fn bool QRegExp::isEmpty() const + Returns TRUE if the regexp is empty. +*/ + +/*! + \fn bool QRegExp::isValid() const + Returns TRUE if the regexp is valid, or FALSE if it is invalid. + + The pattern "[a-z" is an example of an invalid pattern, since it lacks a + closing bracket. +*/ + + +/*! + \fn bool QRegExp::wildcard() const + Returns TRUE if wildcard mode is on, otherwise FALSE. \sa setWildcard(). +*/ + +/*! + Sets the wildcard option for the regular expression. The default + is FALSE. + + Setting \e wildcard to TRUE makes it convenient to match filenames + instead of plain text. + + For example, "qr*.cpp" matches the string "qregexp.cpp" in wildcard mode, + but not "qicpp" (which would be matched in normal mode). + + \sa wildcard() +*/ + +void QRegExp::setWildcard( bool wildcard ) +{ + if ( wildcard != wc ) { + wc = wildcard; + compile(); + } +} + +/*! + \fn bool QRegExp::caseSensitive() const + + Returns TRUE if case sensitivity is enabled, otherwise FALSE. The + default is TRUE. + + \sa setCaseSensitive() +*/ + +/*! + Enables or disables case sensitive matching. + + In case sensitive mode, "a.e" matches "axe" but not "Axe". + + See also: caseSensitive() +*/ + +void QRegExp::setCaseSensitive( bool enable ) +{ + if ( cs != enable ) { + cs = enable; + compile(); + } +} + + +/*! + \fn QString QRegExp::pattern() const + Returns the pattern string of the regexp. +*/ + + +/*! + \fn void QRegExp::setPattern(const QString & pattern) + Sets the pattern string to \a pattern and returns a reference to this regexp. + The case sensitivity or wildcard options do not change. +*/ + +static inline bool iswordchar( int x ) +{ + return isalnum(x) || x == '_'; //# Only 8-bit support +} + + +/*! + \internal + Match character class +*/ + +static bool matchcharclass( uint *rxd, QChar c ) +{ + uint *d = rxd; + uint clcode = *d & MCD; + bool neg = clcode == CCN; + if ( clcode != CCL && clcode != CCN) + qWarning("QRegExp: Internal error, please report to qt-bugs@trolltech.com"); + uint numFields = *d & MVL; + uint cval = (((uint)(c.row())) << 8) | ((uint)c.cell()); + bool found = FALSE; + for ( int i = 0; i < (int)numFields; i++ ) { + d++; + if ( *d == PWS && c.isSpace() ) { + found = TRUE; + break; + } + if ( *d == PDG && c.isDigit() ) { + found = TRUE; + break; + } + else { + uint from = ( *d & MCD ) >> 16; + uint to = *d & MVL; + if ( (cval >= from) && (cval <= to) ) { + found = TRUE; + break; + } + } + } + return neg ? !found : found; +} + + + +/* + Internal: Recursively match string. +*/ + +static int matchstring( uint *rxd, const QChar *str, uint strlength, + const QChar *bol, bool cs ) +{ + const QChar *p = str; + const QChar *start = p; + uint pl = strlength; + uint *d = rxd; + + //### in all cases here: handle pl == 0! (don't read past strlen) + while ( *d ) { + if ( *d & CHR ) { // match char + if ( !pl ) + return -1; + QChar c( *d ); + if ( !cs && !c.row() ) { // case insensitive, #Only 8bit + if ( p->row() || tolower(p->cell()) != c.cell() ) + return -1; + p++; + pl--; + } else { // case insensitive + if ( *p != c ) + return -1; + p++; + pl--; + } + d++; + } + else if ( *d & MCC ) { // match char class + if ( !pl ) + return -1; + if ( !matchcharclass( d, *p ) ) + return -1; + p++; + pl--; + d += (*d & MVL) + 1; + } + else switch ( *d++ ) { + case PWS: // match whitespace + if ( !pl || !p->isSpace() ) + return -1; + p++; + pl--; + break; + case PDG: // match digits + if ( !pl || !p->isDigit() ) + return -1; + p++; + pl--; + break; + case ANY: // match anything + if ( !pl ) + return -1; + p++; + pl--; + break; + case BOL: // match beginning of line + if ( p != bol ) + return -1; + break; + case EOL: // match end of line + if ( pl ) + return -1; + break; + case BOW: // match beginning of word + if ( !iswordchar(*p) || (p > bol && iswordchar(*(p-1)) ) ) + return -1; + break; + case EOW: // match end of word + if ( iswordchar(*p) || p == bol || !iswordchar(*(p-1)) ) + return -1; + break; + case CLO: // Kleene closure + { + const QChar *first_p = p; + if ( *d & CHR ) { // match char + QChar c( *d ); + if ( !cs && !c.row() ) { // case insensitive, #only 8bit + while ( pl && !p->row() && tolower(p->cell())==c.cell() ) { + p++; + pl--; + } + } + else { // case sensitive + while ( pl && *p == c ) { + p++; + pl--; + } + } + d++; + } + else if ( *d & MCC ) { // match char class + while( pl && matchcharclass( d, *p ) ) { + p++; + pl--; + } + d += (*d & MVL) + 1; + } + else if ( *d == PWS ) { + while ( pl && p->isSpace() ) { + p++; + pl--; + } + d++; + } + else if ( *d == PDG ) { + while ( pl && p->isDigit() ) { + p++; + pl--; + } + d++; + } + else if ( *d == ANY ) { + p += pl; + pl = 0; + d++; + } + else { + return -1; // error + } + d++; // skip CLO's END + while ( p >= first_p ) { // go backwards + int end = matchstring( d, p, pl, bol, cs ); + if ( end >= 0 ) + return ( p - start ) + end; + if ( !p ) + return -1; + --p; + ++pl; + } + } + return -1; + case OPT: // optional closure + { + const QChar *first_p = p; + if ( *d & CHR ) { // match char + QChar c( *d ); + if ( !cs && !c.row() ) { // case insensitive, #only 8bit + if ( pl && !p->row() && tolower(p->cell()) == c.cell() ) { + p++; + pl--; + } + } + else { // case sensitive + if ( pl && *p == c ) { + p++; + pl--; + } + } + d++; + } + else if ( *d & MCC ) { // match char class + if ( pl && matchcharclass( d, *p ) ) { + p++; + pl--; + } + d += (*d & MVL) + 1; + } + else if ( *d == PWS ) { + if ( pl && p->isSpace() ) { + p++; + pl--; + } + d++; + } + else if ( *d == PDG ) { + if ( pl && p->isDigit() ) { + p++; + pl--; + } + d++; + } + else if ( *d == ANY ) { + if ( pl ) { + p++; + pl--; + } + d++; + } + else { + return -1; // error + } + d++; // skip OPT's END + while ( p >= first_p ) { // go backwards + int end = matchstring( d, p, pl, bol, cs ); + if ( end >= 0 ) + return ( p - start ) + end; + if ( !p ) + return -1; + --p; + ++pl; + } + } + return -1; + + default: // error + return -1; + } + } + return p - start; +} + + +/*! + \internal + Recursively match string. +*/ + +// This is obsolete now, but since it is protected (not private), it +// is still implemented on the off-chance that somebody has made a +// class derived from QRegExp and calls this directly. +// Qt 3.0: Remove this? + + +const QChar *QRegExp::matchstr( uint *rxd, const QChar *str, uint strlength, + const QChar *bol ) const +{ + int len = matchstring( rxd, str, strlength, bol, cs ); + if ( len < 0 ) + return 0; + return str + len; +} + +/*! + Attempts to match in \e str, starting from position \e index. + Returns the position of the match, or -1 if there was no match. + + If \e len is not a null pointer, the length of the match is stored in + \e *len. + + If \e indexIsStart is TRUE (the default), the position \e index in + the string will match the start-of-input primitive (^) in the + regexp, if present. Otherwise, position 0 in \e str will match. + + Example: + \code + QRegExp r("[0-9]*\\.[0-9]+"); // matches floating point + int len; + r.match("pi = 3.1416", 0, &len); // returns 5, len == 6 + \endcode + + \note In Qt 3.0, this function will be replaced by find(). +*/ + +int QRegExp::match( const QString &str, int index, int *len, + bool indexIsStart ) const +{ + if ( !isValid() || isEmpty() ) + return -1; + if ( str.length() < (uint)index ) + return -1; + const QChar *start = str.unicode(); + const QChar *p = start + index; + uint pl = str.length() - index; + uint *d = rxdata; + int ep = -1; + + if ( *d == BOL ) { // match from beginning of line + ep = matchstring( d, p, pl, indexIsStart ? p : start, cs ); + } else { + if ( *d & CHR ) { + QChar c( *d ); + if ( !cs && !c.row() ) { // case sensitive, # only 8bit + while ( pl && ( p->row() || tolower(p->cell()) != c.cell() ) ) { + p++; + pl--; + } + } else { // case insensitive + while ( pl && *p != c ) { + p++; + pl--; + } + } + } + while( 1 ) { // regular match + ep = matchstring( d, p, pl, indexIsStart ? start+index : start, cs ); + if ( ep >= 0 ) + break; + if ( !pl ) + break; + p++; + pl--; + } + } + if ( len ) + *len = ep >= 0 ? ep : 0; // No match -> 0, for historical reasons + return ep >= 0 ? (int)(p - start) : -1; // return index; +} + +/*! \fn int QRegExp::find( const QString& str, int index ) + + Attempts to match in \e str, starting from position \e index. + Returns the position of the match, or -1 if there was no match. + + \sa match() +*/ + +// +// Translate wildcard pattern to standard regexp pattern. +// Ex: *.cpp ==> ^.*\.cpp$ +// + +static QString wc2rx( const QString &pattern ) +{ + int patlen = (int)pattern.length(); + QString wcpattern = QString::fromLatin1("^"); + + QChar c; + for( int i = 0; i < patlen; i++ ) { + c = pattern[i]; + switch ( (char)c ) { + case '*': // '*' ==> '.*' + wcpattern += '.'; + break; + case '?': // '?' ==> '.' + c = '.'; + break; + case '.': // quote special regexp chars + case '+': + case '\\': + case '$': + case '^': + wcpattern += '\\'; + break; + case '[': + if ( (char)pattern[i+1] == '^' ) { // don't quote '^' after '[' + wcpattern += '['; + c = pattern[i+1]; + i++; + } + break; + } + wcpattern += c; + + } + wcpattern += '$'; + return wcpattern; // return new regexp pattern +} + + +// +// Internal: Get char value and increment pointer. +// + +static uint char_val( const QChar **str, uint *strlength ) // get char value +{ + const QChar *p = *str; + uint pl = *strlength; + uint len = 1; + uint v = 0; + if ( (char)*p == '\\' ) { // escaped code + p++; + pl--; + if ( !pl ) { // it is just a '\' + (*str)++; + (*strlength)--; + return '\\'; + } + len++; // length at least 2 + int i; + char c; + char ch = tolower((char)*p); + switch ( ch ) { + case 'b': v = '\b'; break; // bell + case 'f': v = '\f'; break; // form feed + case 'n': v = '\n'; break; // newline + case 'r': v = '\r'; break; // return + case 't': v = '\t'; break; // tab + case 's': v = PWS; break; // whitespace charclass + case 'd': v = PDG; break; // digit charclass + case '<': v = BOW; break; // word beginning matcher + case '>': v = EOW; break; // word ending matcher + + case 'x': { // hex code + p++; + pl--; + for ( i = 0; (i < 4) && pl; i++ ) { //up to 4 hex digits + c = tolower((char)*p); + bool a = ( c >= 'a' && c <= 'f' ); + if ( (c >= '0' && c <= '9') || a ) { + v <<= 4; + v += a ? 10 + c - 'a' : c - '0'; + len++; + } + else { + break; + } + p++; + pl--; + } + } + break; + + default: { + if ( ch >= '0' && ch <= '7' ) { //octal code + len--; + for ( i = 0; (i < 3) && pl; i++ ) { // up to 3 oct digits + c = (char)*p; + if ( c >= '0' && c <= '7' ) { + v <<= 3; + v += c - '0'; + len++; + } + else { + break; + } + p++; + pl--; + } + } + else { // not an octal number + v = (((uint)(p->row())) << 8) | ((uint)p->cell()); + } + } + } + } else { + v = (((uint)(p->row())) << 8) | ((uint)p->cell()); + } + *str += len; + *strlength -= len; + return v; +} + + +#if defined(DEBUG) +static uint *dump( uint *p ) +{ + while ( *p != END ) { + if ( *p & CHR ) { + QChar uc = (QChar)*p; + char c = (char)uc; + uint u = (((uint)(uc.row())) << 8) | ((uint)uc.cell()); + qDebug( "\tCHR\tU%04x (%c)", u, (c ? c : ' ')); + p++; + } + else if ( *p & MCC ) { + uint clcode = *p & MCD; + uint numFields = *p & MVL; + if ( clcode == CCL ) + qDebug( "\tCCL\t%i", numFields ); + else if ( clcode == CCN ) + qDebug( "\tCCN\t%i", numFields ); + else + qDebug("coding error!"); + for ( int i = 0; i < (int)numFields; i++ ) { + p++; + if ( *p == PWS ) + qDebug( "\t\tPWS" ); + else if ( *p == PDG ) + qDebug( "\t\tPDG" ); + else { + uint from = ( *p & MCD ) >> 16; + uint to = *p & MVL; + char fc = (char)QChar(from); + char tc = (char)QChar(to); + qDebug( "\t\tU%04x (%c) - U%04x (%c)", from, + (fc ? fc : ' '), to, (tc ? tc : ' ') ); + } + } + p++; + } + else switch ( *p++ ) { + case PWS: + qDebug( "\tPWS" ); + break; + case PDG: + qDebug( "\tPDG" ); + break; + case BOL: + qDebug( "\tBOL" ); + break; + case EOL: + qDebug( "\tEOL" ); + break; + case BOW: + qDebug( "\tBOW" ); + break; + case EOW: + qDebug( "\tEOW" ); + break; + case ANY: + qDebug( "\tANY" ); + break; + case CLO: + qDebug( "\tCLO" ); + p = dump( p ); + break; + case OPT: + qDebug( "\tOPT" ); + p = dump( p ); + break; + } + } + qDebug( "\tEND" ); + return p+1; +} +#endif // DEBUG + + +static const int maxlen = 1024; // max length of regexp array +static uint rxarray[ maxlen ]; // tmp regexp array + +/*! + \internal + Compiles the regular expression and stores the result in rxdata. + The 'error' flag is set to non-zero if an error is detected. + NOTE! This function is not reentrant! +*/ + +void QRegExp::compile() +{ + if ( rxdata ) { // delete old data + delete [] rxdata; + rxdata = 0; + } + if ( rxstring.isEmpty() ) { // no regexp pattern set + error = PatNull; + return; + } + + error = PatOk; // assume pattern is ok + + QString pattern; + if ( wc ) + pattern = wc2rx(rxstring); + else + pattern = rxstring; + const QChar *start = pattern.unicode(); // pattern pointer + const QChar *p = start; // pattern pointer + uint pl = pattern.length(); + uint *d = rxarray; // data pointer + uint *prev_d = 0; + +#define GEN(x) *d++ = (x) + + while ( pl ) { + char ch = (char)*p; + switch ( ch ) { + + case '^': // beginning of line + prev_d = d; + GEN( p == start ? BOL : (CHR | ch) ); + p++; + pl--; + break; + + case '$': // end of line + prev_d = d; + GEN( pl == 1 ? EOL : (CHR | ch) ); + p++; + pl--; + break; + + case '.': // any char + prev_d = d; + GEN( ANY ); + p++; + pl--; + break; + + case '[': // character class + { + prev_d = d; + p++; + pl--; + if ( !pl ) { + error = PatSyntax; + return; + } + bool firstIsEscaped = ( (char)*p == '\\' ); + uint cch = char_val( &p, &pl ); + if ( cch == '^' && !firstIsEscaped ) { // negate! + GEN( CCN ); + if ( !pl ) { + error = PatSyntax; + return; + } + cch = char_val( &p, &pl ); + } else { + GEN( CCL ); + } + uint numFields = 0; + while ( pl ) { + if ((pl>2) && ((char)*p == '-') && ((char)*(p+1) != ']')) { + // Found a range + char_val( &p, &pl ); // Read the '-' + uint cch2 = char_val( &p, &pl ); // Read the range end + if ( cch > cch2 ) { // swap start and stop + int tmp = cch; + cch = cch2; + cch2 = tmp; + } + GEN( (cch << 16) | cch2 ); // from < to + numFields++; + } + else { + // Found a single character + if ( cch & MCD ) // It's a code; will not be mistaken + GEN( cch ); // for a range, since from > to + else + GEN( (cch << 16) | cch ); // from == to range + numFields++; + } + if ( d >= rxarray + maxlen ) { // pattern too long + error = PatOverflow; + return; + } + if ( !pl ) { // At least ']' should be left + error = PatSyntax; + return; + } + bool nextIsEscaped = ( (char)*p == '\\' ); + cch = char_val( &p, &pl ); + if ( cch == (uint)']' && !nextIsEscaped ) + break; + if ( !pl ) { // End, should have seen ']' + error = PatSyntax; + return; + } + } + *prev_d |= numFields; // Store number of fields + } + break; + + case '*': // Kleene closure, or + case '+': // positive closure, or + case '?': // optional closure + { + if ( prev_d == 0 ) { // no previous expression + error = PatSyntax; // empty closure + return; + } + switch ( *prev_d ) { // test if invalid closure + case BOL: + case BOW: + case EOW: + case CLO: + case OPT: + error = PatSyntax; + return; + } + int ddiff = d - prev_d; + if ( *p == '+' ) { // convert to Kleene closure + if ( d + ddiff >= rxarray + maxlen ) { + error = PatOverflow; // pattern too long + return; + } + memcpy( d, prev_d, ddiff*sizeof(uint) ); + d += ddiff; + prev_d += ddiff; + } + memmove( prev_d+1, prev_d, ddiff*sizeof(uint) ); + *prev_d = ch == '?' ? OPT : CLO; + d++; + GEN( END ); + p++; + pl--; + } + break; + + default: + { + prev_d = d; + uint cv = char_val( &p, &pl ); + if ( cv & MCD ) { // It's a code + GEN( cv ); + } + else { + if ( !cs && cv <= 0xff ) // #only 8bit support + cv = tolower( cv ); + GEN( CHR | cv ); + } + } + } + if ( d >= rxarray + maxlen ) { // oops! + error = PatOverflow; // pattern too long + return; + } + } + GEN( END ); + int len = d - rxarray; + rxdata = new uint[ len ]; // copy from rxarray to rxdata + CHECK_PTR( rxdata ); + memcpy( rxdata, rxarray, len*sizeof(uint) ); +#if defined(DEBUG) + //dump( rxdata ); // uncomment this line for debugging +#endif +} diff --git a/trunk/qtools/qregexp.h b/trunk/qtools/qregexp.h new file mode 100644 index 0000000..25868ce --- /dev/null +++ b/trunk/qtools/qregexp.h @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** +** Definition of QRegExp class +** +** Created : 950126 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QREGEXP_H +#define QREGEXP_H + +#ifndef QT_H +#include "qstring.h" +#endif // QT_H + + +class Q_EXPORT QRegExp +{ +public: + QRegExp(); + QRegExp( const QString &, bool caseSensitive=TRUE, bool wildcard=FALSE ); + QRegExp( const QRegExp & ); + ~QRegExp(); + QRegExp &operator=( const QRegExp & ); + QRegExp &operator=( const QString &pattern ); + + bool operator==( const QRegExp & ) const; + bool operator!=( const QRegExp &r ) const + { return !(this->operator==(r)); } + + bool isEmpty() const { return rxdata == 0; } + bool isValid() const { return error == 0; } + + bool caseSensitive() const { return cs; } + void setCaseSensitive( bool ); + + bool wildcard() const { return wc; } + void setWildcard( bool ); + + QString pattern() const { return rxstring; } + // ### in Qt 3.0, provide a real implementation + void setPattern( const QString& pattern ) + { operator=( pattern ); } + + int match( const QString &str, int index=0, int *len=0, + bool indexIsStart = TRUE ) const; + int find( const QString& str, int index ) + { return match( str, index ); } + +protected: + void compile(); + const QChar *matchstr( uint *, const QChar *, uint, const QChar * ) const; + +private: + QString rxstring; // regular expression pattern + uint *rxdata; // compiled regexp pattern + int error; // error status + bool cs; // case sensitive + bool wc; // wildcard +}; + + +#endif // QREGEXP_H diff --git a/trunk/qtools/qshared.h b/trunk/qtools/qshared.h new file mode 100644 index 0000000..79fab7b --- /dev/null +++ b/trunk/qtools/qshared.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** +** Definition of QShared struct +** +** Created : 940112 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSHARED_H +#define QSHARED_H + +#ifndef QT_H +#include "qglobal.h" +#endif // QT_H + + +struct QShared +{ + QShared() { count = 1; } + void ref() { count++; } + bool deref() { return !--count; } + uint count; +}; + + +#endif // QSHARED_H diff --git a/trunk/qtools/qsortedlist.doc b/trunk/qtools/qsortedlist.doc new file mode 100644 index 0000000..6f16f19 --- /dev/null +++ b/trunk/qtools/qsortedlist.doc @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** +** QSortedList documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QSortedList documentation + *****************************************************************************/ + +/*! + \class QSortedList qsortedlist.h + \brief The QSortedList class provides a list sorted by operator< and operator== + + \ingroup collection + \ingroup tools + + If you want to sort a QList you have to reimplement the + QGList::compareItems() method. If the elements of your list support + operator<() and operator==() then you can use QSortedList instead. + Its compareItems() calls operator<() and operator==() and returns an + appropriate result. + + Otherwise, this is as QList. + + \sa QList, \link collection.html Collection Classes\endlink +*/ + + +/*! + \fn QSortedList::QSortedList() + Constructs an empty list. +*/ + +/*! + \fn QSortedList::QSortedList( const QSortedList<type> &list ) + Constructs a copy of \e list. + + Each item in \e list is copied to this new list. +*/ + +/*! + \fn QSortedList::~QSortedList() + Removes all items from the list and destroys the list. + + All list iterators that access this list will be reset. +*/ + +/*! + \fn QSortedList<type>& QSortedList::operator=(const QSortedList<type>& list) + Assigns \e list to this list and returns a reference to this list. + + This list is first cleared, then each item in \e list is + appended to this list. Only the pointers are copied + (shallow copy), unless newItem() has been reimplemented(). +*/ + +/*! + \fn int QSortedList::compareItems( QCollection::Item s1, QCollection::Item s2 ) + + \reimp + + This reimplementation uses operator< and operator== to compare. +*/ diff --git a/trunk/qtools/qsortedlist.h b/trunk/qtools/qsortedlist.h new file mode 100644 index 0000000..aeadd90 --- /dev/null +++ b/trunk/qtools/qsortedlist.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** +** Definition of QList template/macro class +** +** Created : 920701 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSORTEDLIST_H +#define QSORTEDLIST_H + +#ifndef QT_H +#include "qlist.h" +#endif // QT_H + + +template<class type> class Q_EXPORT QSortedList : public QList<type> +{ +public: + QSortedList() {} + QSortedList( const QSortedList<type> &l ) : QList<type>(l) {} + ~QSortedList() { clear(); } + QSortedList<type> &operator=(const QSortedList<type> &l) + { return (QSortedList<type>&)QList<type>::operator=(l); } + + virtual int compareItems( QCollection::Item s1, QCollection::Item s2 ) + { if ( *((type*)s1) == *((type*)s2) ) return 0; return ( *((type*)s1) < *((type*)s2) ? -1 : 1 ); } +}; + +#endif diff --git a/trunk/qtools/qstack.doc b/trunk/qtools/qstack.doc new file mode 100644 index 0000000..ece1e2a --- /dev/null +++ b/trunk/qtools/qstack.doc @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** +** QStack class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QStack documentation + *****************************************************************************/ + +/*! + \class QStack qstack.h + \brief The QStack class is a template class that provides a stack. + + \ingroup collection + \ingroup tools + + QStack is implemented as a template class. Define a template + instance QStack\<X\> to create a stack that operates on pointers to + X, or X*. + + A stack is a Last In, First Out (LIFO) structure. Items are added to + the top of the stack with push() and retrieved from the top + with pop(). + + \sa \link collection.html Collection Classes\endlink +*/ + +/*! \fn QStack::QStack () + Creates and empty stack. +*/ + +/*! \fn QStack::QStack (const QStack<type>& s) + Creates a stack by making a shallow copy of another stack. +*/ + +/*! \fn QStack::~QStack () + Destroys the stack. All items will be deleted if autoDelete() is TRUE. +*/ + +/*! \fn QStack<type>& QStack::operator= (const QStack<type>& s) + Sets the contents of this stack by making a shallow copy of another stack. + Elements currently in this stack will be deleted if autoDelete() is TRUE. +*/ + +/*! \fn bool QStack::isEmpty () const + Returns TRUE is the stack contains no elements to be \link pop() popped\endlink. +*/ + +/*! \fn void QStack::push (const type* d) + Adds an element to the top of the stack. Last in, first out. +*/ + +/*! \fn type* QStack::pop () + Removes the top item from the stack and returns it. +*/ + +/*! \fn bool QStack::remove () + Removes the top item from the stack and deletes it if + autoDelete() is TRUE. Returns TRUE if there was an item to pop. + + \sa clear() +*/ + +/*! \fn void QStack::clear() + Removes all items from the stack, deleting them if + autoDelete() is TRUE. + + \sa remove() +*/ + +/*! \fn uint QStack::count() const + Returns the number of items in the stack. + + \sa isEmpty() +*/ + +/*! \fn type* QStack::top () const + Returns a reference to the top item on the stack (most recently pushed). + The stack is not changed. +*/ + +/*! \fn QStack::operator type* ()const + Returns a reference to the top item on the stack (most recently pushed). + The stack is not changed. +*/ + +/*! \fn type* QStack::current () const + Returns a reference to the top item on the stack (most recently pushed). + The stack is not changed. +*/ + +/*! \fn bool QStack::autoDelete() const + + The same as QCollection::autoDelete(). + + \sa setAutoDelete() +*/ + +/*! \fn void QStack::setAutoDelete( bool enable ) + + The same as QCollection::setAutoDelete(). + + \sa autoDelete() +*/ diff --git a/trunk/qtools/qstack.h b/trunk/qtools/qstack.h new file mode 100644 index 0000000..c84d8d2 --- /dev/null +++ b/trunk/qtools/qstack.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** +** Definition of QStack template/macro class +** +** Created : 920917 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSTACK_H +#define QSTACK_H + +#ifndef QT_H +#include "qglist.h" +#endif // QT_H + + +template<class type> class QStack : private QGList +{ +public: + QStack() {} + QStack( const QStack<type> &s ) : QGList(s) {} + ~QStack() { clear(); } + QStack<type> &operator=(const QStack<type> &s) + { return (QStack<type>&)QGList::operator=(s); } + bool autoDelete() const { return QCollection::autoDelete(); } + void setAutoDelete( bool del ) { QCollection::setAutoDelete(del); } + uint count() const { return QGList::count(); } + bool isEmpty() const { return QGList::count() == 0; } + void push( const type *d ) { QGList::insertAt(0,Item(d)); } + type *pop() { return (type *)QGList::takeFirst(); } + bool remove() { return QGList::removeFirst(); } + void clear() { QGList::clear(); } + type *bottom() const { return (type *)QGList::clast(); } + type *top() const { return (type *)QGList::cfirst(); } + operator type *() const { return (type *)QGList::cfirst(); } + type *current() const { return (type *)QGList::cfirst(); } +private: + void deleteItem( Item d ) { if ( del_item ) delete (type *)d; } +}; + + +#endif // QSTACK_H diff --git a/trunk/qtools/qstring.cpp b/trunk/qtools/qstring.cpp new file mode 100644 index 0000000..e073168 --- /dev/null +++ b/trunk/qtools/qstring.cpp @@ -0,0 +1,15222 @@ +/**************************************************************************** +** +** +** Implementation of the QString class and related Unicode functions +** +** Created : 920722 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +// Don't define it while compiling this module, or USERS of Qt will +// not be able to link. +#ifdef QT_NO_CAST_ASCII +#undef QT_NO_CAST_ASCII +#endif + +#include "qstring.h" +#include "qregexp.h" +#include "qdatastream.h" +#include "qtextcodec.h" +#include "qstack.h" +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <ctype.h> +#include <limits.h> + + +/* ------------------------------------------------------------------------- + * unicode information + * these tables are generated from the unicode reference file + * ftp://ftp.unicode.org/Public/3.0-Update/UnicodeData-3.0.0.html + * + * Lars Knoll <knoll@mpi-hd.mpg.de> + * ------------------------------------------------------------------------- + */ + +/* Perl script to generate (run perl -x tools/qstring.cpp) + +#!perl + +sub numberize +{ + my(%r, $n, $id); + for $id ( @_ ) { + $id="" if $id eq "EMPTY"; + $r{$id}=$n++; + } + return %r; +} + + +# Code to integer mappings... +# +%category_code = numberize(qw{ + EMPTY + Mn Mc Me + Nd Nl No + Zs Zl Zp + Cc Cf Cs Co Cn + + Lu Ll Lt Lm Lo + Pc Pd Ps Pe Pi Pf Po + Sm Sc Sk So +}); +%bidi_category_code = numberize(qw{ + L R EN ES ET AN CS B S WS ON LRE LRO AL RLE RLO PDF NSM BN}); +%character_decomposition_tag = numberize(qw{ + <single> <canonical> <font> <noBreak> <initial> <medial> + <final> <isolated> <circle> <super> <sub> <vertical> + <wide> <narrow> <small> <square> <compat> <fraction> +}); +%mirrored_code = numberize(qw{N Y}); + +%joining_code = numberize(qw{U D R C}); + +# Read data into hashes... +# +open IN, "UnicodeData.txt"; +$position = 1; +while (<IN>) { + @fields = split /;/; + $code = shift @fields; + for $n (qw{ + name category combining_class bidi_category + character_decomposition decimal_digit_value digit_value + numeric_value mirrored oldname comment + uppercase lowercase titlecase}) + { + $id = shift @fields; + $codes = "${n}_code"; + if ( defined %$codes && defined $$codes{$id} ) { + $id = $$codes{$id}; + } + ${$n}{$code}=$id; + } + $decomp = $character_decomposition{$code}; + if ( length $decomp == 0 ) { + $decomp = "<single>"; + } + if (substr($decomp, 0, 1) ne '<') { + $decomp = "<canonical> " . $decomp; + } + @fields = split(" ", $decomp); + $tag = shift @fields; + $tag = $character_decomposition_tag{$tag}; + $decomp = join( ", 0x", @fields ); + $decomp = "0x".$decomp; + $decomposition{$code} = $decomp; + $decomposition_tag{$code} = $tag; + $decomposition_pos{$code} = $position; + $len = scalar(@fields); + $decomposition_len{$code} = $len; + +# we use canonical decompositions longer than 1 char +# and all arabic ligatures for the ligature table + if(($len > 1 and $tag == 1) or ($tag > 3 and $tag < 8)) { +# ligature to add... + $start = shift @fields; + $ligature{$start} = $ligature{$start}." ".$code; + } + +# adjust position + if($len != 0) { + $position += $len + 3; + } + + +} + +open IN2, "ArabicShaping.txt"; +$position = 1; +while (<IN2>) { + @fields = split /;/; + $code = shift @fields; + $dummy = shift @fields; + $join = shift @fields; + $join =~ s/ //g; + $join = $joining_code{$join}; + $joining{$code}=$join; +} + +# Build pages... +# +$rowtable_txt = + "static const Q_UINT8 * const unicode_info[256] = {"; +for $row ( 0..255 ) { + $nonzero=0; + $txt = ""; + for $cell ( 0..255 ) { + $code = sprintf("%02X%02X",$row,$cell); + $info = $category{$code}; + $info = 0 if !defined $info; + $txt .= "\n " if $cell%8 == 0; + $txt .= "$info, "; + } + $therow = $row{$txt}; + if ( !defined $therow ) { + $size+=256; + $therow = "ui_".sprintf("%02X",$row); + $rowtext{$therow} = + "static const Q_UINT8 ${therow}[] = {$txt\n};\n\n"; + $row{$txt}=$therow; + } + $rowtable_txt .= "\n " if $row%8 == 0; + $rowtable_txt .= "$therow, "; +} + +print "// START OF GENERATED DATA\n\n"; +print "#ifndef QT_NO_UNICODETABLES\n\n"; + +# Print pages... +# +for $r ( sort keys %rowtext ) { + print $rowtext{$r}; +} +print "$rowtable_txt\n};\n"; +$size += 256*4; +print "// $size bytes\n\n"; + +# Build decomposition tables +# +$rowtable_txt = + "static const Q_UINT16 * const decomposition_info[256] = {"; +$table_txt = + "static const Q_UINT16 decomposition_map[] = {\n 0,\n"; +for $row ( 0..255 ) { + $nonzero=0; + $txt = ""; + for $cell ( 0..255 ) { + $code = sprintf("%02X%02X",$row,$cell); + $txt .= "\n " if $cell%8 == 0; + if( $decomposition_tag{$code} != 0 ) { + $txt .= " $decomposition_pos{$code},"; + $table_txt .= " $decomposition_tag{$code},"; + $table_txt .= " 0x$code,"; + $table_txt .= " $decomposition{$code}, 0,\n"; + $size += 2 * $decomposition_len{$code} + 6; + } else { + $txt .= " 0,"; + } + } + $therow = $row{$txt}; + if ( !defined $therow ) { + $size+=512; + $therow = "di_".sprintf("%02X",$row); + $dec_rowtext{$therow} = + "static const Q_UINT16 ${therow}[] = {$txt\n};\n\n"; + $row{$txt}=$therow; + } + $rowtable_txt .= "\n " if $row%8 == 0; + $rowtable_txt .= "$therow, "; +} + +# Print decomposition tables +# +print "$table_txt\n};\n\n"; +for $r ( sort keys %dec_rowtext ) { + print $dec_rowtext{$r}; +} +print "$rowtable_txt\n};\n"; +$size += 256*4; +print "// $size bytes\n\n"; + + +# build ligature tables +# +$size = 0; +$position = 1; +$rowtable_txt = + "static const Q_UINT16 * const ligature_info[256] = {"; +$table_txt = + "static const Q_UINT16 ligature_map[] = {\n 0,\n"; +for $lig_row ( 0..255 ) { + $nonzero=0; + $txt = ""; + for $cell ( 0..255 ) { + $code = sprintf("%02X%02X",$lig_row,$cell); + $txt .= "\n " if $cell%8 == 0; + if( defined $ligature{$code} ) { + $txt .= " $position,"; + @ligature = split(" ", $ligature{$code}); +# we need to sort ligatures according to their length. +# long ones have to come first! + @ligature_sort = sort { $decomposition_len{$b} <=> $decomposition_len{$a} } @ligature; +# now replace each code by it's position in +# the decomposition map. + undef(@lig_pos); + for $n (@ligature_sort) { + push(@lig_pos, $decomposition_pos{$n}); + } +# debug info + if( 0 ) { + print "ligatures: $ligature{$code}\n"; + $sort = join(" ", @ligature_sort); + print "sorted : $sort\n"; + } + $lig = join(", ", @lig_pos); + $table_txt .= " $lig, 0,\n"; + $size += 2 * scalar(@ligature) + 2; + $position += scalar(@ligature) + 1; + } else { + $txt .= " 0,"; + } + } + $therow = $lig_row{$txt}; + if ( !defined $therow ) { + $size+=512; + $therow = "li_".sprintf("%02X",$lig_row); + $lig_rowtext{$therow} = + "static const Q_UINT16 ${therow}[] = {$txt\n};\n\n"; + $lig_row{$txt}=$therow; + } + $rowtable_txt .= "\n " if $lig_row%8 == 0; + $rowtable_txt .= "$therow, "; +} + +# Print ligature tables +# +print "$table_txt\n};\n\n"; +for $r ( sort keys %lig_rowtext ) { + print $lig_rowtext{$r}; +} +print "$rowtable_txt\n};\n"; +$size += 256*4; +print "// $size bytes\n\n"; + + + +# Build direction/joining/mirrored pages... +# +$rowtable_txt = + "static const Q_UINT8 * const direction_info[256] = {"; +for $dir_row ( 0..255 ) { + $nonzero=0; + $txt = ""; + for $cell ( 0..255 ) { + $code = sprintf("%02X%02X",$dir_row,$cell); + $dir = $bidi_category{$code}; + $dir = 0 if !defined $dir; + $join = $joining{$code}; + $join = 0 if !defined $join; + $mirr = $mirrored{$code}; + $mirr = 0 if !defined $mirr; + $info = $dir + 32*$join + 128*$mirr; + $txt .= "\n " if $cell%8 == 0; + $txt .= "$info, "; + } + $therow = $dir_row{$txt}; + if ( !defined $therow ) { + $size+=256; + $therow = "dir_".sprintf("%02X",$dir_row); + $dir_rowtext{$therow} = + "static const Q_UINT8 ${therow}[] = {$txt\n};\n\n"; + $dir_row{$txt}=$therow; + } + $rowtable_txt .= "\n " if $dir_row%8 == 0; + $rowtable_txt .= "$therow, "; +} + +# Print pages... +# +for $r ( sort keys %dir_rowtext ) { + print $dir_rowtext{$r}; +} +print "$rowtable_txt\n};\n"; +$size += 256*4; +print "// $size bytes\n\n"; + + + +print "#endif\n\n"; +print "// END OF GENERATED DATA\n\n"; + + +__END__ + +*/ + + +// START OF GENERATED DATA + +static const Q_UINT8 ui_00[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 7, 26, 26, 26, 28, 26, 26, 26, + 22, 23, 26, 27, 26, 21, 26, 26, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 26, 26, 27, 27, 27, 26, + 26, 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, 22, 26, 23, 29, 20, + 29, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 22, 27, 23, 27, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 7, 26, 28, 28, 28, 28, 30, 30, + 29, 30, 16, 24, 27, 21, 30, 29, + 30, 27, 6, 6, 29, 16, 30, 26, + 29, 6, 16, 25, 6, 6, 6, 26, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 27, + 15, 15, 15, 15, 15, 15, 15, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 27, + 16, 16, 16, 16, 16, 16, 16, 16, +}; + +#ifndef QT_NO_UNICODETABLES + +static const Q_UINT8 ui_01[] = { + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 16, 15, 16, 15, 16, 15, 16, 15, + 16, 15, 16, 15, 16, 15, 16, 15, + 16, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 15, 16, 15, 16, 15, 16, 16, + 16, 15, 15, 16, 15, 16, 15, 15, + 16, 15, 15, 15, 16, 16, 15, 15, + 15, 15, 16, 15, 15, 16, 15, 15, + 15, 16, 16, 16, 15, 15, 16, 15, + 15, 16, 15, 16, 15, 16, 15, 15, + 16, 15, 16, 16, 15, 16, 15, 15, + 16, 15, 15, 15, 16, 15, 16, 15, + 15, 16, 16, 19, 15, 16, 16, 16, + 19, 19, 19, 19, 15, 17, 16, 15, + 17, 16, 15, 17, 16, 15, 16, 15, + 16, 15, 16, 15, 16, 15, 16, 15, + 16, 15, 16, 15, 16, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 16, 15, 17, 16, 15, 16, 15, 15, + 15, 16, 15, 16, 15, 16, 15, 16, +}; + +static const Q_UINT8 ui_02[] = { + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 0, 0, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 0, 0, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 29, 29, 18, 18, 18, 18, 18, + 18, 18, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, + 18, 18, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, + 18, 18, 18, 18, 18, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 18, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_03[] = { + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 29, 29, 0, 0, + 0, 0, 18, 0, 0, 0, 26, 0, + 0, 0, 0, 0, 29, 29, 15, 26, + 15, 15, 15, 0, 15, 0, 15, 15, + 16, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 0, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 0, + 16, 16, 15, 15, 15, 16, 16, 16, + 0, 0, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 16, 16, 16, 16, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_04[] = { + 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, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 30, 1, 1, 1, 1, 0, + 3, 3, 0, 0, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 15, 16, 15, 16, 0, 0, 15, + 16, 0, 0, 15, 16, 0, 0, 0, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 0, 0, + 15, 16, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_05[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 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, 18, 26, 26, 26, 26, 26, 26, + 0, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 0, 26, 21, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 0, 1, 1, 1, 26, 1, + 26, 1, 1, 26, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 0, + 19, 19, 19, 26, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_06[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 26, 0, 0, 0, 26, + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 0, + 18, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 26, 26, 26, 26, 0, 0, + 1, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 26, 19, 1, 1, + 1, 1, 1, 1, 1, 3, 3, 1, + 1, 1, 1, 1, 1, 18, 18, 1, + 1, 30, 1, 1, 1, 1, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 19, 19, 19, 30, 30, 0, +}; + +static const Q_UINT8 ui_07[] = { + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 0, 11, + 19, 1, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_08[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_09[] = { + 0, 1, 1, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 0, 1, 19, 2, 2, + 2, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 1, 0, 0, + 19, 1, 1, 1, 1, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 1, 1, 26, 26, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 26, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 19, + 19, 0, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 0, 0, 0, 19, 19, + 19, 19, 0, 0, 1, 0, 2, 2, + 2, 1, 1, 1, 1, 0, 0, 2, + 2, 0, 0, 2, 2, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 19, 19, 0, 19, + 19, 19, 1, 1, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 19, 19, 28, 28, 6, 6, 6, 6, + 6, 6, 30, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_0A[] = { + 0, 0, 1, 0, 0, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 19, + 19, 0, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 0, 19, 19, 0, + 19, 19, 0, 0, 1, 0, 2, 2, + 2, 1, 1, 0, 0, 0, 0, 1, + 1, 0, 0, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 19, 19, 19, 19, 0, 19, 0, + 0, 0, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 1, 1, 19, 19, 19, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 0, 19, 0, 19, + 19, 19, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 0, 19, 19, 19, + 19, 19, 0, 0, 1, 19, 2, 2, + 2, 1, 1, 1, 1, 1, 0, 1, + 1, 2, 0, 2, 2, 1, 0, 0, + 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 0, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_0B[] = { + 0, 1, 2, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 19, + 19, 0, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 0, 0, 19, 19, + 19, 19, 0, 0, 1, 19, 2, 1, + 2, 1, 1, 1, 0, 0, 0, 2, + 2, 0, 0, 2, 2, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 2, + 0, 0, 0, 0, 19, 19, 0, 19, + 19, 19, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 30, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 2, 0, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 19, 19, + 19, 0, 19, 19, 19, 19, 0, 0, + 0, 19, 19, 0, 19, 0, 19, 19, + 0, 0, 0, 19, 19, 0, 0, 0, + 19, 19, 19, 0, 0, 0, 19, 19, + 19, 19, 19, 19, 19, 19, 0, 19, + 19, 19, 0, 0, 0, 0, 2, 2, + 1, 2, 2, 0, 0, 0, 2, 2, + 2, 0, 2, 2, 2, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 6, 6, 6, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_0C[] = { + 0, 2, 2, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 0, 19, 19, 19, + 19, 19, 0, 0, 0, 0, 1, 1, + 1, 2, 2, 2, 2, 0, 1, 1, + 1, 0, 1, 1, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 1, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 0, 19, 19, 19, + 19, 19, 0, 0, 0, 0, 2, 1, + 2, 2, 2, 2, 2, 0, 1, 2, + 2, 0, 2, 2, 1, 1, 0, 0, + 0, 0, 0, 0, 0, 2, 2, 0, + 0, 0, 0, 0, 0, 0, 19, 0, + 19, 19, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_0D[] = { + 0, 0, 2, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 0, 0, 0, 2, 2, + 2, 1, 1, 1, 0, 0, 2, 2, + 2, 0, 2, 2, 2, 1, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 0, 0, 0, 0, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 0, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 1, 0, 0, 0, 0, 2, + 2, 2, 1, 1, 1, 0, 1, 0, + 2, 2, 2, 2, 2, 2, 2, 2, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 2, 26, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_0E[] = { + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 1, 19, 19, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 28, + 19, 19, 19, 19, 19, 19, 18, 1, + 1, 1, 1, 1, 1, 1, 1, 26, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 26, 26, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 19, 19, 0, 19, 0, 0, 19, + 19, 0, 19, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 19, 19, 19, 19, + 0, 19, 19, 19, 19, 19, 19, 19, + 0, 19, 19, 19, 0, 19, 0, 19, + 0, 0, 19, 19, 0, 19, 19, 19, + 19, 1, 19, 19, 1, 1, 1, 1, + 1, 1, 0, 1, 1, 19, 0, 0, + 19, 19, 19, 19, 19, 0, 18, 0, + 1, 1, 1, 1, 1, 1, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 0, 0, 19, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_0F[] = { + 19, 30, 30, 30, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 30, 30, 30, 30, 30, + 1, 1, 30, 30, 30, 30, 30, 30, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 30, 1, 30, 1, + 30, 1, 22, 23, 22, 23, 2, 2, + 19, 19, 19, 19, 19, 19, 19, 19, + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 1, 1, 1, 26, 1, 1, + 19, 19, 19, 19, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 30, 30, + 30, 30, 30, 30, 30, 30, 1, 30, + 30, 30, 30, 30, 30, 0, 0, 30, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_10[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 19, 19, 19, 19, 19, + 0, 19, 19, 0, 2, 1, 1, 1, + 1, 2, 1, 0, 0, 0, 1, 1, + 2, 1, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 26, 26, 26, 26, 26, 26, + 19, 19, 19, 19, 19, 19, 2, 2, + 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 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, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 0, 26, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_11[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 0, 0, 0, 0, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_12[] = { + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 0, 19, 19, 19, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 0, 19, 19, 19, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 0, 19, 19, 19, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 0, 19, 19, 19, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 0, 19, 19, 19, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, +}; + +static const Q_UINT8 ui_13[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 0, 19, 19, 19, 19, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 0, 0, 0, 0, 0, + 0, 26, 26, 26, 26, 26, 26, 26, + 26, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_14[] = { + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, +}; + +static const Q_UINT8 ui_15[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, +}; + +static const Q_UINT8 ui_16[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 26, 26, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 7, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 22, 23, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 26, 26, 26, 6, 6, + 6, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_17[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 2, 2, 2, 1, + 1, 1, 1, 1, 1, 1, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, + 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 26, 26, 26, 26, + 26, 26, 26, 28, 26, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_18[] = { + 26, 26, 26, 26, 26, 26, 21, 26, + 26, 26, 26, 11, 11, 11, 11, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 18, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_1E[] = { + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 16, 16, + 16, 16, 16, 16, 0, 0, 0, 0, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 15, 16, 15, 16, 15, 16, + 15, 16, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_1F[] = { + 16, 16, 16, 16, 16, 16, 16, 16, + 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 0, 0, + 15, 15, 15, 15, 15, 15, 0, 0, + 16, 16, 16, 16, 16, 16, 16, 16, + 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, + 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 0, 0, + 15, 15, 15, 15, 15, 15, 0, 0, + 16, 16, 16, 16, 16, 16, 16, 16, + 0, 15, 0, 15, 0, 15, 0, 15, + 16, 16, 16, 16, 16, 16, 16, 16, + 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 0, 0, + 16, 16, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 17, 17, + 16, 16, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 17, 17, + 16, 16, 16, 16, 16, 16, 16, 16, + 17, 17, 17, 17, 17, 17, 17, 17, + 16, 16, 16, 16, 16, 0, 16, 16, + 15, 15, 15, 15, 17, 29, 16, 29, + 29, 29, 16, 16, 16, 0, 16, 16, + 15, 15, 15, 15, 17, 29, 29, 29, + 16, 16, 16, 16, 0, 0, 16, 16, + 15, 15, 15, 15, 0, 29, 29, 29, + 16, 16, 16, 16, 16, 16, 16, 16, + 15, 15, 15, 15, 15, 29, 29, 29, + 0, 0, 16, 16, 16, 0, 16, 16, + 15, 15, 15, 15, 17, 29, 29, 0, +}; + +static const Q_UINT8 ui_20[] = { + 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 11, 11, 11, 11, + 21, 21, 21, 21, 21, 21, 26, 26, + 24, 25, 22, 24, 24, 25, 22, 24, + 26, 26, 26, 26, 26, 26, 26, 26, + 8, 9, 11, 11, 11, 11, 11, 7, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 24, 25, 26, 26, 26, 26, 20, + 20, 26, 26, 26, 27, 22, 23, 0, + 26, 26, 26, 26, 26, 26, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 11, 11, 11, 11, 11, 11, + 6, 0, 0, 0, 6, 6, 6, 6, + 6, 6, 27, 27, 27, 22, 23, 16, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 27, 27, 27, 22, 23, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 3, 3, + 3, 1, 3, 3, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_21[] = { + 30, 30, 15, 30, 30, 30, 30, 15, + 30, 30, 16, 15, 15, 15, 16, 16, + 15, 15, 15, 16, 30, 15, 30, 30, + 30, 15, 15, 15, 15, 15, 30, 30, + 30, 30, 30, 30, 15, 30, 15, 30, + 15, 30, 15, 15, 15, 15, 30, 16, + 15, 15, 30, 15, 16, 19, 19, 19, + 19, 16, 30, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 27, 27, 27, 27, 27, 30, 30, 30, + 30, 30, 27, 27, 30, 30, 30, 30, + 27, 30, 30, 27, 30, 30, 27, 30, + 30, 30, 30, 30, 30, 30, 27, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 27, 27, + 30, 30, 27, 30, 27, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_22[] = { + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_23[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 27, 27, 27, 27, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 27, 27, 30, 30, 30, 30, 30, 30, + 30, 22, 23, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_24[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 6, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_25[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 27, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 27, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_26[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 0, + 0, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 27, + 30, 30, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_27[] = { + 0, 30, 30, 30, 30, 0, 30, 30, + 30, 30, 0, 0, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 0, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 30, 0, 30, + 30, 30, 30, 0, 0, 0, 30, 0, + 30, 30, 30, 30, 30, 30, 30, 0, + 0, 30, 30, 30, 30, 30, 30, 30, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 30, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 0, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_28[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, +}; + +static const Q_UINT8 ui_2E[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 0, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_2F[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_30[] = { + 7, 26, 26, 26, 30, 18, 19, 5, + 22, 23, 22, 23, 22, 23, 22, 23, + 22, 23, 30, 30, 22, 23, 22, 23, + 22, 23, 22, 23, 21, 22, 23, 23, + 30, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 1, 1, 1, 1, 1, 1, + 21, 18, 18, 18, 18, 18, 30, 30, + 5, 5, 5, 0, 0, 0, 30, 30, + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 0, + 0, 1, 1, 29, 29, 18, 18, 0, + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 20, 18, 18, 18, 0, +}; + +static const Q_UINT8 ui_31[] = { + 0, 0, 0, 0, 0, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 0, + 0, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 30, 30, 6, 6, 6, 6, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_32[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 0, 0, 0, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 30, + 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 0, +}; + +static const Q_UINT8 ui_33[] = { + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 0, + 0, 0, 0, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 0, +}; + +static const Q_UINT8 ui_34[] = { + 19, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_4D[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_9F[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_A4[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 0, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 0, 0, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 0, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, + 30, 0, 30, 30, 30, 0, 30, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_D7[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 19, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_D8[] = { + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_DB[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 12, + 12, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 12, +}; + +static const Q_UINT8 ui_DF[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 12, +}; + +static const Q_UINT8 ui_E0[] = { + 13, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_F8[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 13, +}; + +static const Q_UINT8 ui_FA[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_FB[] = { + 16, 16, 16, 16, 16, 16, 16, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 16, 16, 16, 16, 16, + 0, 0, 0, 0, 0, 19, 1, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 27, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 19, 19, 19, 19, 19, 0, 19, 0, + 19, 19, 0, 19, 19, 0, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, +}; + +static const Q_UINT8 ui_FD[] = { + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 22, 23, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 0, 0, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 0, 0, 0, 0, +}; + +static const Q_UINT8 ui_FE[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 26, 21, 21, 20, 20, 22, 23, 22, + 23, 22, 23, 22, 23, 22, 23, 22, + 23, 22, 23, 22, 23, 0, 0, 0, + 0, 26, 26, 26, 26, 20, 20, 20, + 26, 26, 26, 0, 26, 26, 26, 26, + 21, 22, 23, 22, 23, 22, 23, 26, + 26, 26, 27, 21, 27, 27, 27, 0, + 26, 28, 26, 26, 0, 0, 0, 0, + 19, 19, 19, 0, 19, 0, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 0, 0, 11, +}; + +static const Q_UINT8 ui_FF[] = { + 0, 26, 26, 26, 28, 26, 26, 26, + 22, 23, 26, 27, 26, 21, 26, 26, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 26, 26, 27, 27, 27, 26, + 26, 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, 22, 26, 23, 29, 20, + 29, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 22, 27, 23, 27, 0, + 0, 26, 22, 23, 26, 20, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 18, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 18, 18, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 19, 0, + 0, 0, 19, 19, 19, 19, 19, 19, + 0, 0, 19, 19, 19, 19, 19, 19, + 0, 0, 19, 19, 19, 19, 19, 19, + 0, 0, 19, 19, 19, 0, 0, 0, + 28, 28, 27, 29, 30, 28, 28, 0, + 30, 27, 27, 27, 27, 30, 30, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 11, 11, 11, 30, 30, 0, 0, +}; + +static const Q_UINT8 * const unicode_info[256] = { + ui_00, ui_01, ui_02, ui_03, ui_04, ui_05, ui_06, ui_07, + ui_08, ui_09, ui_0A, ui_0B, ui_0C, ui_0D, ui_0E, ui_0F, + ui_10, ui_11, ui_12, ui_13, ui_14, ui_15, ui_16, ui_17, + ui_18, ui_08, ui_08, ui_08, ui_08, ui_08, ui_1E, ui_1F, + ui_20, ui_21, ui_22, ui_23, ui_24, ui_25, ui_26, ui_27, + ui_28, ui_08, ui_08, ui_08, ui_08, ui_08, ui_2E, ui_2F, + ui_30, ui_31, ui_32, ui_33, ui_34, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_4D, ui_34, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_9F, + ui_15, ui_15, ui_15, ui_15, ui_A4, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_34, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_D7, + ui_D8, ui_08, ui_08, ui_DB, ui_D8, ui_08, ui_08, ui_DF, + ui_E0, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, ui_08, + ui_F8, ui_15, ui_FA, ui_FB, ui_15, ui_FD, ui_FE, ui_FF, +}; +// 15616 bytes + +static const Q_UINT16 decomposition_map [] = { + 0, + 3, 0x00A0, 0x0020, 0, + 16, 0x00A8, 0x0020, 0x0308, 0, + 9, 0x00AA, 0x0061, 0, + 16, 0x00AF, 0x0020, 0x0304, 0, + 9, 0x00B2, 0x0032, 0, + 9, 0x00B3, 0x0033, 0, + 16, 0x00B4, 0x0020, 0x0301, 0, + 16, 0x00B5, 0x03BC, 0, + 16, 0x00B8, 0x0020, 0x0327, 0, + 9, 0x00B9, 0x0031, 0, + 9, 0x00BA, 0x006F, 0, + 17, 0x00BC, 0x0031, 0x2044, 0x0034, 0, + 17, 0x00BD, 0x0031, 0x2044, 0x0032, 0, + 17, 0x00BE, 0x0033, 0x2044, 0x0034, 0, + 1, 0x00C0, 0x0041, 0x0300, 0, + 1, 0x00C1, 0x0041, 0x0301, 0, + 1, 0x00C2, 0x0041, 0x0302, 0, + 1, 0x00C3, 0x0041, 0x0303, 0, + 1, 0x00C4, 0x0041, 0x0308, 0, + 1, 0x00C5, 0x0041, 0x030A, 0, + 1, 0x00C7, 0x0043, 0x0327, 0, + 1, 0x00C8, 0x0045, 0x0300, 0, + 1, 0x00C9, 0x0045, 0x0301, 0, + 1, 0x00CA, 0x0045, 0x0302, 0, + 1, 0x00CB, 0x0045, 0x0308, 0, + 1, 0x00CC, 0x0049, 0x0300, 0, + 1, 0x00CD, 0x0049, 0x0301, 0, + 1, 0x00CE, 0x0049, 0x0302, 0, + 1, 0x00CF, 0x0049, 0x0308, 0, + 1, 0x00D1, 0x004E, 0x0303, 0, + 1, 0x00D2, 0x004F, 0x0300, 0, + 1, 0x00D3, 0x004F, 0x0301, 0, + 1, 0x00D4, 0x004F, 0x0302, 0, + 1, 0x00D5, 0x004F, 0x0303, 0, + 1, 0x00D6, 0x004F, 0x0308, 0, + 1, 0x00D9, 0x0055, 0x0300, 0, + 1, 0x00DA, 0x0055, 0x0301, 0, + 1, 0x00DB, 0x0055, 0x0302, 0, + 1, 0x00DC, 0x0055, 0x0308, 0, + 1, 0x00DD, 0x0059, 0x0301, 0, + 1, 0x00E0, 0x0061, 0x0300, 0, + 1, 0x00E1, 0x0061, 0x0301, 0, + 1, 0x00E2, 0x0061, 0x0302, 0, + 1, 0x00E3, 0x0061, 0x0303, 0, + 1, 0x00E4, 0x0061, 0x0308, 0, + 1, 0x00E5, 0x0061, 0x030A, 0, + 1, 0x00E7, 0x0063, 0x0327, 0, + 1, 0x00E8, 0x0065, 0x0300, 0, + 1, 0x00E9, 0x0065, 0x0301, 0, + 1, 0x00EA, 0x0065, 0x0302, 0, + 1, 0x00EB, 0x0065, 0x0308, 0, + 1, 0x00EC, 0x0069, 0x0300, 0, + 1, 0x00ED, 0x0069, 0x0301, 0, + 1, 0x00EE, 0x0069, 0x0302, 0, + 1, 0x00EF, 0x0069, 0x0308, 0, + 1, 0x00F1, 0x006E, 0x0303, 0, + 1, 0x00F2, 0x006F, 0x0300, 0, + 1, 0x00F3, 0x006F, 0x0301, 0, + 1, 0x00F4, 0x006F, 0x0302, 0, + 1, 0x00F5, 0x006F, 0x0303, 0, + 1, 0x00F6, 0x006F, 0x0308, 0, + 1, 0x00F9, 0x0075, 0x0300, 0, + 1, 0x00FA, 0x0075, 0x0301, 0, + 1, 0x00FB, 0x0075, 0x0302, 0, + 1, 0x00FC, 0x0075, 0x0308, 0, + 1, 0x00FD, 0x0079, 0x0301, 0, + 1, 0x00FF, 0x0079, 0x0308, 0, + 1, 0x0100, 0x0041, 0x0304, 0, + 1, 0x0101, 0x0061, 0x0304, 0, + 1, 0x0102, 0x0041, 0x0306, 0, + 1, 0x0103, 0x0061, 0x0306, 0, + 1, 0x0104, 0x0041, 0x0328, 0, + 1, 0x0105, 0x0061, 0x0328, 0, + 1, 0x0106, 0x0043, 0x0301, 0, + 1, 0x0107, 0x0063, 0x0301, 0, + 1, 0x0108, 0x0043, 0x0302, 0, + 1, 0x0109, 0x0063, 0x0302, 0, + 1, 0x010A, 0x0043, 0x0307, 0, + 1, 0x010B, 0x0063, 0x0307, 0, + 1, 0x010C, 0x0043, 0x030C, 0, + 1, 0x010D, 0x0063, 0x030C, 0, + 1, 0x010E, 0x0044, 0x030C, 0, + 1, 0x010F, 0x0064, 0x030C, 0, + 1, 0x0112, 0x0045, 0x0304, 0, + 1, 0x0113, 0x0065, 0x0304, 0, + 1, 0x0114, 0x0045, 0x0306, 0, + 1, 0x0115, 0x0065, 0x0306, 0, + 1, 0x0116, 0x0045, 0x0307, 0, + 1, 0x0117, 0x0065, 0x0307, 0, + 1, 0x0118, 0x0045, 0x0328, 0, + 1, 0x0119, 0x0065, 0x0328, 0, + 1, 0x011A, 0x0045, 0x030C, 0, + 1, 0x011B, 0x0065, 0x030C, 0, + 1, 0x011C, 0x0047, 0x0302, 0, + 1, 0x011D, 0x0067, 0x0302, 0, + 1, 0x011E, 0x0047, 0x0306, 0, + 1, 0x011F, 0x0067, 0x0306, 0, + 1, 0x0120, 0x0047, 0x0307, 0, + 1, 0x0121, 0x0067, 0x0307, 0, + 1, 0x0122, 0x0047, 0x0327, 0, + 1, 0x0123, 0x0067, 0x0327, 0, + 1, 0x0124, 0x0048, 0x0302, 0, + 1, 0x0125, 0x0068, 0x0302, 0, + 1, 0x0128, 0x0049, 0x0303, 0, + 1, 0x0129, 0x0069, 0x0303, 0, + 1, 0x012A, 0x0049, 0x0304, 0, + 1, 0x012B, 0x0069, 0x0304, 0, + 1, 0x012C, 0x0049, 0x0306, 0, + 1, 0x012D, 0x0069, 0x0306, 0, + 1, 0x012E, 0x0049, 0x0328, 0, + 1, 0x012F, 0x0069, 0x0328, 0, + 1, 0x0130, 0x0049, 0x0307, 0, + 16, 0x0132, 0x0049, 0x004A, 0, + 16, 0x0133, 0x0069, 0x006A, 0, + 1, 0x0134, 0x004A, 0x0302, 0, + 1, 0x0135, 0x006A, 0x0302, 0, + 1, 0x0136, 0x004B, 0x0327, 0, + 1, 0x0137, 0x006B, 0x0327, 0, + 1, 0x0139, 0x004C, 0x0301, 0, + 1, 0x013A, 0x006C, 0x0301, 0, + 1, 0x013B, 0x004C, 0x0327, 0, + 1, 0x013C, 0x006C, 0x0327, 0, + 1, 0x013D, 0x004C, 0x030C, 0, + 1, 0x013E, 0x006C, 0x030C, 0, + 16, 0x013F, 0x004C, 0x00B7, 0, + 16, 0x0140, 0x006C, 0x00B7, 0, + 1, 0x0143, 0x004E, 0x0301, 0, + 1, 0x0144, 0x006E, 0x0301, 0, + 1, 0x0145, 0x004E, 0x0327, 0, + 1, 0x0146, 0x006E, 0x0327, 0, + 1, 0x0147, 0x004E, 0x030C, 0, + 1, 0x0148, 0x006E, 0x030C, 0, + 16, 0x0149, 0x02BC, 0x006E, 0, + 1, 0x014C, 0x004F, 0x0304, 0, + 1, 0x014D, 0x006F, 0x0304, 0, + 1, 0x014E, 0x004F, 0x0306, 0, + 1, 0x014F, 0x006F, 0x0306, 0, + 1, 0x0150, 0x004F, 0x030B, 0, + 1, 0x0151, 0x006F, 0x030B, 0, + 1, 0x0154, 0x0052, 0x0301, 0, + 1, 0x0155, 0x0072, 0x0301, 0, + 1, 0x0156, 0x0052, 0x0327, 0, + 1, 0x0157, 0x0072, 0x0327, 0, + 1, 0x0158, 0x0052, 0x030C, 0, + 1, 0x0159, 0x0072, 0x030C, 0, + 1, 0x015A, 0x0053, 0x0301, 0, + 1, 0x015B, 0x0073, 0x0301, 0, + 1, 0x015C, 0x0053, 0x0302, 0, + 1, 0x015D, 0x0073, 0x0302, 0, + 1, 0x015E, 0x0053, 0x0327, 0, + 1, 0x015F, 0x0073, 0x0327, 0, + 1, 0x0160, 0x0053, 0x030C, 0, + 1, 0x0161, 0x0073, 0x030C, 0, + 1, 0x0162, 0x0054, 0x0327, 0, + 1, 0x0163, 0x0074, 0x0327, 0, + 1, 0x0164, 0x0054, 0x030C, 0, + 1, 0x0165, 0x0074, 0x030C, 0, + 1, 0x0168, 0x0055, 0x0303, 0, + 1, 0x0169, 0x0075, 0x0303, 0, + 1, 0x016A, 0x0055, 0x0304, 0, + 1, 0x016B, 0x0075, 0x0304, 0, + 1, 0x016C, 0x0055, 0x0306, 0, + 1, 0x016D, 0x0075, 0x0306, 0, + 1, 0x016E, 0x0055, 0x030A, 0, + 1, 0x016F, 0x0075, 0x030A, 0, + 1, 0x0170, 0x0055, 0x030B, 0, + 1, 0x0171, 0x0075, 0x030B, 0, + 1, 0x0172, 0x0055, 0x0328, 0, + 1, 0x0173, 0x0075, 0x0328, 0, + 1, 0x0174, 0x0057, 0x0302, 0, + 1, 0x0175, 0x0077, 0x0302, 0, + 1, 0x0176, 0x0059, 0x0302, 0, + 1, 0x0177, 0x0079, 0x0302, 0, + 1, 0x0178, 0x0059, 0x0308, 0, + 1, 0x0179, 0x005A, 0x0301, 0, + 1, 0x017A, 0x007A, 0x0301, 0, + 1, 0x017B, 0x005A, 0x0307, 0, + 1, 0x017C, 0x007A, 0x0307, 0, + 1, 0x017D, 0x005A, 0x030C, 0, + 1, 0x017E, 0x007A, 0x030C, 0, + 16, 0x017F, 0x0073, 0, + 1, 0x01A0, 0x004F, 0x031B, 0, + 1, 0x01A1, 0x006F, 0x031B, 0, + 1, 0x01AF, 0x0055, 0x031B, 0, + 1, 0x01B0, 0x0075, 0x031B, 0, + 16, 0x01C4, 0x0044, 0x017D, 0, + 16, 0x01C5, 0x0044, 0x017E, 0, + 16, 0x01C6, 0x0064, 0x017E, 0, + 16, 0x01C7, 0x004C, 0x004A, 0, + 16, 0x01C8, 0x004C, 0x006A, 0, + 16, 0x01C9, 0x006C, 0x006A, 0, + 16, 0x01CA, 0x004E, 0x004A, 0, + 16, 0x01CB, 0x004E, 0x006A, 0, + 16, 0x01CC, 0x006E, 0x006A, 0, + 1, 0x01CD, 0x0041, 0x030C, 0, + 1, 0x01CE, 0x0061, 0x030C, 0, + 1, 0x01CF, 0x0049, 0x030C, 0, + 1, 0x01D0, 0x0069, 0x030C, 0, + 1, 0x01D1, 0x004F, 0x030C, 0, + 1, 0x01D2, 0x006F, 0x030C, 0, + 1, 0x01D3, 0x0055, 0x030C, 0, + 1, 0x01D4, 0x0075, 0x030C, 0, + 1, 0x01D5, 0x00DC, 0x0304, 0, + 1, 0x01D6, 0x00FC, 0x0304, 0, + 1, 0x01D7, 0x00DC, 0x0301, 0, + 1, 0x01D8, 0x00FC, 0x0301, 0, + 1, 0x01D9, 0x00DC, 0x030C, 0, + 1, 0x01DA, 0x00FC, 0x030C, 0, + 1, 0x01DB, 0x00DC, 0x0300, 0, + 1, 0x01DC, 0x00FC, 0x0300, 0, + 1, 0x01DE, 0x00C4, 0x0304, 0, + 1, 0x01DF, 0x00E4, 0x0304, 0, + 1, 0x01E0, 0x0226, 0x0304, 0, + 1, 0x01E1, 0x0227, 0x0304, 0, + 1, 0x01E2, 0x00C6, 0x0304, 0, + 1, 0x01E3, 0x00E6, 0x0304, 0, + 1, 0x01E6, 0x0047, 0x030C, 0, + 1, 0x01E7, 0x0067, 0x030C, 0, + 1, 0x01E8, 0x004B, 0x030C, 0, + 1, 0x01E9, 0x006B, 0x030C, 0, + 1, 0x01EA, 0x004F, 0x0328, 0, + 1, 0x01EB, 0x006F, 0x0328, 0, + 1, 0x01EC, 0x01EA, 0x0304, 0, + 1, 0x01ED, 0x01EB, 0x0304, 0, + 1, 0x01EE, 0x01B7, 0x030C, 0, + 1, 0x01EF, 0x0292, 0x030C, 0, + 1, 0x01F0, 0x006A, 0x030C, 0, + 16, 0x01F1, 0x0044, 0x005A, 0, + 16, 0x01F2, 0x0044, 0x007A, 0, + 16, 0x01F3, 0x0064, 0x007A, 0, + 1, 0x01F4, 0x0047, 0x0301, 0, + 1, 0x01F5, 0x0067, 0x0301, 0, + 1, 0x01F8, 0x004E, 0x0300, 0, + 1, 0x01F9, 0x006E, 0x0300, 0, + 1, 0x01FA, 0x00C5, 0x0301, 0, + 1, 0x01FB, 0x00E5, 0x0301, 0, + 1, 0x01FC, 0x00C6, 0x0301, 0, + 1, 0x01FD, 0x00E6, 0x0301, 0, + 1, 0x01FE, 0x00D8, 0x0301, 0, + 1, 0x01FF, 0x00F8, 0x0301, 0, + 1, 0x0200, 0x0041, 0x030F, 0, + 1, 0x0201, 0x0061, 0x030F, 0, + 1, 0x0202, 0x0041, 0x0311, 0, + 1, 0x0203, 0x0061, 0x0311, 0, + 1, 0x0204, 0x0045, 0x030F, 0, + 1, 0x0205, 0x0065, 0x030F, 0, + 1, 0x0206, 0x0045, 0x0311, 0, + 1, 0x0207, 0x0065, 0x0311, 0, + 1, 0x0208, 0x0049, 0x030F, 0, + 1, 0x0209, 0x0069, 0x030F, 0, + 1, 0x020A, 0x0049, 0x0311, 0, + 1, 0x020B, 0x0069, 0x0311, 0, + 1, 0x020C, 0x004F, 0x030F, 0, + 1, 0x020D, 0x006F, 0x030F, 0, + 1, 0x020E, 0x004F, 0x0311, 0, + 1, 0x020F, 0x006F, 0x0311, 0, + 1, 0x0210, 0x0052, 0x030F, 0, + 1, 0x0211, 0x0072, 0x030F, 0, + 1, 0x0212, 0x0052, 0x0311, 0, + 1, 0x0213, 0x0072, 0x0311, 0, + 1, 0x0214, 0x0055, 0x030F, 0, + 1, 0x0215, 0x0075, 0x030F, 0, + 1, 0x0216, 0x0055, 0x0311, 0, + 1, 0x0217, 0x0075, 0x0311, 0, + 1, 0x0218, 0x0053, 0x0326, 0, + 1, 0x0219, 0x0073, 0x0326, 0, + 1, 0x021A, 0x0054, 0x0326, 0, + 1, 0x021B, 0x0074, 0x0326, 0, + 1, 0x021E, 0x0048, 0x030C, 0, + 1, 0x021F, 0x0068, 0x030C, 0, + 1, 0x0226, 0x0041, 0x0307, 0, + 1, 0x0227, 0x0061, 0x0307, 0, + 1, 0x0228, 0x0045, 0x0327, 0, + 1, 0x0229, 0x0065, 0x0327, 0, + 1, 0x022A, 0x00D6, 0x0304, 0, + 1, 0x022B, 0x00F6, 0x0304, 0, + 1, 0x022C, 0x00D5, 0x0304, 0, + 1, 0x022D, 0x00F5, 0x0304, 0, + 1, 0x022E, 0x004F, 0x0307, 0, + 1, 0x022F, 0x006F, 0x0307, 0, + 1, 0x0230, 0x022E, 0x0304, 0, + 1, 0x0231, 0x022F, 0x0304, 0, + 1, 0x0232, 0x0059, 0x0304, 0, + 1, 0x0233, 0x0079, 0x0304, 0, + 9, 0x02B0, 0x0068, 0, + 9, 0x02B1, 0x0266, 0, + 9, 0x02B2, 0x006A, 0, + 9, 0x02B3, 0x0072, 0, + 9, 0x02B4, 0x0279, 0, + 9, 0x02B5, 0x027B, 0, + 9, 0x02B6, 0x0281, 0, + 9, 0x02B7, 0x0077, 0, + 9, 0x02B8, 0x0079, 0, + 16, 0x02D8, 0x0020, 0x0306, 0, + 16, 0x02D9, 0x0020, 0x0307, 0, + 16, 0x02DA, 0x0020, 0x030A, 0, + 16, 0x02DB, 0x0020, 0x0328, 0, + 16, 0x02DC, 0x0020, 0x0303, 0, + 16, 0x02DD, 0x0020, 0x030B, 0, + 9, 0x02E0, 0x0263, 0, + 9, 0x02E1, 0x006C, 0, + 9, 0x02E2, 0x0073, 0, + 9, 0x02E3, 0x0078, 0, + 9, 0x02E4, 0x0295, 0, + 1, 0x0340, 0x0300, 0, + 1, 0x0341, 0x0301, 0, + 1, 0x0343, 0x0313, 0, + 1, 0x0344, 0x0308, 0x0301, 0, + 1, 0x0374, 0x02B9, 0, + 16, 0x037A, 0x0020, 0x0345, 0, + 1, 0x037E, 0x003B, 0, + 16, 0x0384, 0x0020, 0x0301, 0, + 1, 0x0385, 0x00A8, 0x0301, 0, + 1, 0x0386, 0x0391, 0x0301, 0, + 1, 0x0387, 0x00B7, 0, + 1, 0x0388, 0x0395, 0x0301, 0, + 1, 0x0389, 0x0397, 0x0301, 0, + 1, 0x038A, 0x0399, 0x0301, 0, + 1, 0x038C, 0x039F, 0x0301, 0, + 1, 0x038E, 0x03A5, 0x0301, 0, + 1, 0x038F, 0x03A9, 0x0301, 0, + 1, 0x0390, 0x03CA, 0x0301, 0, + 1, 0x03AA, 0x0399, 0x0308, 0, + 1, 0x03AB, 0x03A5, 0x0308, 0, + 1, 0x03AC, 0x03B1, 0x0301, 0, + 1, 0x03AD, 0x03B5, 0x0301, 0, + 1, 0x03AE, 0x03B7, 0x0301, 0, + 1, 0x03AF, 0x03B9, 0x0301, 0, + 1, 0x03B0, 0x03CB, 0x0301, 0, + 1, 0x03CA, 0x03B9, 0x0308, 0, + 1, 0x03CB, 0x03C5, 0x0308, 0, + 1, 0x03CC, 0x03BF, 0x0301, 0, + 1, 0x03CD, 0x03C5, 0x0301, 0, + 1, 0x03CE, 0x03C9, 0x0301, 0, + 16, 0x03D0, 0x03B2, 0, + 16, 0x03D1, 0x03B8, 0, + 16, 0x03D2, 0x03A5, 0, + 1, 0x03D3, 0x03D2, 0x0301, 0, + 1, 0x03D4, 0x03D2, 0x0308, 0, + 16, 0x03D5, 0x03C6, 0, + 16, 0x03D6, 0x03C0, 0, + 16, 0x03F0, 0x03BA, 0, + 16, 0x03F1, 0x03C1, 0, + 16, 0x03F2, 0x03C2, 0, + 1, 0x0400, 0x0415, 0x0300, 0, + 1, 0x0401, 0x0415, 0x0308, 0, + 1, 0x0403, 0x0413, 0x0301, 0, + 1, 0x0407, 0x0406, 0x0308, 0, + 1, 0x040C, 0x041A, 0x0301, 0, + 1, 0x040D, 0x0418, 0x0300, 0, + 1, 0x040E, 0x0423, 0x0306, 0, + 1, 0x0419, 0x0418, 0x0306, 0, + 1, 0x0439, 0x0438, 0x0306, 0, + 1, 0x0450, 0x0435, 0x0300, 0, + 1, 0x0451, 0x0435, 0x0308, 0, + 1, 0x0453, 0x0433, 0x0301, 0, + 1, 0x0457, 0x0456, 0x0308, 0, + 1, 0x045C, 0x043A, 0x0301, 0, + 1, 0x045D, 0x0438, 0x0300, 0, + 1, 0x045E, 0x0443, 0x0306, 0, + 1, 0x0476, 0x0474, 0x030F, 0, + 1, 0x0477, 0x0475, 0x030F, 0, + 1, 0x04C1, 0x0416, 0x0306, 0, + 1, 0x04C2, 0x0436, 0x0306, 0, + 1, 0x04D0, 0x0410, 0x0306, 0, + 1, 0x04D1, 0x0430, 0x0306, 0, + 1, 0x04D2, 0x0410, 0x0308, 0, + 1, 0x04D3, 0x0430, 0x0308, 0, + 1, 0x04D6, 0x0415, 0x0306, 0, + 1, 0x04D7, 0x0435, 0x0306, 0, + 1, 0x04DA, 0x04D8, 0x0308, 0, + 1, 0x04DB, 0x04D9, 0x0308, 0, + 1, 0x04DC, 0x0416, 0x0308, 0, + 1, 0x04DD, 0x0436, 0x0308, 0, + 1, 0x04DE, 0x0417, 0x0308, 0, + 1, 0x04DF, 0x0437, 0x0308, 0, + 1, 0x04E2, 0x0418, 0x0304, 0, + 1, 0x04E3, 0x0438, 0x0304, 0, + 1, 0x04E4, 0x0418, 0x0308, 0, + 1, 0x04E5, 0x0438, 0x0308, 0, + 1, 0x04E6, 0x041E, 0x0308, 0, + 1, 0x04E7, 0x043E, 0x0308, 0, + 1, 0x04EA, 0x04E8, 0x0308, 0, + 1, 0x04EB, 0x04E9, 0x0308, 0, + 1, 0x04EC, 0x042D, 0x0308, 0, + 1, 0x04ED, 0x044D, 0x0308, 0, + 1, 0x04EE, 0x0423, 0x0304, 0, + 1, 0x04EF, 0x0443, 0x0304, 0, + 1, 0x04F0, 0x0423, 0x0308, 0, + 1, 0x04F1, 0x0443, 0x0308, 0, + 1, 0x04F2, 0x0423, 0x030B, 0, + 1, 0x04F3, 0x0443, 0x030B, 0, + 1, 0x04F4, 0x0427, 0x0308, 0, + 1, 0x04F5, 0x0447, 0x0308, 0, + 1, 0x04F8, 0x042B, 0x0308, 0, + 1, 0x04F9, 0x044B, 0x0308, 0, + 16, 0x0587, 0x0565, 0x0582, 0, + 1, 0x0622, 0x0627, 0x0653, 0, + 1, 0x0623, 0x0627, 0x0654, 0, + 1, 0x0624, 0x0648, 0x0654, 0, + 1, 0x0625, 0x0627, 0x0655, 0, + 1, 0x0626, 0x064A, 0x0654, 0, + 16, 0x0675, 0x0627, 0x0674, 0, + 16, 0x0676, 0x0648, 0x0674, 0, + 16, 0x0677, 0x06C7, 0x0674, 0, + 16, 0x0678, 0x064A, 0x0674, 0, + 1, 0x06C0, 0x06D5, 0x0654, 0, + 1, 0x06C2, 0x06C1, 0x0654, 0, + 1, 0x06D3, 0x06D2, 0x0654, 0, + 1, 0x0929, 0x0928, 0x093C, 0, + 1, 0x0931, 0x0930, 0x093C, 0, + 1, 0x0934, 0x0933, 0x093C, 0, + 1, 0x0958, 0x0915, 0x093C, 0, + 1, 0x0959, 0x0916, 0x093C, 0, + 1, 0x095A, 0x0917, 0x093C, 0, + 1, 0x095B, 0x091C, 0x093C, 0, + 1, 0x095C, 0x0921, 0x093C, 0, + 1, 0x095D, 0x0922, 0x093C, 0, + 1, 0x095E, 0x092B, 0x093C, 0, + 1, 0x095F, 0x092F, 0x093C, 0, + 1, 0x09CB, 0x09C7, 0x09BE, 0, + 1, 0x09CC, 0x09C7, 0x09D7, 0, + 1, 0x09DC, 0x09A1, 0x09BC, 0, + 1, 0x09DD, 0x09A2, 0x09BC, 0, + 1, 0x09DF, 0x09AF, 0x09BC, 0, + 1, 0x0A33, 0x0A32, 0x0A3C, 0, + 1, 0x0A36, 0x0A38, 0x0A3C, 0, + 1, 0x0A59, 0x0A16, 0x0A3C, 0, + 1, 0x0A5A, 0x0A17, 0x0A3C, 0, + 1, 0x0A5B, 0x0A1C, 0x0A3C, 0, + 1, 0x0A5E, 0x0A2B, 0x0A3C, 0, + 1, 0x0B48, 0x0B47, 0x0B56, 0, + 1, 0x0B4B, 0x0B47, 0x0B3E, 0, + 1, 0x0B4C, 0x0B47, 0x0B57, 0, + 1, 0x0B5C, 0x0B21, 0x0B3C, 0, + 1, 0x0B5D, 0x0B22, 0x0B3C, 0, + 1, 0x0B94, 0x0B92, 0x0BD7, 0, + 1, 0x0BCA, 0x0BC6, 0x0BBE, 0, + 1, 0x0BCB, 0x0BC7, 0x0BBE, 0, + 1, 0x0BCC, 0x0BC6, 0x0BD7, 0, + 1, 0x0C48, 0x0C46, 0x0C56, 0, + 1, 0x0CC0, 0x0CBF, 0x0CD5, 0, + 1, 0x0CC7, 0x0CC6, 0x0CD5, 0, + 1, 0x0CC8, 0x0CC6, 0x0CD6, 0, + 1, 0x0CCA, 0x0CC6, 0x0CC2, 0, + 1, 0x0CCB, 0x0CCA, 0x0CD5, 0, + 1, 0x0D4A, 0x0D46, 0x0D3E, 0, + 1, 0x0D4B, 0x0D47, 0x0D3E, 0, + 1, 0x0D4C, 0x0D46, 0x0D57, 0, + 1, 0x0DDA, 0x0DD9, 0x0DCA, 0, + 1, 0x0DDC, 0x0DD9, 0x0DCF, 0, + 1, 0x0DDD, 0x0DDC, 0x0DCA, 0, + 1, 0x0DDE, 0x0DD9, 0x0DDF, 0, + 16, 0x0E33, 0x0E4D, 0x0E32, 0, + 16, 0x0EB3, 0x0ECD, 0x0EB2, 0, + 16, 0x0EDC, 0x0EAB, 0x0E99, 0, + 16, 0x0EDD, 0x0EAB, 0x0EA1, 0, + 3, 0x0F0C, 0x0F0B, 0, + 1, 0x0F43, 0x0F42, 0x0FB7, 0, + 1, 0x0F4D, 0x0F4C, 0x0FB7, 0, + 1, 0x0F52, 0x0F51, 0x0FB7, 0, + 1, 0x0F57, 0x0F56, 0x0FB7, 0, + 1, 0x0F5C, 0x0F5B, 0x0FB7, 0, + 1, 0x0F69, 0x0F40, 0x0FB5, 0, + 1, 0x0F73, 0x0F71, 0x0F72, 0, + 1, 0x0F75, 0x0F71, 0x0F74, 0, + 1, 0x0F76, 0x0FB2, 0x0F80, 0, + 16, 0x0F77, 0x0FB2, 0x0F81, 0, + 1, 0x0F78, 0x0FB3, 0x0F80, 0, + 16, 0x0F79, 0x0FB3, 0x0F81, 0, + 1, 0x0F81, 0x0F71, 0x0F80, 0, + 1, 0x0F93, 0x0F92, 0x0FB7, 0, + 1, 0x0F9D, 0x0F9C, 0x0FB7, 0, + 1, 0x0FA2, 0x0FA1, 0x0FB7, 0, + 1, 0x0FA7, 0x0FA6, 0x0FB7, 0, + 1, 0x0FAC, 0x0FAB, 0x0FB7, 0, + 1, 0x0FB9, 0x0F90, 0x0FB5, 0, + 1, 0x1026, 0x1025, 0x102E, 0, + 1, 0x1E00, 0x0041, 0x0325, 0, + 1, 0x1E01, 0x0061, 0x0325, 0, + 1, 0x1E02, 0x0042, 0x0307, 0, + 1, 0x1E03, 0x0062, 0x0307, 0, + 1, 0x1E04, 0x0042, 0x0323, 0, + 1, 0x1E05, 0x0062, 0x0323, 0, + 1, 0x1E06, 0x0042, 0x0331, 0, + 1, 0x1E07, 0x0062, 0x0331, 0, + 1, 0x1E08, 0x00C7, 0x0301, 0, + 1, 0x1E09, 0x00E7, 0x0301, 0, + 1, 0x1E0A, 0x0044, 0x0307, 0, + 1, 0x1E0B, 0x0064, 0x0307, 0, + 1, 0x1E0C, 0x0044, 0x0323, 0, + 1, 0x1E0D, 0x0064, 0x0323, 0, + 1, 0x1E0E, 0x0044, 0x0331, 0, + 1, 0x1E0F, 0x0064, 0x0331, 0, + 1, 0x1E10, 0x0044, 0x0327, 0, + 1, 0x1E11, 0x0064, 0x0327, 0, + 1, 0x1E12, 0x0044, 0x032D, 0, + 1, 0x1E13, 0x0064, 0x032D, 0, + 1, 0x1E14, 0x0112, 0x0300, 0, + 1, 0x1E15, 0x0113, 0x0300, 0, + 1, 0x1E16, 0x0112, 0x0301, 0, + 1, 0x1E17, 0x0113, 0x0301, 0, + 1, 0x1E18, 0x0045, 0x032D, 0, + 1, 0x1E19, 0x0065, 0x032D, 0, + 1, 0x1E1A, 0x0045, 0x0330, 0, + 1, 0x1E1B, 0x0065, 0x0330, 0, + 1, 0x1E1C, 0x0228, 0x0306, 0, + 1, 0x1E1D, 0x0229, 0x0306, 0, + 1, 0x1E1E, 0x0046, 0x0307, 0, + 1, 0x1E1F, 0x0066, 0x0307, 0, + 1, 0x1E20, 0x0047, 0x0304, 0, + 1, 0x1E21, 0x0067, 0x0304, 0, + 1, 0x1E22, 0x0048, 0x0307, 0, + 1, 0x1E23, 0x0068, 0x0307, 0, + 1, 0x1E24, 0x0048, 0x0323, 0, + 1, 0x1E25, 0x0068, 0x0323, 0, + 1, 0x1E26, 0x0048, 0x0308, 0, + 1, 0x1E27, 0x0068, 0x0308, 0, + 1, 0x1E28, 0x0048, 0x0327, 0, + 1, 0x1E29, 0x0068, 0x0327, 0, + 1, 0x1E2A, 0x0048, 0x032E, 0, + 1, 0x1E2B, 0x0068, 0x032E, 0, + 1, 0x1E2C, 0x0049, 0x0330, 0, + 1, 0x1E2D, 0x0069, 0x0330, 0, + 1, 0x1E2E, 0x00CF, 0x0301, 0, + 1, 0x1E2F, 0x00EF, 0x0301, 0, + 1, 0x1E30, 0x004B, 0x0301, 0, + 1, 0x1E31, 0x006B, 0x0301, 0, + 1, 0x1E32, 0x004B, 0x0323, 0, + 1, 0x1E33, 0x006B, 0x0323, 0, + 1, 0x1E34, 0x004B, 0x0331, 0, + 1, 0x1E35, 0x006B, 0x0331, 0, + 1, 0x1E36, 0x004C, 0x0323, 0, + 1, 0x1E37, 0x006C, 0x0323, 0, + 1, 0x1E38, 0x1E36, 0x0304, 0, + 1, 0x1E39, 0x1E37, 0x0304, 0, + 1, 0x1E3A, 0x004C, 0x0331, 0, + 1, 0x1E3B, 0x006C, 0x0331, 0, + 1, 0x1E3C, 0x004C, 0x032D, 0, + 1, 0x1E3D, 0x006C, 0x032D, 0, + 1, 0x1E3E, 0x004D, 0x0301, 0, + 1, 0x1E3F, 0x006D, 0x0301, 0, + 1, 0x1E40, 0x004D, 0x0307, 0, + 1, 0x1E41, 0x006D, 0x0307, 0, + 1, 0x1E42, 0x004D, 0x0323, 0, + 1, 0x1E43, 0x006D, 0x0323, 0, + 1, 0x1E44, 0x004E, 0x0307, 0, + 1, 0x1E45, 0x006E, 0x0307, 0, + 1, 0x1E46, 0x004E, 0x0323, 0, + 1, 0x1E47, 0x006E, 0x0323, 0, + 1, 0x1E48, 0x004E, 0x0331, 0, + 1, 0x1E49, 0x006E, 0x0331, 0, + 1, 0x1E4A, 0x004E, 0x032D, 0, + 1, 0x1E4B, 0x006E, 0x032D, 0, + 1, 0x1E4C, 0x00D5, 0x0301, 0, + 1, 0x1E4D, 0x00F5, 0x0301, 0, + 1, 0x1E4E, 0x00D5, 0x0308, 0, + 1, 0x1E4F, 0x00F5, 0x0308, 0, + 1, 0x1E50, 0x014C, 0x0300, 0, + 1, 0x1E51, 0x014D, 0x0300, 0, + 1, 0x1E52, 0x014C, 0x0301, 0, + 1, 0x1E53, 0x014D, 0x0301, 0, + 1, 0x1E54, 0x0050, 0x0301, 0, + 1, 0x1E55, 0x0070, 0x0301, 0, + 1, 0x1E56, 0x0050, 0x0307, 0, + 1, 0x1E57, 0x0070, 0x0307, 0, + 1, 0x1E58, 0x0052, 0x0307, 0, + 1, 0x1E59, 0x0072, 0x0307, 0, + 1, 0x1E5A, 0x0052, 0x0323, 0, + 1, 0x1E5B, 0x0072, 0x0323, 0, + 1, 0x1E5C, 0x1E5A, 0x0304, 0, + 1, 0x1E5D, 0x1E5B, 0x0304, 0, + 1, 0x1E5E, 0x0052, 0x0331, 0, + 1, 0x1E5F, 0x0072, 0x0331, 0, + 1, 0x1E60, 0x0053, 0x0307, 0, + 1, 0x1E61, 0x0073, 0x0307, 0, + 1, 0x1E62, 0x0053, 0x0323, 0, + 1, 0x1E63, 0x0073, 0x0323, 0, + 1, 0x1E64, 0x015A, 0x0307, 0, + 1, 0x1E65, 0x015B, 0x0307, 0, + 1, 0x1E66, 0x0160, 0x0307, 0, + 1, 0x1E67, 0x0161, 0x0307, 0, + 1, 0x1E68, 0x1E62, 0x0307, 0, + 1, 0x1E69, 0x1E63, 0x0307, 0, + 1, 0x1E6A, 0x0054, 0x0307, 0, + 1, 0x1E6B, 0x0074, 0x0307, 0, + 1, 0x1E6C, 0x0054, 0x0323, 0, + 1, 0x1E6D, 0x0074, 0x0323, 0, + 1, 0x1E6E, 0x0054, 0x0331, 0, + 1, 0x1E6F, 0x0074, 0x0331, 0, + 1, 0x1E70, 0x0054, 0x032D, 0, + 1, 0x1E71, 0x0074, 0x032D, 0, + 1, 0x1E72, 0x0055, 0x0324, 0, + 1, 0x1E73, 0x0075, 0x0324, 0, + 1, 0x1E74, 0x0055, 0x0330, 0, + 1, 0x1E75, 0x0075, 0x0330, 0, + 1, 0x1E76, 0x0055, 0x032D, 0, + 1, 0x1E77, 0x0075, 0x032D, 0, + 1, 0x1E78, 0x0168, 0x0301, 0, + 1, 0x1E79, 0x0169, 0x0301, 0, + 1, 0x1E7A, 0x016A, 0x0308, 0, + 1, 0x1E7B, 0x016B, 0x0308, 0, + 1, 0x1E7C, 0x0056, 0x0303, 0, + 1, 0x1E7D, 0x0076, 0x0303, 0, + 1, 0x1E7E, 0x0056, 0x0323, 0, + 1, 0x1E7F, 0x0076, 0x0323, 0, + 1, 0x1E80, 0x0057, 0x0300, 0, + 1, 0x1E81, 0x0077, 0x0300, 0, + 1, 0x1E82, 0x0057, 0x0301, 0, + 1, 0x1E83, 0x0077, 0x0301, 0, + 1, 0x1E84, 0x0057, 0x0308, 0, + 1, 0x1E85, 0x0077, 0x0308, 0, + 1, 0x1E86, 0x0057, 0x0307, 0, + 1, 0x1E87, 0x0077, 0x0307, 0, + 1, 0x1E88, 0x0057, 0x0323, 0, + 1, 0x1E89, 0x0077, 0x0323, 0, + 1, 0x1E8A, 0x0058, 0x0307, 0, + 1, 0x1E8B, 0x0078, 0x0307, 0, + 1, 0x1E8C, 0x0058, 0x0308, 0, + 1, 0x1E8D, 0x0078, 0x0308, 0, + 1, 0x1E8E, 0x0059, 0x0307, 0, + 1, 0x1E8F, 0x0079, 0x0307, 0, + 1, 0x1E90, 0x005A, 0x0302, 0, + 1, 0x1E91, 0x007A, 0x0302, 0, + 1, 0x1E92, 0x005A, 0x0323, 0, + 1, 0x1E93, 0x007A, 0x0323, 0, + 1, 0x1E94, 0x005A, 0x0331, 0, + 1, 0x1E95, 0x007A, 0x0331, 0, + 1, 0x1E96, 0x0068, 0x0331, 0, + 1, 0x1E97, 0x0074, 0x0308, 0, + 1, 0x1E98, 0x0077, 0x030A, 0, + 1, 0x1E99, 0x0079, 0x030A, 0, + 16, 0x1E9A, 0x0061, 0x02BE, 0, + 1, 0x1E9B, 0x017F, 0x0307, 0, + 1, 0x1EA0, 0x0041, 0x0323, 0, + 1, 0x1EA1, 0x0061, 0x0323, 0, + 1, 0x1EA2, 0x0041, 0x0309, 0, + 1, 0x1EA3, 0x0061, 0x0309, 0, + 1, 0x1EA4, 0x00C2, 0x0301, 0, + 1, 0x1EA5, 0x00E2, 0x0301, 0, + 1, 0x1EA6, 0x00C2, 0x0300, 0, + 1, 0x1EA7, 0x00E2, 0x0300, 0, + 1, 0x1EA8, 0x00C2, 0x0309, 0, + 1, 0x1EA9, 0x00E2, 0x0309, 0, + 1, 0x1EAA, 0x00C2, 0x0303, 0, + 1, 0x1EAB, 0x00E2, 0x0303, 0, + 1, 0x1EAC, 0x1EA0, 0x0302, 0, + 1, 0x1EAD, 0x1EA1, 0x0302, 0, + 1, 0x1EAE, 0x0102, 0x0301, 0, + 1, 0x1EAF, 0x0103, 0x0301, 0, + 1, 0x1EB0, 0x0102, 0x0300, 0, + 1, 0x1EB1, 0x0103, 0x0300, 0, + 1, 0x1EB2, 0x0102, 0x0309, 0, + 1, 0x1EB3, 0x0103, 0x0309, 0, + 1, 0x1EB4, 0x0102, 0x0303, 0, + 1, 0x1EB5, 0x0103, 0x0303, 0, + 1, 0x1EB6, 0x1EA0, 0x0306, 0, + 1, 0x1EB7, 0x1EA1, 0x0306, 0, + 1, 0x1EB8, 0x0045, 0x0323, 0, + 1, 0x1EB9, 0x0065, 0x0323, 0, + 1, 0x1EBA, 0x0045, 0x0309, 0, + 1, 0x1EBB, 0x0065, 0x0309, 0, + 1, 0x1EBC, 0x0045, 0x0303, 0, + 1, 0x1EBD, 0x0065, 0x0303, 0, + 1, 0x1EBE, 0x00CA, 0x0301, 0, + 1, 0x1EBF, 0x00EA, 0x0301, 0, + 1, 0x1EC0, 0x00CA, 0x0300, 0, + 1, 0x1EC1, 0x00EA, 0x0300, 0, + 1, 0x1EC2, 0x00CA, 0x0309, 0, + 1, 0x1EC3, 0x00EA, 0x0309, 0, + 1, 0x1EC4, 0x00CA, 0x0303, 0, + 1, 0x1EC5, 0x00EA, 0x0303, 0, + 1, 0x1EC6, 0x1EB8, 0x0302, 0, + 1, 0x1EC7, 0x1EB9, 0x0302, 0, + 1, 0x1EC8, 0x0049, 0x0309, 0, + 1, 0x1EC9, 0x0069, 0x0309, 0, + 1, 0x1ECA, 0x0049, 0x0323, 0, + 1, 0x1ECB, 0x0069, 0x0323, 0, + 1, 0x1ECC, 0x004F, 0x0323, 0, + 1, 0x1ECD, 0x006F, 0x0323, 0, + 1, 0x1ECE, 0x004F, 0x0309, 0, + 1, 0x1ECF, 0x006F, 0x0309, 0, + 1, 0x1ED0, 0x00D4, 0x0301, 0, + 1, 0x1ED1, 0x00F4, 0x0301, 0, + 1, 0x1ED2, 0x00D4, 0x0300, 0, + 1, 0x1ED3, 0x00F4, 0x0300, 0, + 1, 0x1ED4, 0x00D4, 0x0309, 0, + 1, 0x1ED5, 0x00F4, 0x0309, 0, + 1, 0x1ED6, 0x00D4, 0x0303, 0, + 1, 0x1ED7, 0x00F4, 0x0303, 0, + 1, 0x1ED8, 0x1ECC, 0x0302, 0, + 1, 0x1ED9, 0x1ECD, 0x0302, 0, + 1, 0x1EDA, 0x01A0, 0x0301, 0, + 1, 0x1EDB, 0x01A1, 0x0301, 0, + 1, 0x1EDC, 0x01A0, 0x0300, 0, + 1, 0x1EDD, 0x01A1, 0x0300, 0, + 1, 0x1EDE, 0x01A0, 0x0309, 0, + 1, 0x1EDF, 0x01A1, 0x0309, 0, + 1, 0x1EE0, 0x01A0, 0x0303, 0, + 1, 0x1EE1, 0x01A1, 0x0303, 0, + 1, 0x1EE2, 0x01A0, 0x0323, 0, + 1, 0x1EE3, 0x01A1, 0x0323, 0, + 1, 0x1EE4, 0x0055, 0x0323, 0, + 1, 0x1EE5, 0x0075, 0x0323, 0, + 1, 0x1EE6, 0x0055, 0x0309, 0, + 1, 0x1EE7, 0x0075, 0x0309, 0, + 1, 0x1EE8, 0x01AF, 0x0301, 0, + 1, 0x1EE9, 0x01B0, 0x0301, 0, + 1, 0x1EEA, 0x01AF, 0x0300, 0, + 1, 0x1EEB, 0x01B0, 0x0300, 0, + 1, 0x1EEC, 0x01AF, 0x0309, 0, + 1, 0x1EED, 0x01B0, 0x0309, 0, + 1, 0x1EEE, 0x01AF, 0x0303, 0, + 1, 0x1EEF, 0x01B0, 0x0303, 0, + 1, 0x1EF0, 0x01AF, 0x0323, 0, + 1, 0x1EF1, 0x01B0, 0x0323, 0, + 1, 0x1EF2, 0x0059, 0x0300, 0, + 1, 0x1EF3, 0x0079, 0x0300, 0, + 1, 0x1EF4, 0x0059, 0x0323, 0, + 1, 0x1EF5, 0x0079, 0x0323, 0, + 1, 0x1EF6, 0x0059, 0x0309, 0, + 1, 0x1EF7, 0x0079, 0x0309, 0, + 1, 0x1EF8, 0x0059, 0x0303, 0, + 1, 0x1EF9, 0x0079, 0x0303, 0, + 1, 0x1F00, 0x03B1, 0x0313, 0, + 1, 0x1F01, 0x03B1, 0x0314, 0, + 1, 0x1F02, 0x1F00, 0x0300, 0, + 1, 0x1F03, 0x1F01, 0x0300, 0, + 1, 0x1F04, 0x1F00, 0x0301, 0, + 1, 0x1F05, 0x1F01, 0x0301, 0, + 1, 0x1F06, 0x1F00, 0x0342, 0, + 1, 0x1F07, 0x1F01, 0x0342, 0, + 1, 0x1F08, 0x0391, 0x0313, 0, + 1, 0x1F09, 0x0391, 0x0314, 0, + 1, 0x1F0A, 0x1F08, 0x0300, 0, + 1, 0x1F0B, 0x1F09, 0x0300, 0, + 1, 0x1F0C, 0x1F08, 0x0301, 0, + 1, 0x1F0D, 0x1F09, 0x0301, 0, + 1, 0x1F0E, 0x1F08, 0x0342, 0, + 1, 0x1F0F, 0x1F09, 0x0342, 0, + 1, 0x1F10, 0x03B5, 0x0313, 0, + 1, 0x1F11, 0x03B5, 0x0314, 0, + 1, 0x1F12, 0x1F10, 0x0300, 0, + 1, 0x1F13, 0x1F11, 0x0300, 0, + 1, 0x1F14, 0x1F10, 0x0301, 0, + 1, 0x1F15, 0x1F11, 0x0301, 0, + 1, 0x1F18, 0x0395, 0x0313, 0, + 1, 0x1F19, 0x0395, 0x0314, 0, + 1, 0x1F1A, 0x1F18, 0x0300, 0, + 1, 0x1F1B, 0x1F19, 0x0300, 0, + 1, 0x1F1C, 0x1F18, 0x0301, 0, + 1, 0x1F1D, 0x1F19, 0x0301, 0, + 1, 0x1F20, 0x03B7, 0x0313, 0, + 1, 0x1F21, 0x03B7, 0x0314, 0, + 1, 0x1F22, 0x1F20, 0x0300, 0, + 1, 0x1F23, 0x1F21, 0x0300, 0, + 1, 0x1F24, 0x1F20, 0x0301, 0, + 1, 0x1F25, 0x1F21, 0x0301, 0, + 1, 0x1F26, 0x1F20, 0x0342, 0, + 1, 0x1F27, 0x1F21, 0x0342, 0, + 1, 0x1F28, 0x0397, 0x0313, 0, + 1, 0x1F29, 0x0397, 0x0314, 0, + 1, 0x1F2A, 0x1F28, 0x0300, 0, + 1, 0x1F2B, 0x1F29, 0x0300, 0, + 1, 0x1F2C, 0x1F28, 0x0301, 0, + 1, 0x1F2D, 0x1F29, 0x0301, 0, + 1, 0x1F2E, 0x1F28, 0x0342, 0, + 1, 0x1F2F, 0x1F29, 0x0342, 0, + 1, 0x1F30, 0x03B9, 0x0313, 0, + 1, 0x1F31, 0x03B9, 0x0314, 0, + 1, 0x1F32, 0x1F30, 0x0300, 0, + 1, 0x1F33, 0x1F31, 0x0300, 0, + 1, 0x1F34, 0x1F30, 0x0301, 0, + 1, 0x1F35, 0x1F31, 0x0301, 0, + 1, 0x1F36, 0x1F30, 0x0342, 0, + 1, 0x1F37, 0x1F31, 0x0342, 0, + 1, 0x1F38, 0x0399, 0x0313, 0, + 1, 0x1F39, 0x0399, 0x0314, 0, + 1, 0x1F3A, 0x1F38, 0x0300, 0, + 1, 0x1F3B, 0x1F39, 0x0300, 0, + 1, 0x1F3C, 0x1F38, 0x0301, 0, + 1, 0x1F3D, 0x1F39, 0x0301, 0, + 1, 0x1F3E, 0x1F38, 0x0342, 0, + 1, 0x1F3F, 0x1F39, 0x0342, 0, + 1, 0x1F40, 0x03BF, 0x0313, 0, + 1, 0x1F41, 0x03BF, 0x0314, 0, + 1, 0x1F42, 0x1F40, 0x0300, 0, + 1, 0x1F43, 0x1F41, 0x0300, 0, + 1, 0x1F44, 0x1F40, 0x0301, 0, + 1, 0x1F45, 0x1F41, 0x0301, 0, + 1, 0x1F48, 0x039F, 0x0313, 0, + 1, 0x1F49, 0x039F, 0x0314, 0, + 1, 0x1F4A, 0x1F48, 0x0300, 0, + 1, 0x1F4B, 0x1F49, 0x0300, 0, + 1, 0x1F4C, 0x1F48, 0x0301, 0, + 1, 0x1F4D, 0x1F49, 0x0301, 0, + 1, 0x1F50, 0x03C5, 0x0313, 0, + 1, 0x1F51, 0x03C5, 0x0314, 0, + 1, 0x1F52, 0x1F50, 0x0300, 0, + 1, 0x1F53, 0x1F51, 0x0300, 0, + 1, 0x1F54, 0x1F50, 0x0301, 0, + 1, 0x1F55, 0x1F51, 0x0301, 0, + 1, 0x1F56, 0x1F50, 0x0342, 0, + 1, 0x1F57, 0x1F51, 0x0342, 0, + 1, 0x1F59, 0x03A5, 0x0314, 0, + 1, 0x1F5B, 0x1F59, 0x0300, 0, + 1, 0x1F5D, 0x1F59, 0x0301, 0, + 1, 0x1F5F, 0x1F59, 0x0342, 0, + 1, 0x1F60, 0x03C9, 0x0313, 0, + 1, 0x1F61, 0x03C9, 0x0314, 0, + 1, 0x1F62, 0x1F60, 0x0300, 0, + 1, 0x1F63, 0x1F61, 0x0300, 0, + 1, 0x1F64, 0x1F60, 0x0301, 0, + 1, 0x1F65, 0x1F61, 0x0301, 0, + 1, 0x1F66, 0x1F60, 0x0342, 0, + 1, 0x1F67, 0x1F61, 0x0342, 0, + 1, 0x1F68, 0x03A9, 0x0313, 0, + 1, 0x1F69, 0x03A9, 0x0314, 0, + 1, 0x1F6A, 0x1F68, 0x0300, 0, + 1, 0x1F6B, 0x1F69, 0x0300, 0, + 1, 0x1F6C, 0x1F68, 0x0301, 0, + 1, 0x1F6D, 0x1F69, 0x0301, 0, + 1, 0x1F6E, 0x1F68, 0x0342, 0, + 1, 0x1F6F, 0x1F69, 0x0342, 0, + 1, 0x1F70, 0x03B1, 0x0300, 0, + 1, 0x1F71, 0x03AC, 0, + 1, 0x1F72, 0x03B5, 0x0300, 0, + 1, 0x1F73, 0x03AD, 0, + 1, 0x1F74, 0x03B7, 0x0300, 0, + 1, 0x1F75, 0x03AE, 0, + 1, 0x1F76, 0x03B9, 0x0300, 0, + 1, 0x1F77, 0x03AF, 0, + 1, 0x1F78, 0x03BF, 0x0300, 0, + 1, 0x1F79, 0x03CC, 0, + 1, 0x1F7A, 0x03C5, 0x0300, 0, + 1, 0x1F7B, 0x03CD, 0, + 1, 0x1F7C, 0x03C9, 0x0300, 0, + 1, 0x1F7D, 0x03CE, 0, + 1, 0x1F80, 0x1F00, 0x0345, 0, + 1, 0x1F81, 0x1F01, 0x0345, 0, + 1, 0x1F82, 0x1F02, 0x0345, 0, + 1, 0x1F83, 0x1F03, 0x0345, 0, + 1, 0x1F84, 0x1F04, 0x0345, 0, + 1, 0x1F85, 0x1F05, 0x0345, 0, + 1, 0x1F86, 0x1F06, 0x0345, 0, + 1, 0x1F87, 0x1F07, 0x0345, 0, + 1, 0x1F88, 0x1F08, 0x0345, 0, + 1, 0x1F89, 0x1F09, 0x0345, 0, + 1, 0x1F8A, 0x1F0A, 0x0345, 0, + 1, 0x1F8B, 0x1F0B, 0x0345, 0, + 1, 0x1F8C, 0x1F0C, 0x0345, 0, + 1, 0x1F8D, 0x1F0D, 0x0345, 0, + 1, 0x1F8E, 0x1F0E, 0x0345, 0, + 1, 0x1F8F, 0x1F0F, 0x0345, 0, + 1, 0x1F90, 0x1F20, 0x0345, 0, + 1, 0x1F91, 0x1F21, 0x0345, 0, + 1, 0x1F92, 0x1F22, 0x0345, 0, + 1, 0x1F93, 0x1F23, 0x0345, 0, + 1, 0x1F94, 0x1F24, 0x0345, 0, + 1, 0x1F95, 0x1F25, 0x0345, 0, + 1, 0x1F96, 0x1F26, 0x0345, 0, + 1, 0x1F97, 0x1F27, 0x0345, 0, + 1, 0x1F98, 0x1F28, 0x0345, 0, + 1, 0x1F99, 0x1F29, 0x0345, 0, + 1, 0x1F9A, 0x1F2A, 0x0345, 0, + 1, 0x1F9B, 0x1F2B, 0x0345, 0, + 1, 0x1F9C, 0x1F2C, 0x0345, 0, + 1, 0x1F9D, 0x1F2D, 0x0345, 0, + 1, 0x1F9E, 0x1F2E, 0x0345, 0, + 1, 0x1F9F, 0x1F2F, 0x0345, 0, + 1, 0x1FA0, 0x1F60, 0x0345, 0, + 1, 0x1FA1, 0x1F61, 0x0345, 0, + 1, 0x1FA2, 0x1F62, 0x0345, 0, + 1, 0x1FA3, 0x1F63, 0x0345, 0, + 1, 0x1FA4, 0x1F64, 0x0345, 0, + 1, 0x1FA5, 0x1F65, 0x0345, 0, + 1, 0x1FA6, 0x1F66, 0x0345, 0, + 1, 0x1FA7, 0x1F67, 0x0345, 0, + 1, 0x1FA8, 0x1F68, 0x0345, 0, + 1, 0x1FA9, 0x1F69, 0x0345, 0, + 1, 0x1FAA, 0x1F6A, 0x0345, 0, + 1, 0x1FAB, 0x1F6B, 0x0345, 0, + 1, 0x1FAC, 0x1F6C, 0x0345, 0, + 1, 0x1FAD, 0x1F6D, 0x0345, 0, + 1, 0x1FAE, 0x1F6E, 0x0345, 0, + 1, 0x1FAF, 0x1F6F, 0x0345, 0, + 1, 0x1FB0, 0x03B1, 0x0306, 0, + 1, 0x1FB1, 0x03B1, 0x0304, 0, + 1, 0x1FB2, 0x1F70, 0x0345, 0, + 1, 0x1FB3, 0x03B1, 0x0345, 0, + 1, 0x1FB4, 0x03AC, 0x0345, 0, + 1, 0x1FB6, 0x03B1, 0x0342, 0, + 1, 0x1FB7, 0x1FB6, 0x0345, 0, + 1, 0x1FB8, 0x0391, 0x0306, 0, + 1, 0x1FB9, 0x0391, 0x0304, 0, + 1, 0x1FBA, 0x0391, 0x0300, 0, + 1, 0x1FBB, 0x0386, 0, + 1, 0x1FBC, 0x0391, 0x0345, 0, + 16, 0x1FBD, 0x0020, 0x0313, 0, + 1, 0x1FBE, 0x03B9, 0, + 16, 0x1FBF, 0x0020, 0x0313, 0, + 16, 0x1FC0, 0x0020, 0x0342, 0, + 1, 0x1FC1, 0x00A8, 0x0342, 0, + 1, 0x1FC2, 0x1F74, 0x0345, 0, + 1, 0x1FC3, 0x03B7, 0x0345, 0, + 1, 0x1FC4, 0x03AE, 0x0345, 0, + 1, 0x1FC6, 0x03B7, 0x0342, 0, + 1, 0x1FC7, 0x1FC6, 0x0345, 0, + 1, 0x1FC8, 0x0395, 0x0300, 0, + 1, 0x1FC9, 0x0388, 0, + 1, 0x1FCA, 0x0397, 0x0300, 0, + 1, 0x1FCB, 0x0389, 0, + 1, 0x1FCC, 0x0397, 0x0345, 0, + 1, 0x1FCD, 0x1FBF, 0x0300, 0, + 1, 0x1FCE, 0x1FBF, 0x0301, 0, + 1, 0x1FCF, 0x1FBF, 0x0342, 0, + 1, 0x1FD0, 0x03B9, 0x0306, 0, + 1, 0x1FD1, 0x03B9, 0x0304, 0, + 1, 0x1FD2, 0x03CA, 0x0300, 0, + 1, 0x1FD3, 0x0390, 0, + 1, 0x1FD6, 0x03B9, 0x0342, 0, + 1, 0x1FD7, 0x03CA, 0x0342, 0, + 1, 0x1FD8, 0x0399, 0x0306, 0, + 1, 0x1FD9, 0x0399, 0x0304, 0, + 1, 0x1FDA, 0x0399, 0x0300, 0, + 1, 0x1FDB, 0x038A, 0, + 1, 0x1FDD, 0x1FFE, 0x0300, 0, + 1, 0x1FDE, 0x1FFE, 0x0301, 0, + 1, 0x1FDF, 0x1FFE, 0x0342, 0, + 1, 0x1FE0, 0x03C5, 0x0306, 0, + 1, 0x1FE1, 0x03C5, 0x0304, 0, + 1, 0x1FE2, 0x03CB, 0x0300, 0, + 1, 0x1FE3, 0x03B0, 0, + 1, 0x1FE4, 0x03C1, 0x0313, 0, + 1, 0x1FE5, 0x03C1, 0x0314, 0, + 1, 0x1FE6, 0x03C5, 0x0342, 0, + 1, 0x1FE7, 0x03CB, 0x0342, 0, + 1, 0x1FE8, 0x03A5, 0x0306, 0, + 1, 0x1FE9, 0x03A5, 0x0304, 0, + 1, 0x1FEA, 0x03A5, 0x0300, 0, + 1, 0x1FEB, 0x038E, 0, + 1, 0x1FEC, 0x03A1, 0x0314, 0, + 1, 0x1FED, 0x00A8, 0x0300, 0, + 1, 0x1FEE, 0x0385, 0, + 1, 0x1FEF, 0x0060, 0, + 1, 0x1FF2, 0x1F7C, 0x0345, 0, + 1, 0x1FF3, 0x03C9, 0x0345, 0, + 1, 0x1FF4, 0x03CE, 0x0345, 0, + 1, 0x1FF6, 0x03C9, 0x0342, 0, + 1, 0x1FF7, 0x1FF6, 0x0345, 0, + 1, 0x1FF8, 0x039F, 0x0300, 0, + 1, 0x1FF9, 0x038C, 0, + 1, 0x1FFA, 0x03A9, 0x0300, 0, + 1, 0x1FFB, 0x038F, 0, + 1, 0x1FFC, 0x03A9, 0x0345, 0, + 1, 0x1FFD, 0x00B4, 0, + 16, 0x1FFE, 0x0020, 0x0314, 0, + 1, 0x2000, 0x2002, 0, + 1, 0x2001, 0x2003, 0, + 16, 0x2002, 0x0020, 0, + 16, 0x2003, 0x0020, 0, + 16, 0x2004, 0x0020, 0, + 16, 0x2005, 0x0020, 0, + 16, 0x2006, 0x0020, 0, + 3, 0x2007, 0x0020, 0, + 16, 0x2008, 0x0020, 0, + 16, 0x2009, 0x0020, 0, + 16, 0x200A, 0x0020, 0, + 3, 0x2011, 0x2010, 0, + 16, 0x2017, 0x0020, 0x0333, 0, + 16, 0x2024, 0x002E, 0, + 16, 0x2025, 0x002E, 0x002E, 0, + 16, 0x2026, 0x002E, 0x002E, 0x002E, 0, + 3, 0x202F, 0x0020, 0, + 16, 0x2033, 0x2032, 0x2032, 0, + 16, 0x2034, 0x2032, 0x2032, 0x2032, 0, + 16, 0x2036, 0x2035, 0x2035, 0, + 16, 0x2037, 0x2035, 0x2035, 0x2035, 0, + 16, 0x203C, 0x0021, 0x0021, 0, + 16, 0x203E, 0x0020, 0x0305, 0, + 16, 0x2048, 0x003F, 0x0021, 0, + 16, 0x2049, 0x0021, 0x003F, 0, + 9, 0x2070, 0x0030, 0, + 9, 0x2074, 0x0034, 0, + 9, 0x2075, 0x0035, 0, + 9, 0x2076, 0x0036, 0, + 9, 0x2077, 0x0037, 0, + 9, 0x2078, 0x0038, 0, + 9, 0x2079, 0x0039, 0, + 9, 0x207A, 0x002B, 0, + 9, 0x207B, 0x2212, 0, + 9, 0x207C, 0x003D, 0, + 9, 0x207D, 0x0028, 0, + 9, 0x207E, 0x0029, 0, + 9, 0x207F, 0x006E, 0, + 10, 0x2080, 0x0030, 0, + 10, 0x2081, 0x0031, 0, + 10, 0x2082, 0x0032, 0, + 10, 0x2083, 0x0033, 0, + 10, 0x2084, 0x0034, 0, + 10, 0x2085, 0x0035, 0, + 10, 0x2086, 0x0036, 0, + 10, 0x2087, 0x0037, 0, + 10, 0x2088, 0x0038, 0, + 10, 0x2089, 0x0039, 0, + 10, 0x208A, 0x002B, 0, + 10, 0x208B, 0x2212, 0, + 10, 0x208C, 0x003D, 0, + 10, 0x208D, 0x0028, 0, + 10, 0x208E, 0x0029, 0, + 16, 0x20A8, 0x0052, 0x0073, 0, + 16, 0x2100, 0x0061, 0x002F, 0x0063, 0, + 16, 0x2101, 0x0061, 0x002F, 0x0073, 0, + 2, 0x2102, 0x0043, 0, + 16, 0x2103, 0x00B0, 0x0043, 0, + 16, 0x2105, 0x0063, 0x002F, 0x006F, 0, + 16, 0x2106, 0x0063, 0x002F, 0x0075, 0, + 16, 0x2107, 0x0190, 0, + 16, 0x2109, 0x00B0, 0x0046, 0, + 2, 0x210A, 0x0067, 0, + 2, 0x210B, 0x0048, 0, + 2, 0x210C, 0x0048, 0, + 2, 0x210D, 0x0048, 0, + 2, 0x210E, 0x0068, 0, + 2, 0x210F, 0x0127, 0, + 2, 0x2110, 0x0049, 0, + 2, 0x2111, 0x0049, 0, + 2, 0x2112, 0x004C, 0, + 2, 0x2113, 0x006C, 0, + 2, 0x2115, 0x004E, 0, + 16, 0x2116, 0x004E, 0x006F, 0, + 2, 0x2119, 0x0050, 0, + 2, 0x211A, 0x0051, 0, + 2, 0x211B, 0x0052, 0, + 2, 0x211C, 0x0052, 0, + 2, 0x211D, 0x0052, 0, + 9, 0x2120, 0x0053, 0x004D, 0, + 16, 0x2121, 0x0054, 0x0045, 0x004C, 0, + 9, 0x2122, 0x0054, 0x004D, 0, + 2, 0x2124, 0x005A, 0, + 1, 0x2126, 0x03A9, 0, + 2, 0x2128, 0x005A, 0, + 1, 0x212A, 0x004B, 0, + 1, 0x212B, 0x00C5, 0, + 2, 0x212C, 0x0042, 0, + 2, 0x212D, 0x0043, 0, + 2, 0x212F, 0x0065, 0, + 2, 0x2130, 0x0045, 0, + 2, 0x2131, 0x0046, 0, + 2, 0x2133, 0x004D, 0, + 2, 0x2134, 0x006F, 0, + 16, 0x2135, 0x05D0, 0, + 16, 0x2136, 0x05D1, 0, + 16, 0x2137, 0x05D2, 0, + 16, 0x2138, 0x05D3, 0, + 2, 0x2139, 0x0069, 0, + 17, 0x2153, 0x0031, 0x2044, 0x0033, 0, + 17, 0x2154, 0x0032, 0x2044, 0x0033, 0, + 17, 0x2155, 0x0031, 0x2044, 0x0035, 0, + 17, 0x2156, 0x0032, 0x2044, 0x0035, 0, + 17, 0x2157, 0x0033, 0x2044, 0x0035, 0, + 17, 0x2158, 0x0034, 0x2044, 0x0035, 0, + 17, 0x2159, 0x0031, 0x2044, 0x0036, 0, + 17, 0x215A, 0x0035, 0x2044, 0x0036, 0, + 17, 0x215B, 0x0031, 0x2044, 0x0038, 0, + 17, 0x215C, 0x0033, 0x2044, 0x0038, 0, + 17, 0x215D, 0x0035, 0x2044, 0x0038, 0, + 17, 0x215E, 0x0037, 0x2044, 0x0038, 0, + 17, 0x215F, 0x0031, 0x2044, 0, + 16, 0x2160, 0x0049, 0, + 16, 0x2161, 0x0049, 0x0049, 0, + 16, 0x2162, 0x0049, 0x0049, 0x0049, 0, + 16, 0x2163, 0x0049, 0x0056, 0, + 16, 0x2164, 0x0056, 0, + 16, 0x2165, 0x0056, 0x0049, 0, + 16, 0x2166, 0x0056, 0x0049, 0x0049, 0, + 16, 0x2167, 0x0056, 0x0049, 0x0049, 0x0049, 0, + 16, 0x2168, 0x0049, 0x0058, 0, + 16, 0x2169, 0x0058, 0, + 16, 0x216A, 0x0058, 0x0049, 0, + 16, 0x216B, 0x0058, 0x0049, 0x0049, 0, + 16, 0x216C, 0x004C, 0, + 16, 0x216D, 0x0043, 0, + 16, 0x216E, 0x0044, 0, + 16, 0x216F, 0x004D, 0, + 16, 0x2170, 0x0069, 0, + 16, 0x2171, 0x0069, 0x0069, 0, + 16, 0x2172, 0x0069, 0x0069, 0x0069, 0, + 16, 0x2173, 0x0069, 0x0076, 0, + 16, 0x2174, 0x0076, 0, + 16, 0x2175, 0x0076, 0x0069, 0, + 16, 0x2176, 0x0076, 0x0069, 0x0069, 0, + 16, 0x2177, 0x0076, 0x0069, 0x0069, 0x0069, 0, + 16, 0x2178, 0x0069, 0x0078, 0, + 16, 0x2179, 0x0078, 0, + 16, 0x217A, 0x0078, 0x0069, 0, + 16, 0x217B, 0x0078, 0x0069, 0x0069, 0, + 16, 0x217C, 0x006C, 0, + 16, 0x217D, 0x0063, 0, + 16, 0x217E, 0x0064, 0, + 16, 0x217F, 0x006D, 0, + 1, 0x219A, 0x2190, 0x0338, 0, + 1, 0x219B, 0x2192, 0x0338, 0, + 1, 0x21AE, 0x2194, 0x0338, 0, + 1, 0x21CD, 0x21D0, 0x0338, 0, + 1, 0x21CE, 0x21D4, 0x0338, 0, + 1, 0x21CF, 0x21D2, 0x0338, 0, + 1, 0x2204, 0x2203, 0x0338, 0, + 1, 0x2209, 0x2208, 0x0338, 0, + 1, 0x220C, 0x220B, 0x0338, 0, + 1, 0x2224, 0x2223, 0x0338, 0, + 1, 0x2226, 0x2225, 0x0338, 0, + 16, 0x222C, 0x222B, 0x222B, 0, + 16, 0x222D, 0x222B, 0x222B, 0x222B, 0, + 16, 0x222F, 0x222E, 0x222E, 0, + 16, 0x2230, 0x222E, 0x222E, 0x222E, 0, + 1, 0x2241, 0x223C, 0x0338, 0, + 1, 0x2244, 0x2243, 0x0338, 0, + 1, 0x2247, 0x2245, 0x0338, 0, + 1, 0x2249, 0x2248, 0x0338, 0, + 1, 0x2260, 0x003D, 0x0338, 0, + 1, 0x2262, 0x2261, 0x0338, 0, + 1, 0x226D, 0x224D, 0x0338, 0, + 1, 0x226E, 0x003C, 0x0338, 0, + 1, 0x226F, 0x003E, 0x0338, 0, + 1, 0x2270, 0x2264, 0x0338, 0, + 1, 0x2271, 0x2265, 0x0338, 0, + 1, 0x2274, 0x2272, 0x0338, 0, + 1, 0x2275, 0x2273, 0x0338, 0, + 1, 0x2278, 0x2276, 0x0338, 0, + 1, 0x2279, 0x2277, 0x0338, 0, + 1, 0x2280, 0x227A, 0x0338, 0, + 1, 0x2281, 0x227B, 0x0338, 0, + 1, 0x2284, 0x2282, 0x0338, 0, + 1, 0x2285, 0x2283, 0x0338, 0, + 1, 0x2288, 0x2286, 0x0338, 0, + 1, 0x2289, 0x2287, 0x0338, 0, + 1, 0x22AC, 0x22A2, 0x0338, 0, + 1, 0x22AD, 0x22A8, 0x0338, 0, + 1, 0x22AE, 0x22A9, 0x0338, 0, + 1, 0x22AF, 0x22AB, 0x0338, 0, + 1, 0x22E0, 0x227C, 0x0338, 0, + 1, 0x22E1, 0x227D, 0x0338, 0, + 1, 0x22E2, 0x2291, 0x0338, 0, + 1, 0x22E3, 0x2292, 0x0338, 0, + 1, 0x22EA, 0x22B2, 0x0338, 0, + 1, 0x22EB, 0x22B3, 0x0338, 0, + 1, 0x22EC, 0x22B4, 0x0338, 0, + 1, 0x22ED, 0x22B5, 0x0338, 0, + 1, 0x2329, 0x3008, 0, + 1, 0x232A, 0x3009, 0, + 8, 0x2460, 0x0031, 0, + 8, 0x2461, 0x0032, 0, + 8, 0x2462, 0x0033, 0, + 8, 0x2463, 0x0034, 0, + 8, 0x2464, 0x0035, 0, + 8, 0x2465, 0x0036, 0, + 8, 0x2466, 0x0037, 0, + 8, 0x2467, 0x0038, 0, + 8, 0x2468, 0x0039, 0, + 8, 0x2469, 0x0031, 0x0030, 0, + 8, 0x246A, 0x0031, 0x0031, 0, + 8, 0x246B, 0x0031, 0x0032, 0, + 8, 0x246C, 0x0031, 0x0033, 0, + 8, 0x246D, 0x0031, 0x0034, 0, + 8, 0x246E, 0x0031, 0x0035, 0, + 8, 0x246F, 0x0031, 0x0036, 0, + 8, 0x2470, 0x0031, 0x0037, 0, + 8, 0x2471, 0x0031, 0x0038, 0, + 8, 0x2472, 0x0031, 0x0039, 0, + 8, 0x2473, 0x0032, 0x0030, 0, + 16, 0x2474, 0x0028, 0x0031, 0x0029, 0, + 16, 0x2475, 0x0028, 0x0032, 0x0029, 0, + 16, 0x2476, 0x0028, 0x0033, 0x0029, 0, + 16, 0x2477, 0x0028, 0x0034, 0x0029, 0, + 16, 0x2478, 0x0028, 0x0035, 0x0029, 0, + 16, 0x2479, 0x0028, 0x0036, 0x0029, 0, + 16, 0x247A, 0x0028, 0x0037, 0x0029, 0, + 16, 0x247B, 0x0028, 0x0038, 0x0029, 0, + 16, 0x247C, 0x0028, 0x0039, 0x0029, 0, + 16, 0x247D, 0x0028, 0x0031, 0x0030, 0x0029, 0, + 16, 0x247E, 0x0028, 0x0031, 0x0031, 0x0029, 0, + 16, 0x247F, 0x0028, 0x0031, 0x0032, 0x0029, 0, + 16, 0x2480, 0x0028, 0x0031, 0x0033, 0x0029, 0, + 16, 0x2481, 0x0028, 0x0031, 0x0034, 0x0029, 0, + 16, 0x2482, 0x0028, 0x0031, 0x0035, 0x0029, 0, + 16, 0x2483, 0x0028, 0x0031, 0x0036, 0x0029, 0, + 16, 0x2484, 0x0028, 0x0031, 0x0037, 0x0029, 0, + 16, 0x2485, 0x0028, 0x0031, 0x0038, 0x0029, 0, + 16, 0x2486, 0x0028, 0x0031, 0x0039, 0x0029, 0, + 16, 0x2487, 0x0028, 0x0032, 0x0030, 0x0029, 0, + 16, 0x2488, 0x0031, 0x002E, 0, + 16, 0x2489, 0x0032, 0x002E, 0, + 16, 0x248A, 0x0033, 0x002E, 0, + 16, 0x248B, 0x0034, 0x002E, 0, + 16, 0x248C, 0x0035, 0x002E, 0, + 16, 0x248D, 0x0036, 0x002E, 0, + 16, 0x248E, 0x0037, 0x002E, 0, + 16, 0x248F, 0x0038, 0x002E, 0, + 16, 0x2490, 0x0039, 0x002E, 0, + 16, 0x2491, 0x0031, 0x0030, 0x002E, 0, + 16, 0x2492, 0x0031, 0x0031, 0x002E, 0, + 16, 0x2493, 0x0031, 0x0032, 0x002E, 0, + 16, 0x2494, 0x0031, 0x0033, 0x002E, 0, + 16, 0x2495, 0x0031, 0x0034, 0x002E, 0, + 16, 0x2496, 0x0031, 0x0035, 0x002E, 0, + 16, 0x2497, 0x0031, 0x0036, 0x002E, 0, + 16, 0x2498, 0x0031, 0x0037, 0x002E, 0, + 16, 0x2499, 0x0031, 0x0038, 0x002E, 0, + 16, 0x249A, 0x0031, 0x0039, 0x002E, 0, + 16, 0x249B, 0x0032, 0x0030, 0x002E, 0, + 16, 0x249C, 0x0028, 0x0061, 0x0029, 0, + 16, 0x249D, 0x0028, 0x0062, 0x0029, 0, + 16, 0x249E, 0x0028, 0x0063, 0x0029, 0, + 16, 0x249F, 0x0028, 0x0064, 0x0029, 0, + 16, 0x24A0, 0x0028, 0x0065, 0x0029, 0, + 16, 0x24A1, 0x0028, 0x0066, 0x0029, 0, + 16, 0x24A2, 0x0028, 0x0067, 0x0029, 0, + 16, 0x24A3, 0x0028, 0x0068, 0x0029, 0, + 16, 0x24A4, 0x0028, 0x0069, 0x0029, 0, + 16, 0x24A5, 0x0028, 0x006A, 0x0029, 0, + 16, 0x24A6, 0x0028, 0x006B, 0x0029, 0, + 16, 0x24A7, 0x0028, 0x006C, 0x0029, 0, + 16, 0x24A8, 0x0028, 0x006D, 0x0029, 0, + 16, 0x24A9, 0x0028, 0x006E, 0x0029, 0, + 16, 0x24AA, 0x0028, 0x006F, 0x0029, 0, + 16, 0x24AB, 0x0028, 0x0070, 0x0029, 0, + 16, 0x24AC, 0x0028, 0x0071, 0x0029, 0, + 16, 0x24AD, 0x0028, 0x0072, 0x0029, 0, + 16, 0x24AE, 0x0028, 0x0073, 0x0029, 0, + 16, 0x24AF, 0x0028, 0x0074, 0x0029, 0, + 16, 0x24B0, 0x0028, 0x0075, 0x0029, 0, + 16, 0x24B1, 0x0028, 0x0076, 0x0029, 0, + 16, 0x24B2, 0x0028, 0x0077, 0x0029, 0, + 16, 0x24B3, 0x0028, 0x0078, 0x0029, 0, + 16, 0x24B4, 0x0028, 0x0079, 0x0029, 0, + 16, 0x24B5, 0x0028, 0x007A, 0x0029, 0, + 8, 0x24B6, 0x0041, 0, + 8, 0x24B7, 0x0042, 0, + 8, 0x24B8, 0x0043, 0, + 8, 0x24B9, 0x0044, 0, + 8, 0x24BA, 0x0045, 0, + 8, 0x24BB, 0x0046, 0, + 8, 0x24BC, 0x0047, 0, + 8, 0x24BD, 0x0048, 0, + 8, 0x24BE, 0x0049, 0, + 8, 0x24BF, 0x004A, 0, + 8, 0x24C0, 0x004B, 0, + 8, 0x24C1, 0x004C, 0, + 8, 0x24C2, 0x004D, 0, + 8, 0x24C3, 0x004E, 0, + 8, 0x24C4, 0x004F, 0, + 8, 0x24C5, 0x0050, 0, + 8, 0x24C6, 0x0051, 0, + 8, 0x24C7, 0x0052, 0, + 8, 0x24C8, 0x0053, 0, + 8, 0x24C9, 0x0054, 0, + 8, 0x24CA, 0x0055, 0, + 8, 0x24CB, 0x0056, 0, + 8, 0x24CC, 0x0057, 0, + 8, 0x24CD, 0x0058, 0, + 8, 0x24CE, 0x0059, 0, + 8, 0x24CF, 0x005A, 0, + 8, 0x24D0, 0x0061, 0, + 8, 0x24D1, 0x0062, 0, + 8, 0x24D2, 0x0063, 0, + 8, 0x24D3, 0x0064, 0, + 8, 0x24D4, 0x0065, 0, + 8, 0x24D5, 0x0066, 0, + 8, 0x24D6, 0x0067, 0, + 8, 0x24D7, 0x0068, 0, + 8, 0x24D8, 0x0069, 0, + 8, 0x24D9, 0x006A, 0, + 8, 0x24DA, 0x006B, 0, + 8, 0x24DB, 0x006C, 0, + 8, 0x24DC, 0x006D, 0, + 8, 0x24DD, 0x006E, 0, + 8, 0x24DE, 0x006F, 0, + 8, 0x24DF, 0x0070, 0, + 8, 0x24E0, 0x0071, 0, + 8, 0x24E1, 0x0072, 0, + 8, 0x24E2, 0x0073, 0, + 8, 0x24E3, 0x0074, 0, + 8, 0x24E4, 0x0075, 0, + 8, 0x24E5, 0x0076, 0, + 8, 0x24E6, 0x0077, 0, + 8, 0x24E7, 0x0078, 0, + 8, 0x24E8, 0x0079, 0, + 8, 0x24E9, 0x007A, 0, + 8, 0x24EA, 0x0030, 0, + 16, 0x2E9F, 0x6BCD, 0, + 16, 0x2EF3, 0x9F9F, 0, + 16, 0x2F00, 0x4E00, 0, + 16, 0x2F01, 0x4E28, 0, + 16, 0x2F02, 0x4E36, 0, + 16, 0x2F03, 0x4E3F, 0, + 16, 0x2F04, 0x4E59, 0, + 16, 0x2F05, 0x4E85, 0, + 16, 0x2F06, 0x4E8C, 0, + 16, 0x2F07, 0x4EA0, 0, + 16, 0x2F08, 0x4EBA, 0, + 16, 0x2F09, 0x513F, 0, + 16, 0x2F0A, 0x5165, 0, + 16, 0x2F0B, 0x516B, 0, + 16, 0x2F0C, 0x5182, 0, + 16, 0x2F0D, 0x5196, 0, + 16, 0x2F0E, 0x51AB, 0, + 16, 0x2F0F, 0x51E0, 0, + 16, 0x2F10, 0x51F5, 0, + 16, 0x2F11, 0x5200, 0, + 16, 0x2F12, 0x529B, 0, + 16, 0x2F13, 0x52F9, 0, + 16, 0x2F14, 0x5315, 0, + 16, 0x2F15, 0x531A, 0, + 16, 0x2F16, 0x5338, 0, + 16, 0x2F17, 0x5341, 0, + 16, 0x2F18, 0x535C, 0, + 16, 0x2F19, 0x5369, 0, + 16, 0x2F1A, 0x5382, 0, + 16, 0x2F1B, 0x53B6, 0, + 16, 0x2F1C, 0x53C8, 0, + 16, 0x2F1D, 0x53E3, 0, + 16, 0x2F1E, 0x56D7, 0, + 16, 0x2F1F, 0x571F, 0, + 16, 0x2F20, 0x58EB, 0, + 16, 0x2F21, 0x5902, 0, + 16, 0x2F22, 0x590A, 0, + 16, 0x2F23, 0x5915, 0, + 16, 0x2F24, 0x5927, 0, + 16, 0x2F25, 0x5973, 0, + 16, 0x2F26, 0x5B50, 0, + 16, 0x2F27, 0x5B80, 0, + 16, 0x2F28, 0x5BF8, 0, + 16, 0x2F29, 0x5C0F, 0, + 16, 0x2F2A, 0x5C22, 0, + 16, 0x2F2B, 0x5C38, 0, + 16, 0x2F2C, 0x5C6E, 0, + 16, 0x2F2D, 0x5C71, 0, + 16, 0x2F2E, 0x5DDB, 0, + 16, 0x2F2F, 0x5DE5, 0, + 16, 0x2F30, 0x5DF1, 0, + 16, 0x2F31, 0x5DFE, 0, + 16, 0x2F32, 0x5E72, 0, + 16, 0x2F33, 0x5E7A, 0, + 16, 0x2F34, 0x5E7F, 0, + 16, 0x2F35, 0x5EF4, 0, + 16, 0x2F36, 0x5EFE, 0, + 16, 0x2F37, 0x5F0B, 0, + 16, 0x2F38, 0x5F13, 0, + 16, 0x2F39, 0x5F50, 0, + 16, 0x2F3A, 0x5F61, 0, + 16, 0x2F3B, 0x5F73, 0, + 16, 0x2F3C, 0x5FC3, 0, + 16, 0x2F3D, 0x6208, 0, + 16, 0x2F3E, 0x6236, 0, + 16, 0x2F3F, 0x624B, 0, + 16, 0x2F40, 0x652F, 0, + 16, 0x2F41, 0x6534, 0, + 16, 0x2F42, 0x6587, 0, + 16, 0x2F43, 0x6597, 0, + 16, 0x2F44, 0x65A4, 0, + 16, 0x2F45, 0x65B9, 0, + 16, 0x2F46, 0x65E0, 0, + 16, 0x2F47, 0x65E5, 0, + 16, 0x2F48, 0x66F0, 0, + 16, 0x2F49, 0x6708, 0, + 16, 0x2F4A, 0x6728, 0, + 16, 0x2F4B, 0x6B20, 0, + 16, 0x2F4C, 0x6B62, 0, + 16, 0x2F4D, 0x6B79, 0, + 16, 0x2F4E, 0x6BB3, 0, + 16, 0x2F4F, 0x6BCB, 0, + 16, 0x2F50, 0x6BD4, 0, + 16, 0x2F51, 0x6BDB, 0, + 16, 0x2F52, 0x6C0F, 0, + 16, 0x2F53, 0x6C14, 0, + 16, 0x2F54, 0x6C34, 0, + 16, 0x2F55, 0x706B, 0, + 16, 0x2F56, 0x722A, 0, + 16, 0x2F57, 0x7236, 0, + 16, 0x2F58, 0x723B, 0, + 16, 0x2F59, 0x723F, 0, + 16, 0x2F5A, 0x7247, 0, + 16, 0x2F5B, 0x7259, 0, + 16, 0x2F5C, 0x725B, 0, + 16, 0x2F5D, 0x72AC, 0, + 16, 0x2F5E, 0x7384, 0, + 16, 0x2F5F, 0x7389, 0, + 16, 0x2F60, 0x74DC, 0, + 16, 0x2F61, 0x74E6, 0, + 16, 0x2F62, 0x7518, 0, + 16, 0x2F63, 0x751F, 0, + 16, 0x2F64, 0x7528, 0, + 16, 0x2F65, 0x7530, 0, + 16, 0x2F66, 0x758B, 0, + 16, 0x2F67, 0x7592, 0, + 16, 0x2F68, 0x7676, 0, + 16, 0x2F69, 0x767D, 0, + 16, 0x2F6A, 0x76AE, 0, + 16, 0x2F6B, 0x76BF, 0, + 16, 0x2F6C, 0x76EE, 0, + 16, 0x2F6D, 0x77DB, 0, + 16, 0x2F6E, 0x77E2, 0, + 16, 0x2F6F, 0x77F3, 0, + 16, 0x2F70, 0x793A, 0, + 16, 0x2F71, 0x79B8, 0, + 16, 0x2F72, 0x79BE, 0, + 16, 0x2F73, 0x7A74, 0, + 16, 0x2F74, 0x7ACB, 0, + 16, 0x2F75, 0x7AF9, 0, + 16, 0x2F76, 0x7C73, 0, + 16, 0x2F77, 0x7CF8, 0, + 16, 0x2F78, 0x7F36, 0, + 16, 0x2F79, 0x7F51, 0, + 16, 0x2F7A, 0x7F8A, 0, + 16, 0x2F7B, 0x7FBD, 0, + 16, 0x2F7C, 0x8001, 0, + 16, 0x2F7D, 0x800C, 0, + 16, 0x2F7E, 0x8012, 0, + 16, 0x2F7F, 0x8033, 0, + 16, 0x2F80, 0x807F, 0, + 16, 0x2F81, 0x8089, 0, + 16, 0x2F82, 0x81E3, 0, + 16, 0x2F83, 0x81EA, 0, + 16, 0x2F84, 0x81F3, 0, + 16, 0x2F85, 0x81FC, 0, + 16, 0x2F86, 0x820C, 0, + 16, 0x2F87, 0x821B, 0, + 16, 0x2F88, 0x821F, 0, + 16, 0x2F89, 0x826E, 0, + 16, 0x2F8A, 0x8272, 0, + 16, 0x2F8B, 0x8278, 0, + 16, 0x2F8C, 0x864D, 0, + 16, 0x2F8D, 0x866B, 0, + 16, 0x2F8E, 0x8840, 0, + 16, 0x2F8F, 0x884C, 0, + 16, 0x2F90, 0x8863, 0, + 16, 0x2F91, 0x897E, 0, + 16, 0x2F92, 0x898B, 0, + 16, 0x2F93, 0x89D2, 0, + 16, 0x2F94, 0x8A00, 0, + 16, 0x2F95, 0x8C37, 0, + 16, 0x2F96, 0x8C46, 0, + 16, 0x2F97, 0x8C55, 0, + 16, 0x2F98, 0x8C78, 0, + 16, 0x2F99, 0x8C9D, 0, + 16, 0x2F9A, 0x8D64, 0, + 16, 0x2F9B, 0x8D70, 0, + 16, 0x2F9C, 0x8DB3, 0, + 16, 0x2F9D, 0x8EAB, 0, + 16, 0x2F9E, 0x8ECA, 0, + 16, 0x2F9F, 0x8F9B, 0, + 16, 0x2FA0, 0x8FB0, 0, + 16, 0x2FA1, 0x8FB5, 0, + 16, 0x2FA2, 0x9091, 0, + 16, 0x2FA3, 0x9149, 0, + 16, 0x2FA4, 0x91C6, 0, + 16, 0x2FA5, 0x91CC, 0, + 16, 0x2FA6, 0x91D1, 0, + 16, 0x2FA7, 0x9577, 0, + 16, 0x2FA8, 0x9580, 0, + 16, 0x2FA9, 0x961C, 0, + 16, 0x2FAA, 0x96B6, 0, + 16, 0x2FAB, 0x96B9, 0, + 16, 0x2FAC, 0x96E8, 0, + 16, 0x2FAD, 0x9751, 0, + 16, 0x2FAE, 0x975E, 0, + 16, 0x2FAF, 0x9762, 0, + 16, 0x2FB0, 0x9769, 0, + 16, 0x2FB1, 0x97CB, 0, + 16, 0x2FB2, 0x97ED, 0, + 16, 0x2FB3, 0x97F3, 0, + 16, 0x2FB4, 0x9801, 0, + 16, 0x2FB5, 0x98A8, 0, + 16, 0x2FB6, 0x98DB, 0, + 16, 0x2FB7, 0x98DF, 0, + 16, 0x2FB8, 0x9996, 0, + 16, 0x2FB9, 0x9999, 0, + 16, 0x2FBA, 0x99AC, 0, + 16, 0x2FBB, 0x9AA8, 0, + 16, 0x2FBC, 0x9AD8, 0, + 16, 0x2FBD, 0x9ADF, 0, + 16, 0x2FBE, 0x9B25, 0, + 16, 0x2FBF, 0x9B2F, 0, + 16, 0x2FC0, 0x9B32, 0, + 16, 0x2FC1, 0x9B3C, 0, + 16, 0x2FC2, 0x9B5A, 0, + 16, 0x2FC3, 0x9CE5, 0, + 16, 0x2FC4, 0x9E75, 0, + 16, 0x2FC5, 0x9E7F, 0, + 16, 0x2FC6, 0x9EA5, 0, + 16, 0x2FC7, 0x9EBB, 0, + 16, 0x2FC8, 0x9EC3, 0, + 16, 0x2FC9, 0x9ECD, 0, + 16, 0x2FCA, 0x9ED1, 0, + 16, 0x2FCB, 0x9EF9, 0, + 16, 0x2FCC, 0x9EFD, 0, + 16, 0x2FCD, 0x9F0E, 0, + 16, 0x2FCE, 0x9F13, 0, + 16, 0x2FCF, 0x9F20, 0, + 16, 0x2FD0, 0x9F3B, 0, + 16, 0x2FD1, 0x9F4A, 0, + 16, 0x2FD2, 0x9F52, 0, + 16, 0x2FD3, 0x9F8D, 0, + 16, 0x2FD4, 0x9F9C, 0, + 16, 0x2FD5, 0x9FA0, 0, + 12, 0x3000, 0x0020, 0, + 16, 0x3036, 0x3012, 0, + 16, 0x3038, 0x5341, 0, + 16, 0x3039, 0x5344, 0, + 16, 0x303A, 0x5345, 0, + 1, 0x304C, 0x304B, 0x3099, 0, + 1, 0x304E, 0x304D, 0x3099, 0, + 1, 0x3050, 0x304F, 0x3099, 0, + 1, 0x3052, 0x3051, 0x3099, 0, + 1, 0x3054, 0x3053, 0x3099, 0, + 1, 0x3056, 0x3055, 0x3099, 0, + 1, 0x3058, 0x3057, 0x3099, 0, + 1, 0x305A, 0x3059, 0x3099, 0, + 1, 0x305C, 0x305B, 0x3099, 0, + 1, 0x305E, 0x305D, 0x3099, 0, + 1, 0x3060, 0x305F, 0x3099, 0, + 1, 0x3062, 0x3061, 0x3099, 0, + 1, 0x3065, 0x3064, 0x3099, 0, + 1, 0x3067, 0x3066, 0x3099, 0, + 1, 0x3069, 0x3068, 0x3099, 0, + 1, 0x3070, 0x306F, 0x3099, 0, + 1, 0x3071, 0x306F, 0x309A, 0, + 1, 0x3073, 0x3072, 0x3099, 0, + 1, 0x3074, 0x3072, 0x309A, 0, + 1, 0x3076, 0x3075, 0x3099, 0, + 1, 0x3077, 0x3075, 0x309A, 0, + 1, 0x3079, 0x3078, 0x3099, 0, + 1, 0x307A, 0x3078, 0x309A, 0, + 1, 0x307C, 0x307B, 0x3099, 0, + 1, 0x307D, 0x307B, 0x309A, 0, + 1, 0x3094, 0x3046, 0x3099, 0, + 16, 0x309B, 0x0020, 0x3099, 0, + 16, 0x309C, 0x0020, 0x309A, 0, + 1, 0x309E, 0x309D, 0x3099, 0, + 1, 0x30AC, 0x30AB, 0x3099, 0, + 1, 0x30AE, 0x30AD, 0x3099, 0, + 1, 0x30B0, 0x30AF, 0x3099, 0, + 1, 0x30B2, 0x30B1, 0x3099, 0, + 1, 0x30B4, 0x30B3, 0x3099, 0, + 1, 0x30B6, 0x30B5, 0x3099, 0, + 1, 0x30B8, 0x30B7, 0x3099, 0, + 1, 0x30BA, 0x30B9, 0x3099, 0, + 1, 0x30BC, 0x30BB, 0x3099, 0, + 1, 0x30BE, 0x30BD, 0x3099, 0, + 1, 0x30C0, 0x30BF, 0x3099, 0, + 1, 0x30C2, 0x30C1, 0x3099, 0, + 1, 0x30C5, 0x30C4, 0x3099, 0, + 1, 0x30C7, 0x30C6, 0x3099, 0, + 1, 0x30C9, 0x30C8, 0x3099, 0, + 1, 0x30D0, 0x30CF, 0x3099, 0, + 1, 0x30D1, 0x30CF, 0x309A, 0, + 1, 0x30D3, 0x30D2, 0x3099, 0, + 1, 0x30D4, 0x30D2, 0x309A, 0, + 1, 0x30D6, 0x30D5, 0x3099, 0, + 1, 0x30D7, 0x30D5, 0x309A, 0, + 1, 0x30D9, 0x30D8, 0x3099, 0, + 1, 0x30DA, 0x30D8, 0x309A, 0, + 1, 0x30DC, 0x30DB, 0x3099, 0, + 1, 0x30DD, 0x30DB, 0x309A, 0, + 1, 0x30F4, 0x30A6, 0x3099, 0, + 1, 0x30F7, 0x30EF, 0x3099, 0, + 1, 0x30F8, 0x30F0, 0x3099, 0, + 1, 0x30F9, 0x30F1, 0x3099, 0, + 1, 0x30FA, 0x30F2, 0x3099, 0, + 1, 0x30FE, 0x30FD, 0x3099, 0, + 16, 0x3131, 0x1100, 0, + 16, 0x3132, 0x1101, 0, + 16, 0x3133, 0x11AA, 0, + 16, 0x3134, 0x1102, 0, + 16, 0x3135, 0x11AC, 0, + 16, 0x3136, 0x11AD, 0, + 16, 0x3137, 0x1103, 0, + 16, 0x3138, 0x1104, 0, + 16, 0x3139, 0x1105, 0, + 16, 0x313A, 0x11B0, 0, + 16, 0x313B, 0x11B1, 0, + 16, 0x313C, 0x11B2, 0, + 16, 0x313D, 0x11B3, 0, + 16, 0x313E, 0x11B4, 0, + 16, 0x313F, 0x11B5, 0, + 16, 0x3140, 0x111A, 0, + 16, 0x3141, 0x1106, 0, + 16, 0x3142, 0x1107, 0, + 16, 0x3143, 0x1108, 0, + 16, 0x3144, 0x1121, 0, + 16, 0x3145, 0x1109, 0, + 16, 0x3146, 0x110A, 0, + 16, 0x3147, 0x110B, 0, + 16, 0x3148, 0x110C, 0, + 16, 0x3149, 0x110D, 0, + 16, 0x314A, 0x110E, 0, + 16, 0x314B, 0x110F, 0, + 16, 0x314C, 0x1110, 0, + 16, 0x314D, 0x1111, 0, + 16, 0x314E, 0x1112, 0, + 16, 0x314F, 0x1161, 0, + 16, 0x3150, 0x1162, 0, + 16, 0x3151, 0x1163, 0, + 16, 0x3152, 0x1164, 0, + 16, 0x3153, 0x1165, 0, + 16, 0x3154, 0x1166, 0, + 16, 0x3155, 0x1167, 0, + 16, 0x3156, 0x1168, 0, + 16, 0x3157, 0x1169, 0, + 16, 0x3158, 0x116A, 0, + 16, 0x3159, 0x116B, 0, + 16, 0x315A, 0x116C, 0, + 16, 0x315B, 0x116D, 0, + 16, 0x315C, 0x116E, 0, + 16, 0x315D, 0x116F, 0, + 16, 0x315E, 0x1170, 0, + 16, 0x315F, 0x1171, 0, + 16, 0x3160, 0x1172, 0, + 16, 0x3161, 0x1173, 0, + 16, 0x3162, 0x1174, 0, + 16, 0x3163, 0x1175, 0, + 16, 0x3164, 0x1160, 0, + 16, 0x3165, 0x1114, 0, + 16, 0x3166, 0x1115, 0, + 16, 0x3167, 0x11C7, 0, + 16, 0x3168, 0x11C8, 0, + 16, 0x3169, 0x11CC, 0, + 16, 0x316A, 0x11CE, 0, + 16, 0x316B, 0x11D3, 0, + 16, 0x316C, 0x11D7, 0, + 16, 0x316D, 0x11D9, 0, + 16, 0x316E, 0x111C, 0, + 16, 0x316F, 0x11DD, 0, + 16, 0x3170, 0x11DF, 0, + 16, 0x3171, 0x111D, 0, + 16, 0x3172, 0x111E, 0, + 16, 0x3173, 0x1120, 0, + 16, 0x3174, 0x1122, 0, + 16, 0x3175, 0x1123, 0, + 16, 0x3176, 0x1127, 0, + 16, 0x3177, 0x1129, 0, + 16, 0x3178, 0x112B, 0, + 16, 0x3179, 0x112C, 0, + 16, 0x317A, 0x112D, 0, + 16, 0x317B, 0x112E, 0, + 16, 0x317C, 0x112F, 0, + 16, 0x317D, 0x1132, 0, + 16, 0x317E, 0x1136, 0, + 16, 0x317F, 0x1140, 0, + 16, 0x3180, 0x1147, 0, + 16, 0x3181, 0x114C, 0, + 16, 0x3182, 0x11F1, 0, + 16, 0x3183, 0x11F2, 0, + 16, 0x3184, 0x1157, 0, + 16, 0x3185, 0x1158, 0, + 16, 0x3186, 0x1159, 0, + 16, 0x3187, 0x1184, 0, + 16, 0x3188, 0x1185, 0, + 16, 0x3189, 0x1188, 0, + 16, 0x318A, 0x1191, 0, + 16, 0x318B, 0x1192, 0, + 16, 0x318C, 0x1194, 0, + 16, 0x318D, 0x119E, 0, + 16, 0x318E, 0x11A1, 0, + 9, 0x3192, 0x4E00, 0, + 9, 0x3193, 0x4E8C, 0, + 9, 0x3194, 0x4E09, 0, + 9, 0x3195, 0x56DB, 0, + 9, 0x3196, 0x4E0A, 0, + 9, 0x3197, 0x4E2D, 0, + 9, 0x3198, 0x4E0B, 0, + 9, 0x3199, 0x7532, 0, + 9, 0x319A, 0x4E59, 0, + 9, 0x319B, 0x4E19, 0, + 9, 0x319C, 0x4E01, 0, + 9, 0x319D, 0x5929, 0, + 9, 0x319E, 0x5730, 0, + 9, 0x319F, 0x4EBA, 0, + 16, 0x3200, 0x0028, 0x1100, 0x0029, 0, + 16, 0x3201, 0x0028, 0x1102, 0x0029, 0, + 16, 0x3202, 0x0028, 0x1103, 0x0029, 0, + 16, 0x3203, 0x0028, 0x1105, 0x0029, 0, + 16, 0x3204, 0x0028, 0x1106, 0x0029, 0, + 16, 0x3205, 0x0028, 0x1107, 0x0029, 0, + 16, 0x3206, 0x0028, 0x1109, 0x0029, 0, + 16, 0x3207, 0x0028, 0x110B, 0x0029, 0, + 16, 0x3208, 0x0028, 0x110C, 0x0029, 0, + 16, 0x3209, 0x0028, 0x110E, 0x0029, 0, + 16, 0x320A, 0x0028, 0x110F, 0x0029, 0, + 16, 0x320B, 0x0028, 0x1110, 0x0029, 0, + 16, 0x320C, 0x0028, 0x1111, 0x0029, 0, + 16, 0x320D, 0x0028, 0x1112, 0x0029, 0, + 16, 0x320E, 0x0028, 0x1100, 0x1161, 0x0029, 0, + 16, 0x320F, 0x0028, 0x1102, 0x1161, 0x0029, 0, + 16, 0x3210, 0x0028, 0x1103, 0x1161, 0x0029, 0, + 16, 0x3211, 0x0028, 0x1105, 0x1161, 0x0029, 0, + 16, 0x3212, 0x0028, 0x1106, 0x1161, 0x0029, 0, + 16, 0x3213, 0x0028, 0x1107, 0x1161, 0x0029, 0, + 16, 0x3214, 0x0028, 0x1109, 0x1161, 0x0029, 0, + 16, 0x3215, 0x0028, 0x110B, 0x1161, 0x0029, 0, + 16, 0x3216, 0x0028, 0x110C, 0x1161, 0x0029, 0, + 16, 0x3217, 0x0028, 0x110E, 0x1161, 0x0029, 0, + 16, 0x3218, 0x0028, 0x110F, 0x1161, 0x0029, 0, + 16, 0x3219, 0x0028, 0x1110, 0x1161, 0x0029, 0, + 16, 0x321A, 0x0028, 0x1111, 0x1161, 0x0029, 0, + 16, 0x321B, 0x0028, 0x1112, 0x1161, 0x0029, 0, + 16, 0x321C, 0x0028, 0x110C, 0x116E, 0x0029, 0, + 16, 0x3220, 0x0028, 0x4E00, 0x0029, 0, + 16, 0x3221, 0x0028, 0x4E8C, 0x0029, 0, + 16, 0x3222, 0x0028, 0x4E09, 0x0029, 0, + 16, 0x3223, 0x0028, 0x56DB, 0x0029, 0, + 16, 0x3224, 0x0028, 0x4E94, 0x0029, 0, + 16, 0x3225, 0x0028, 0x516D, 0x0029, 0, + 16, 0x3226, 0x0028, 0x4E03, 0x0029, 0, + 16, 0x3227, 0x0028, 0x516B, 0x0029, 0, + 16, 0x3228, 0x0028, 0x4E5D, 0x0029, 0, + 16, 0x3229, 0x0028, 0x5341, 0x0029, 0, + 16, 0x322A, 0x0028, 0x6708, 0x0029, 0, + 16, 0x322B, 0x0028, 0x706B, 0x0029, 0, + 16, 0x322C, 0x0028, 0x6C34, 0x0029, 0, + 16, 0x322D, 0x0028, 0x6728, 0x0029, 0, + 16, 0x322E, 0x0028, 0x91D1, 0x0029, 0, + 16, 0x322F, 0x0028, 0x571F, 0x0029, 0, + 16, 0x3230, 0x0028, 0x65E5, 0x0029, 0, + 16, 0x3231, 0x0028, 0x682A, 0x0029, 0, + 16, 0x3232, 0x0028, 0x6709, 0x0029, 0, + 16, 0x3233, 0x0028, 0x793E, 0x0029, 0, + 16, 0x3234, 0x0028, 0x540D, 0x0029, 0, + 16, 0x3235, 0x0028, 0x7279, 0x0029, 0, + 16, 0x3236, 0x0028, 0x8CA1, 0x0029, 0, + 16, 0x3237, 0x0028, 0x795D, 0x0029, 0, + 16, 0x3238, 0x0028, 0x52B4, 0x0029, 0, + 16, 0x3239, 0x0028, 0x4EE3, 0x0029, 0, + 16, 0x323A, 0x0028, 0x547C, 0x0029, 0, + 16, 0x323B, 0x0028, 0x5B66, 0x0029, 0, + 16, 0x323C, 0x0028, 0x76E3, 0x0029, 0, + 16, 0x323D, 0x0028, 0x4F01, 0x0029, 0, + 16, 0x323E, 0x0028, 0x8CC7, 0x0029, 0, + 16, 0x323F, 0x0028, 0x5354, 0x0029, 0, + 16, 0x3240, 0x0028, 0x796D, 0x0029, 0, + 16, 0x3241, 0x0028, 0x4F11, 0x0029, 0, + 16, 0x3242, 0x0028, 0x81EA, 0x0029, 0, + 16, 0x3243, 0x0028, 0x81F3, 0x0029, 0, + 8, 0x3260, 0x1100, 0, + 8, 0x3261, 0x1102, 0, + 8, 0x3262, 0x1103, 0, + 8, 0x3263, 0x1105, 0, + 8, 0x3264, 0x1106, 0, + 8, 0x3265, 0x1107, 0, + 8, 0x3266, 0x1109, 0, + 8, 0x3267, 0x110B, 0, + 8, 0x3268, 0x110C, 0, + 8, 0x3269, 0x110E, 0, + 8, 0x326A, 0x110F, 0, + 8, 0x326B, 0x1110, 0, + 8, 0x326C, 0x1111, 0, + 8, 0x326D, 0x1112, 0, + 8, 0x326E, 0x1100, 0x1161, 0, + 8, 0x326F, 0x1102, 0x1161, 0, + 8, 0x3270, 0x1103, 0x1161, 0, + 8, 0x3271, 0x1105, 0x1161, 0, + 8, 0x3272, 0x1106, 0x1161, 0, + 8, 0x3273, 0x1107, 0x1161, 0, + 8, 0x3274, 0x1109, 0x1161, 0, + 8, 0x3275, 0x110B, 0x1161, 0, + 8, 0x3276, 0x110C, 0x1161, 0, + 8, 0x3277, 0x110E, 0x1161, 0, + 8, 0x3278, 0x110F, 0x1161, 0, + 8, 0x3279, 0x1110, 0x1161, 0, + 8, 0x327A, 0x1111, 0x1161, 0, + 8, 0x327B, 0x1112, 0x1161, 0, + 8, 0x3280, 0x4E00, 0, + 8, 0x3281, 0x4E8C, 0, + 8, 0x3282, 0x4E09, 0, + 8, 0x3283, 0x56DB, 0, + 8, 0x3284, 0x4E94, 0, + 8, 0x3285, 0x516D, 0, + 8, 0x3286, 0x4E03, 0, + 8, 0x3287, 0x516B, 0, + 8, 0x3288, 0x4E5D, 0, + 8, 0x3289, 0x5341, 0, + 8, 0x328A, 0x6708, 0, + 8, 0x328B, 0x706B, 0, + 8, 0x328C, 0x6C34, 0, + 8, 0x328D, 0x6728, 0, + 8, 0x328E, 0x91D1, 0, + 8, 0x328F, 0x571F, 0, + 8, 0x3290, 0x65E5, 0, + 8, 0x3291, 0x682A, 0, + 8, 0x3292, 0x6709, 0, + 8, 0x3293, 0x793E, 0, + 8, 0x3294, 0x540D, 0, + 8, 0x3295, 0x7279, 0, + 8, 0x3296, 0x8CA1, 0, + 8, 0x3297, 0x795D, 0, + 8, 0x3298, 0x52B4, 0, + 8, 0x3299, 0x79D8, 0, + 8, 0x329A, 0x7537, 0, + 8, 0x329B, 0x5973, 0, + 8, 0x329C, 0x9069, 0, + 8, 0x329D, 0x512A, 0, + 8, 0x329E, 0x5370, 0, + 8, 0x329F, 0x6CE8, 0, + 8, 0x32A0, 0x9805, 0, + 8, 0x32A1, 0x4F11, 0, + 8, 0x32A2, 0x5199, 0, + 8, 0x32A3, 0x6B63, 0, + 8, 0x32A4, 0x4E0A, 0, + 8, 0x32A5, 0x4E2D, 0, + 8, 0x32A6, 0x4E0B, 0, + 8, 0x32A7, 0x5DE6, 0, + 8, 0x32A8, 0x53F3, 0, + 8, 0x32A9, 0x533B, 0, + 8, 0x32AA, 0x5B97, 0, + 8, 0x32AB, 0x5B66, 0, + 8, 0x32AC, 0x76E3, 0, + 8, 0x32AD, 0x4F01, 0, + 8, 0x32AE, 0x8CC7, 0, + 8, 0x32AF, 0x5354, 0, + 8, 0x32B0, 0x591C, 0, + 16, 0x32C0, 0x0031, 0x6708, 0, + 16, 0x32C1, 0x0032, 0x6708, 0, + 16, 0x32C2, 0x0033, 0x6708, 0, + 16, 0x32C3, 0x0034, 0x6708, 0, + 16, 0x32C4, 0x0035, 0x6708, 0, + 16, 0x32C5, 0x0036, 0x6708, 0, + 16, 0x32C6, 0x0037, 0x6708, 0, + 16, 0x32C7, 0x0038, 0x6708, 0, + 16, 0x32C8, 0x0039, 0x6708, 0, + 16, 0x32C9, 0x0031, 0x0030, 0x6708, 0, + 16, 0x32CA, 0x0031, 0x0031, 0x6708, 0, + 16, 0x32CB, 0x0031, 0x0032, 0x6708, 0, + 8, 0x32D0, 0x30A2, 0, + 8, 0x32D1, 0x30A4, 0, + 8, 0x32D2, 0x30A6, 0, + 8, 0x32D3, 0x30A8, 0, + 8, 0x32D4, 0x30AA, 0, + 8, 0x32D5, 0x30AB, 0, + 8, 0x32D6, 0x30AD, 0, + 8, 0x32D7, 0x30AF, 0, + 8, 0x32D8, 0x30B1, 0, + 8, 0x32D9, 0x30B3, 0, + 8, 0x32DA, 0x30B5, 0, + 8, 0x32DB, 0x30B7, 0, + 8, 0x32DC, 0x30B9, 0, + 8, 0x32DD, 0x30BB, 0, + 8, 0x32DE, 0x30BD, 0, + 8, 0x32DF, 0x30BF, 0, + 8, 0x32E0, 0x30C1, 0, + 8, 0x32E1, 0x30C4, 0, + 8, 0x32E2, 0x30C6, 0, + 8, 0x32E3, 0x30C8, 0, + 8, 0x32E4, 0x30CA, 0, + 8, 0x32E5, 0x30CB, 0, + 8, 0x32E6, 0x30CC, 0, + 8, 0x32E7, 0x30CD, 0, + 8, 0x32E8, 0x30CE, 0, + 8, 0x32E9, 0x30CF, 0, + 8, 0x32EA, 0x30D2, 0, + 8, 0x32EB, 0x30D5, 0, + 8, 0x32EC, 0x30D8, 0, + 8, 0x32ED, 0x30DB, 0, + 8, 0x32EE, 0x30DE, 0, + 8, 0x32EF, 0x30DF, 0, + 8, 0x32F0, 0x30E0, 0, + 8, 0x32F1, 0x30E1, 0, + 8, 0x32F2, 0x30E2, 0, + 8, 0x32F3, 0x30E4, 0, + 8, 0x32F4, 0x30E6, 0, + 8, 0x32F5, 0x30E8, 0, + 8, 0x32F6, 0x30E9, 0, + 8, 0x32F7, 0x30EA, 0, + 8, 0x32F8, 0x30EB, 0, + 8, 0x32F9, 0x30EC, 0, + 8, 0x32FA, 0x30ED, 0, + 8, 0x32FB, 0x30EF, 0, + 8, 0x32FC, 0x30F0, 0, + 8, 0x32FD, 0x30F1, 0, + 8, 0x32FE, 0x30F2, 0, + 15, 0x3300, 0x30A2, 0x30D1, 0x30FC, 0x30C8, 0, + 15, 0x3301, 0x30A2, 0x30EB, 0x30D5, 0x30A1, 0, + 15, 0x3302, 0x30A2, 0x30F3, 0x30DA, 0x30A2, 0, + 15, 0x3303, 0x30A2, 0x30FC, 0x30EB, 0, + 15, 0x3304, 0x30A4, 0x30CB, 0x30F3, 0x30B0, 0, + 15, 0x3305, 0x30A4, 0x30F3, 0x30C1, 0, + 15, 0x3306, 0x30A6, 0x30A9, 0x30F3, 0, + 15, 0x3307, 0x30A8, 0x30B9, 0x30AF, 0x30FC, 0x30C9, 0, + 15, 0x3308, 0x30A8, 0x30FC, 0x30AB, 0x30FC, 0, + 15, 0x3309, 0x30AA, 0x30F3, 0x30B9, 0, + 15, 0x330A, 0x30AA, 0x30FC, 0x30E0, 0, + 15, 0x330B, 0x30AB, 0x30A4, 0x30EA, 0, + 15, 0x330C, 0x30AB, 0x30E9, 0x30C3, 0x30C8, 0, + 15, 0x330D, 0x30AB, 0x30ED, 0x30EA, 0x30FC, 0, + 15, 0x330E, 0x30AC, 0x30ED, 0x30F3, 0, + 15, 0x330F, 0x30AC, 0x30F3, 0x30DE, 0, + 15, 0x3310, 0x30AE, 0x30AC, 0, + 15, 0x3311, 0x30AE, 0x30CB, 0x30FC, 0, + 15, 0x3312, 0x30AD, 0x30E5, 0x30EA, 0x30FC, 0, + 15, 0x3313, 0x30AE, 0x30EB, 0x30C0, 0x30FC, 0, + 15, 0x3314, 0x30AD, 0x30ED, 0, + 15, 0x3315, 0x30AD, 0x30ED, 0x30B0, 0x30E9, 0x30E0, 0, + 15, 0x3316, 0x30AD, 0x30ED, 0x30E1, 0x30FC, 0x30C8, 0x30EB, 0, + 15, 0x3317, 0x30AD, 0x30ED, 0x30EF, 0x30C3, 0x30C8, 0, + 15, 0x3318, 0x30B0, 0x30E9, 0x30E0, 0, + 15, 0x3319, 0x30B0, 0x30E9, 0x30E0, 0x30C8, 0x30F3, 0, + 15, 0x331A, 0x30AF, 0x30EB, 0x30BC, 0x30A4, 0x30ED, 0, + 15, 0x331B, 0x30AF, 0x30ED, 0x30FC, 0x30CD, 0, + 15, 0x331C, 0x30B1, 0x30FC, 0x30B9, 0, + 15, 0x331D, 0x30B3, 0x30EB, 0x30CA, 0, + 15, 0x331E, 0x30B3, 0x30FC, 0x30DD, 0, + 15, 0x331F, 0x30B5, 0x30A4, 0x30AF, 0x30EB, 0, + 15, 0x3320, 0x30B5, 0x30F3, 0x30C1, 0x30FC, 0x30E0, 0, + 15, 0x3321, 0x30B7, 0x30EA, 0x30F3, 0x30B0, 0, + 15, 0x3322, 0x30BB, 0x30F3, 0x30C1, 0, + 15, 0x3323, 0x30BB, 0x30F3, 0x30C8, 0, + 15, 0x3324, 0x30C0, 0x30FC, 0x30B9, 0, + 15, 0x3325, 0x30C7, 0x30B7, 0, + 15, 0x3326, 0x30C9, 0x30EB, 0, + 15, 0x3327, 0x30C8, 0x30F3, 0, + 15, 0x3328, 0x30CA, 0x30CE, 0, + 15, 0x3329, 0x30CE, 0x30C3, 0x30C8, 0, + 15, 0x332A, 0x30CF, 0x30A4, 0x30C4, 0, + 15, 0x332B, 0x30D1, 0x30FC, 0x30BB, 0x30F3, 0x30C8, 0, + 15, 0x332C, 0x30D1, 0x30FC, 0x30C4, 0, + 15, 0x332D, 0x30D0, 0x30FC, 0x30EC, 0x30EB, 0, + 15, 0x332E, 0x30D4, 0x30A2, 0x30B9, 0x30C8, 0x30EB, 0, + 15, 0x332F, 0x30D4, 0x30AF, 0x30EB, 0, + 15, 0x3330, 0x30D4, 0x30B3, 0, + 15, 0x3331, 0x30D3, 0x30EB, 0, + 15, 0x3332, 0x30D5, 0x30A1, 0x30E9, 0x30C3, 0x30C9, 0, + 15, 0x3333, 0x30D5, 0x30A3, 0x30FC, 0x30C8, 0, + 15, 0x3334, 0x30D6, 0x30C3, 0x30B7, 0x30A7, 0x30EB, 0, + 15, 0x3335, 0x30D5, 0x30E9, 0x30F3, 0, + 15, 0x3336, 0x30D8, 0x30AF, 0x30BF, 0x30FC, 0x30EB, 0, + 15, 0x3337, 0x30DA, 0x30BD, 0, + 15, 0x3338, 0x30DA, 0x30CB, 0x30D2, 0, + 15, 0x3339, 0x30D8, 0x30EB, 0x30C4, 0, + 15, 0x333A, 0x30DA, 0x30F3, 0x30B9, 0, + 15, 0x333B, 0x30DA, 0x30FC, 0x30B8, 0, + 15, 0x333C, 0x30D9, 0x30FC, 0x30BF, 0, + 15, 0x333D, 0x30DD, 0x30A4, 0x30F3, 0x30C8, 0, + 15, 0x333E, 0x30DC, 0x30EB, 0x30C8, 0, + 15, 0x333F, 0x30DB, 0x30F3, 0, + 15, 0x3340, 0x30DD, 0x30F3, 0x30C9, 0, + 15, 0x3341, 0x30DB, 0x30FC, 0x30EB, 0, + 15, 0x3342, 0x30DB, 0x30FC, 0x30F3, 0, + 15, 0x3343, 0x30DE, 0x30A4, 0x30AF, 0x30ED, 0, + 15, 0x3344, 0x30DE, 0x30A4, 0x30EB, 0, + 15, 0x3345, 0x30DE, 0x30C3, 0x30CF, 0, + 15, 0x3346, 0x30DE, 0x30EB, 0x30AF, 0, + 15, 0x3347, 0x30DE, 0x30F3, 0x30B7, 0x30E7, 0x30F3, 0, + 15, 0x3348, 0x30DF, 0x30AF, 0x30ED, 0x30F3, 0, + 15, 0x3349, 0x30DF, 0x30EA, 0, + 15, 0x334A, 0x30DF, 0x30EA, 0x30D0, 0x30FC, 0x30EB, 0, + 15, 0x334B, 0x30E1, 0x30AC, 0, + 15, 0x334C, 0x30E1, 0x30AC, 0x30C8, 0x30F3, 0, + 15, 0x334D, 0x30E1, 0x30FC, 0x30C8, 0x30EB, 0, + 15, 0x334E, 0x30E4, 0x30FC, 0x30C9, 0, + 15, 0x334F, 0x30E4, 0x30FC, 0x30EB, 0, + 15, 0x3350, 0x30E6, 0x30A2, 0x30F3, 0, + 15, 0x3351, 0x30EA, 0x30C3, 0x30C8, 0x30EB, 0, + 15, 0x3352, 0x30EA, 0x30E9, 0, + 15, 0x3353, 0x30EB, 0x30D4, 0x30FC, 0, + 15, 0x3354, 0x30EB, 0x30FC, 0x30D6, 0x30EB, 0, + 15, 0x3355, 0x30EC, 0x30E0, 0, + 15, 0x3356, 0x30EC, 0x30F3, 0x30C8, 0x30B2, 0x30F3, 0, + 15, 0x3357, 0x30EF, 0x30C3, 0x30C8, 0, + 16, 0x3358, 0x0030, 0x70B9, 0, + 16, 0x3359, 0x0031, 0x70B9, 0, + 16, 0x335A, 0x0032, 0x70B9, 0, + 16, 0x335B, 0x0033, 0x70B9, 0, + 16, 0x335C, 0x0034, 0x70B9, 0, + 16, 0x335D, 0x0035, 0x70B9, 0, + 16, 0x335E, 0x0036, 0x70B9, 0, + 16, 0x335F, 0x0037, 0x70B9, 0, + 16, 0x3360, 0x0038, 0x70B9, 0, + 16, 0x3361, 0x0039, 0x70B9, 0, + 16, 0x3362, 0x0031, 0x0030, 0x70B9, 0, + 16, 0x3363, 0x0031, 0x0031, 0x70B9, 0, + 16, 0x3364, 0x0031, 0x0032, 0x70B9, 0, + 16, 0x3365, 0x0031, 0x0033, 0x70B9, 0, + 16, 0x3366, 0x0031, 0x0034, 0x70B9, 0, + 16, 0x3367, 0x0031, 0x0035, 0x70B9, 0, + 16, 0x3368, 0x0031, 0x0036, 0x70B9, 0, + 16, 0x3369, 0x0031, 0x0037, 0x70B9, 0, + 16, 0x336A, 0x0031, 0x0038, 0x70B9, 0, + 16, 0x336B, 0x0031, 0x0039, 0x70B9, 0, + 16, 0x336C, 0x0032, 0x0030, 0x70B9, 0, + 16, 0x336D, 0x0032, 0x0031, 0x70B9, 0, + 16, 0x336E, 0x0032, 0x0032, 0x70B9, 0, + 16, 0x336F, 0x0032, 0x0033, 0x70B9, 0, + 16, 0x3370, 0x0032, 0x0034, 0x70B9, 0, + 15, 0x3371, 0x0068, 0x0050, 0x0061, 0, + 15, 0x3372, 0x0064, 0x0061, 0, + 15, 0x3373, 0x0041, 0x0055, 0, + 15, 0x3374, 0x0062, 0x0061, 0x0072, 0, + 15, 0x3375, 0x006F, 0x0056, 0, + 15, 0x3376, 0x0070, 0x0063, 0, + 15, 0x337B, 0x5E73, 0x6210, 0, + 15, 0x337C, 0x662D, 0x548C, 0, + 15, 0x337D, 0x5927, 0x6B63, 0, + 15, 0x337E, 0x660E, 0x6CBB, 0, + 15, 0x337F, 0x682A, 0x5F0F, 0x4F1A, 0x793E, 0, + 15, 0x3380, 0x0070, 0x0041, 0, + 15, 0x3381, 0x006E, 0x0041, 0, + 15, 0x3382, 0x03BC, 0x0041, 0, + 15, 0x3383, 0x006D, 0x0041, 0, + 15, 0x3384, 0x006B, 0x0041, 0, + 15, 0x3385, 0x004B, 0x0042, 0, + 15, 0x3386, 0x004D, 0x0042, 0, + 15, 0x3387, 0x0047, 0x0042, 0, + 15, 0x3388, 0x0063, 0x0061, 0x006C, 0, + 15, 0x3389, 0x006B, 0x0063, 0x0061, 0x006C, 0, + 15, 0x338A, 0x0070, 0x0046, 0, + 15, 0x338B, 0x006E, 0x0046, 0, + 15, 0x338C, 0x03BC, 0x0046, 0, + 15, 0x338D, 0x03BC, 0x0067, 0, + 15, 0x338E, 0x006D, 0x0067, 0, + 15, 0x338F, 0x006B, 0x0067, 0, + 15, 0x3390, 0x0048, 0x007A, 0, + 15, 0x3391, 0x006B, 0x0048, 0x007A, 0, + 15, 0x3392, 0x004D, 0x0048, 0x007A, 0, + 15, 0x3393, 0x0047, 0x0048, 0x007A, 0, + 15, 0x3394, 0x0054, 0x0048, 0x007A, 0, + 15, 0x3395, 0x03BC, 0x2113, 0, + 15, 0x3396, 0x006D, 0x2113, 0, + 15, 0x3397, 0x0064, 0x2113, 0, + 15, 0x3398, 0x006B, 0x2113, 0, + 15, 0x3399, 0x0066, 0x006D, 0, + 15, 0x339A, 0x006E, 0x006D, 0, + 15, 0x339B, 0x03BC, 0x006D, 0, + 15, 0x339C, 0x006D, 0x006D, 0, + 15, 0x339D, 0x0063, 0x006D, 0, + 15, 0x339E, 0x006B, 0x006D, 0, + 15, 0x339F, 0x006D, 0x006D, 0x00B2, 0, + 15, 0x33A0, 0x0063, 0x006D, 0x00B2, 0, + 15, 0x33A1, 0x006D, 0x00B2, 0, + 15, 0x33A2, 0x006B, 0x006D, 0x00B2, 0, + 15, 0x33A3, 0x006D, 0x006D, 0x00B3, 0, + 15, 0x33A4, 0x0063, 0x006D, 0x00B3, 0, + 15, 0x33A5, 0x006D, 0x00B3, 0, + 15, 0x33A6, 0x006B, 0x006D, 0x00B3, 0, + 15, 0x33A7, 0x006D, 0x2215, 0x0073, 0, + 15, 0x33A8, 0x006D, 0x2215, 0x0073, 0x00B2, 0, + 15, 0x33A9, 0x0050, 0x0061, 0, + 15, 0x33AA, 0x006B, 0x0050, 0x0061, 0, + 15, 0x33AB, 0x004D, 0x0050, 0x0061, 0, + 15, 0x33AC, 0x0047, 0x0050, 0x0061, 0, + 15, 0x33AD, 0x0072, 0x0061, 0x0064, 0, + 15, 0x33AE, 0x0072, 0x0061, 0x0064, 0x2215, 0x0073, 0, + 15, 0x33AF, 0x0072, 0x0061, 0x0064, 0x2215, 0x0073, 0x00B2, 0, + 15, 0x33B0, 0x0070, 0x0073, 0, + 15, 0x33B1, 0x006E, 0x0073, 0, + 15, 0x33B2, 0x03BC, 0x0073, 0, + 15, 0x33B3, 0x006D, 0x0073, 0, + 15, 0x33B4, 0x0070, 0x0056, 0, + 15, 0x33B5, 0x006E, 0x0056, 0, + 15, 0x33B6, 0x03BC, 0x0056, 0, + 15, 0x33B7, 0x006D, 0x0056, 0, + 15, 0x33B8, 0x006B, 0x0056, 0, + 15, 0x33B9, 0x004D, 0x0056, 0, + 15, 0x33BA, 0x0070, 0x0057, 0, + 15, 0x33BB, 0x006E, 0x0057, 0, + 15, 0x33BC, 0x03BC, 0x0057, 0, + 15, 0x33BD, 0x006D, 0x0057, 0, + 15, 0x33BE, 0x006B, 0x0057, 0, + 15, 0x33BF, 0x004D, 0x0057, 0, + 15, 0x33C0, 0x006B, 0x03A9, 0, + 15, 0x33C1, 0x004D, 0x03A9, 0, + 15, 0x33C2, 0x0061, 0x002E, 0x006D, 0x002E, 0, + 15, 0x33C3, 0x0042, 0x0071, 0, + 15, 0x33C4, 0x0063, 0x0063, 0, + 15, 0x33C5, 0x0063, 0x0064, 0, + 15, 0x33C6, 0x0043, 0x2215, 0x006B, 0x0067, 0, + 15, 0x33C7, 0x0043, 0x006F, 0x002E, 0, + 15, 0x33C8, 0x0064, 0x0042, 0, + 15, 0x33C9, 0x0047, 0x0079, 0, + 15, 0x33CA, 0x0068, 0x0061, 0, + 15, 0x33CB, 0x0048, 0x0050, 0, + 15, 0x33CC, 0x0069, 0x006E, 0, + 15, 0x33CD, 0x004B, 0x004B, 0, + 15, 0x33CE, 0x004B, 0x004D, 0, + 15, 0x33CF, 0x006B, 0x0074, 0, + 15, 0x33D0, 0x006C, 0x006D, 0, + 15, 0x33D1, 0x006C, 0x006E, 0, + 15, 0x33D2, 0x006C, 0x006F, 0x0067, 0, + 15, 0x33D3, 0x006C, 0x0078, 0, + 15, 0x33D4, 0x006D, 0x0062, 0, + 15, 0x33D5, 0x006D, 0x0069, 0x006C, 0, + 15, 0x33D6, 0x006D, 0x006F, 0x006C, 0, + 15, 0x33D7, 0x0050, 0x0048, 0, + 15, 0x33D8, 0x0070, 0x002E, 0x006D, 0x002E, 0, + 15, 0x33D9, 0x0050, 0x0050, 0x004D, 0, + 15, 0x33DA, 0x0050, 0x0052, 0, + 15, 0x33DB, 0x0073, 0x0072, 0, + 15, 0x33DC, 0x0053, 0x0076, 0, + 15, 0x33DD, 0x0057, 0x0062, 0, + 16, 0x33E0, 0x0031, 0x65E5, 0, + 16, 0x33E1, 0x0032, 0x65E5, 0, + 16, 0x33E2, 0x0033, 0x65E5, 0, + 16, 0x33E3, 0x0034, 0x65E5, 0, + 16, 0x33E4, 0x0035, 0x65E5, 0, + 16, 0x33E5, 0x0036, 0x65E5, 0, + 16, 0x33E6, 0x0037, 0x65E5, 0, + 16, 0x33E7, 0x0038, 0x65E5, 0, + 16, 0x33E8, 0x0039, 0x65E5, 0, + 16, 0x33E9, 0x0031, 0x0030, 0x65E5, 0, + 16, 0x33EA, 0x0031, 0x0031, 0x65E5, 0, + 16, 0x33EB, 0x0031, 0x0032, 0x65E5, 0, + 16, 0x33EC, 0x0031, 0x0033, 0x65E5, 0, + 16, 0x33ED, 0x0031, 0x0034, 0x65E5, 0, + 16, 0x33EE, 0x0031, 0x0035, 0x65E5, 0, + 16, 0x33EF, 0x0031, 0x0036, 0x65E5, 0, + 16, 0x33F0, 0x0031, 0x0037, 0x65E5, 0, + 16, 0x33F1, 0x0031, 0x0038, 0x65E5, 0, + 16, 0x33F2, 0x0031, 0x0039, 0x65E5, 0, + 16, 0x33F3, 0x0032, 0x0030, 0x65E5, 0, + 16, 0x33F4, 0x0032, 0x0031, 0x65E5, 0, + 16, 0x33F5, 0x0032, 0x0032, 0x65E5, 0, + 16, 0x33F6, 0x0032, 0x0033, 0x65E5, 0, + 16, 0x33F7, 0x0032, 0x0034, 0x65E5, 0, + 16, 0x33F8, 0x0032, 0x0035, 0x65E5, 0, + 16, 0x33F9, 0x0032, 0x0036, 0x65E5, 0, + 16, 0x33FA, 0x0032, 0x0037, 0x65E5, 0, + 16, 0x33FB, 0x0032, 0x0038, 0x65E5, 0, + 16, 0x33FC, 0x0032, 0x0039, 0x65E5, 0, + 16, 0x33FD, 0x0033, 0x0030, 0x65E5, 0, + 16, 0x33FE, 0x0033, 0x0031, 0x65E5, 0, + 1, 0xF900, 0x8C48, 0, + 1, 0xF901, 0x66F4, 0, + 1, 0xF902, 0x8ECA, 0, + 1, 0xF903, 0x8CC8, 0, + 1, 0xF904, 0x6ED1, 0, + 1, 0xF905, 0x4E32, 0, + 1, 0xF906, 0x53E5, 0, + 1, 0xF907, 0x9F9C, 0, + 1, 0xF908, 0x9F9C, 0, + 1, 0xF909, 0x5951, 0, + 1, 0xF90A, 0x91D1, 0, + 1, 0xF90B, 0x5587, 0, + 1, 0xF90C, 0x5948, 0, + 1, 0xF90D, 0x61F6, 0, + 1, 0xF90E, 0x7669, 0, + 1, 0xF90F, 0x7F85, 0, + 1, 0xF910, 0x863F, 0, + 1, 0xF911, 0x87BA, 0, + 1, 0xF912, 0x88F8, 0, + 1, 0xF913, 0x908F, 0, + 1, 0xF914, 0x6A02, 0, + 1, 0xF915, 0x6D1B, 0, + 1, 0xF916, 0x70D9, 0, + 1, 0xF917, 0x73DE, 0, + 1, 0xF918, 0x843D, 0, + 1, 0xF919, 0x916A, 0, + 1, 0xF91A, 0x99F1, 0, + 1, 0xF91B, 0x4E82, 0, + 1, 0xF91C, 0x5375, 0, + 1, 0xF91D, 0x6B04, 0, + 1, 0xF91E, 0x721B, 0, + 1, 0xF91F, 0x862D, 0, + 1, 0xF920, 0x9E1E, 0, + 1, 0xF921, 0x5D50, 0, + 1, 0xF922, 0x6FEB, 0, + 1, 0xF923, 0x85CD, 0, + 1, 0xF924, 0x8964, 0, + 1, 0xF925, 0x62C9, 0, + 1, 0xF926, 0x81D8, 0, + 1, 0xF927, 0x881F, 0, + 1, 0xF928, 0x5ECA, 0, + 1, 0xF929, 0x6717, 0, + 1, 0xF92A, 0x6D6A, 0, + 1, 0xF92B, 0x72FC, 0, + 1, 0xF92C, 0x90CE, 0, + 1, 0xF92D, 0x4F86, 0, + 1, 0xF92E, 0x51B7, 0, + 1, 0xF92F, 0x52DE, 0, + 1, 0xF930, 0x64C4, 0, + 1, 0xF931, 0x6AD3, 0, + 1, 0xF932, 0x7210, 0, + 1, 0xF933, 0x76E7, 0, + 1, 0xF934, 0x8001, 0, + 1, 0xF935, 0x8606, 0, + 1, 0xF936, 0x865C, 0, + 1, 0xF937, 0x8DEF, 0, + 1, 0xF938, 0x9732, 0, + 1, 0xF939, 0x9B6F, 0, + 1, 0xF93A, 0x9DFA, 0, + 1, 0xF93B, 0x788C, 0, + 1, 0xF93C, 0x797F, 0, + 1, 0xF93D, 0x7DA0, 0, + 1, 0xF93E, 0x83C9, 0, + 1, 0xF93F, 0x9304, 0, + 1, 0xF940, 0x9E7F, 0, + 1, 0xF941, 0x8AD6, 0, + 1, 0xF942, 0x58DF, 0, + 1, 0xF943, 0x5F04, 0, + 1, 0xF944, 0x7C60, 0, + 1, 0xF945, 0x807E, 0, + 1, 0xF946, 0x7262, 0, + 1, 0xF947, 0x78CA, 0, + 1, 0xF948, 0x8CC2, 0, + 1, 0xF949, 0x96F7, 0, + 1, 0xF94A, 0x58D8, 0, + 1, 0xF94B, 0x5C62, 0, + 1, 0xF94C, 0x6A13, 0, + 1, 0xF94D, 0x6DDA, 0, + 1, 0xF94E, 0x6F0F, 0, + 1, 0xF94F, 0x7D2F, 0, + 1, 0xF950, 0x7E37, 0, + 1, 0xF951, 0x96FB, 0, + 1, 0xF952, 0x52D2, 0, + 1, 0xF953, 0x808B, 0, + 1, 0xF954, 0x51DC, 0, + 1, 0xF955, 0x51CC, 0, + 1, 0xF956, 0x7A1C, 0, + 1, 0xF957, 0x7DBE, 0, + 1, 0xF958, 0x83F1, 0, + 1, 0xF959, 0x9675, 0, + 1, 0xF95A, 0x8B80, 0, + 1, 0xF95B, 0x62CF, 0, + 1, 0xF95C, 0x6A02, 0, + 1, 0xF95D, 0x8AFE, 0, + 1, 0xF95E, 0x4E39, 0, + 1, 0xF95F, 0x5BE7, 0, + 1, 0xF960, 0x6012, 0, + 1, 0xF961, 0x7387, 0, + 1, 0xF962, 0x7570, 0, + 1, 0xF963, 0x5317, 0, + 1, 0xF964, 0x78FB, 0, + 1, 0xF965, 0x4FBF, 0, + 1, 0xF966, 0x5FA9, 0, + 1, 0xF967, 0x4E0D, 0, + 1, 0xF968, 0x6CCC, 0, + 1, 0xF969, 0x6578, 0, + 1, 0xF96A, 0x7D22, 0, + 1, 0xF96B, 0x53C3, 0, + 1, 0xF96C, 0x585E, 0, + 1, 0xF96D, 0x7701, 0, + 1, 0xF96E, 0x8449, 0, + 1, 0xF96F, 0x8AAA, 0, + 1, 0xF970, 0x6BBA, 0, + 1, 0xF971, 0x8FB0, 0, + 1, 0xF972, 0x6C88, 0, + 1, 0xF973, 0x62FE, 0, + 1, 0xF974, 0x82E5, 0, + 1, 0xF975, 0x63A0, 0, + 1, 0xF976, 0x7565, 0, + 1, 0xF977, 0x4EAE, 0, + 1, 0xF978, 0x5169, 0, + 1, 0xF979, 0x51C9, 0, + 1, 0xF97A, 0x6881, 0, + 1, 0xF97B, 0x7CE7, 0, + 1, 0xF97C, 0x826F, 0, + 1, 0xF97D, 0x8AD2, 0, + 1, 0xF97E, 0x91CF, 0, + 1, 0xF97F, 0x52F5, 0, + 1, 0xF980, 0x5442, 0, + 1, 0xF981, 0x5973, 0, + 1, 0xF982, 0x5EEC, 0, + 1, 0xF983, 0x65C5, 0, + 1, 0xF984, 0x6FFE, 0, + 1, 0xF985, 0x792A, 0, + 1, 0xF986, 0x95AD, 0, + 1, 0xF987, 0x9A6A, 0, + 1, 0xF988, 0x9E97, 0, + 1, 0xF989, 0x9ECE, 0, + 1, 0xF98A, 0x529B, 0, + 1, 0xF98B, 0x66C6, 0, + 1, 0xF98C, 0x6B77, 0, + 1, 0xF98D, 0x8F62, 0, + 1, 0xF98E, 0x5E74, 0, + 1, 0xF98F, 0x6190, 0, + 1, 0xF990, 0x6200, 0, + 1, 0xF991, 0x649A, 0, + 1, 0xF992, 0x6F23, 0, + 1, 0xF993, 0x7149, 0, + 1, 0xF994, 0x7489, 0, + 1, 0xF995, 0x79CA, 0, + 1, 0xF996, 0x7DF4, 0, + 1, 0xF997, 0x806F, 0, + 1, 0xF998, 0x8F26, 0, + 1, 0xF999, 0x84EE, 0, + 1, 0xF99A, 0x9023, 0, + 1, 0xF99B, 0x934A, 0, + 1, 0xF99C, 0x5217, 0, + 1, 0xF99D, 0x52A3, 0, + 1, 0xF99E, 0x54BD, 0, + 1, 0xF99F, 0x70C8, 0, + 1, 0xF9A0, 0x88C2, 0, + 1, 0xF9A1, 0x8AAA, 0, + 1, 0xF9A2, 0x5EC9, 0, + 1, 0xF9A3, 0x5FF5, 0, + 1, 0xF9A4, 0x637B, 0, + 1, 0xF9A5, 0x6BAE, 0, + 1, 0xF9A6, 0x7C3E, 0, + 1, 0xF9A7, 0x7375, 0, + 1, 0xF9A8, 0x4EE4, 0, + 1, 0xF9A9, 0x56F9, 0, + 1, 0xF9AA, 0x5BE7, 0, + 1, 0xF9AB, 0x5DBA, 0, + 1, 0xF9AC, 0x601C, 0, + 1, 0xF9AD, 0x73B2, 0, + 1, 0xF9AE, 0x7469, 0, + 1, 0xF9AF, 0x7F9A, 0, + 1, 0xF9B0, 0x8046, 0, + 1, 0xF9B1, 0x9234, 0, + 1, 0xF9B2, 0x96F6, 0, + 1, 0xF9B3, 0x9748, 0, + 1, 0xF9B4, 0x9818, 0, + 1, 0xF9B5, 0x4F8B, 0, + 1, 0xF9B6, 0x79AE, 0, + 1, 0xF9B7, 0x91B4, 0, + 1, 0xF9B8, 0x96B8, 0, + 1, 0xF9B9, 0x60E1, 0, + 1, 0xF9BA, 0x4E86, 0, + 1, 0xF9BB, 0x50DA, 0, + 1, 0xF9BC, 0x5BEE, 0, + 1, 0xF9BD, 0x5C3F, 0, + 1, 0xF9BE, 0x6599, 0, + 1, 0xF9BF, 0x6A02, 0, + 1, 0xF9C0, 0x71CE, 0, + 1, 0xF9C1, 0x7642, 0, + 1, 0xF9C2, 0x84FC, 0, + 1, 0xF9C3, 0x907C, 0, + 1, 0xF9C4, 0x9F8D, 0, + 1, 0xF9C5, 0x6688, 0, + 1, 0xF9C6, 0x962E, 0, + 1, 0xF9C7, 0x5289, 0, + 1, 0xF9C8, 0x677B, 0, + 1, 0xF9C9, 0x67F3, 0, + 1, 0xF9CA, 0x6D41, 0, + 1, 0xF9CB, 0x6E9C, 0, + 1, 0xF9CC, 0x7409, 0, + 1, 0xF9CD, 0x7559, 0, + 1, 0xF9CE, 0x786B, 0, + 1, 0xF9CF, 0x7D10, 0, + 1, 0xF9D0, 0x985E, 0, + 1, 0xF9D1, 0x516D, 0, + 1, 0xF9D2, 0x622E, 0, + 1, 0xF9D3, 0x9678, 0, + 1, 0xF9D4, 0x502B, 0, + 1, 0xF9D5, 0x5D19, 0, + 1, 0xF9D6, 0x6DEA, 0, + 1, 0xF9D7, 0x8F2A, 0, + 1, 0xF9D8, 0x5F8B, 0, + 1, 0xF9D9, 0x6144, 0, + 1, 0xF9DA, 0x6817, 0, + 1, 0xF9DB, 0x7387, 0, + 1, 0xF9DC, 0x9686, 0, + 1, 0xF9DD, 0x5229, 0, + 1, 0xF9DE, 0x540F, 0, + 1, 0xF9DF, 0x5C65, 0, + 1, 0xF9E0, 0x6613, 0, + 1, 0xF9E1, 0x674E, 0, + 1, 0xF9E2, 0x68A8, 0, + 1, 0xF9E3, 0x6CE5, 0, + 1, 0xF9E4, 0x7406, 0, + 1, 0xF9E5, 0x75E2, 0, + 1, 0xF9E6, 0x7F79, 0, + 1, 0xF9E7, 0x88CF, 0, + 1, 0xF9E8, 0x88E1, 0, + 1, 0xF9E9, 0x91CC, 0, + 1, 0xF9EA, 0x96E2, 0, + 1, 0xF9EB, 0x533F, 0, + 1, 0xF9EC, 0x6EBA, 0, + 1, 0xF9ED, 0x541D, 0, + 1, 0xF9EE, 0x71D0, 0, + 1, 0xF9EF, 0x7498, 0, + 1, 0xF9F0, 0x85FA, 0, + 1, 0xF9F1, 0x96A3, 0, + 1, 0xF9F2, 0x9C57, 0, + 1, 0xF9F3, 0x9E9F, 0, + 1, 0xF9F4, 0x6797, 0, + 1, 0xF9F5, 0x6DCB, 0, + 1, 0xF9F6, 0x81E8, 0, + 1, 0xF9F7, 0x7ACB, 0, + 1, 0xF9F8, 0x7B20, 0, + 1, 0xF9F9, 0x7C92, 0, + 1, 0xF9FA, 0x72C0, 0, + 1, 0xF9FB, 0x7099, 0, + 1, 0xF9FC, 0x8B58, 0, + 1, 0xF9FD, 0x4EC0, 0, + 1, 0xF9FE, 0x8336, 0, + 1, 0xF9FF, 0x523A, 0, + 1, 0xFA00, 0x5207, 0, + 1, 0xFA01, 0x5EA6, 0, + 1, 0xFA02, 0x62D3, 0, + 1, 0xFA03, 0x7CD6, 0, + 1, 0xFA04, 0x5B85, 0, + 1, 0xFA05, 0x6D1E, 0, + 1, 0xFA06, 0x66B4, 0, + 1, 0xFA07, 0x8F3B, 0, + 1, 0xFA08, 0x884C, 0, + 1, 0xFA09, 0x964D, 0, + 1, 0xFA0A, 0x898B, 0, + 1, 0xFA0B, 0x5ED3, 0, + 1, 0xFA0C, 0x5140, 0, + 1, 0xFA0D, 0x55C0, 0, + 1, 0xFA10, 0x585A, 0, + 1, 0xFA12, 0x6674, 0, + 1, 0xFA15, 0x51DE, 0, + 1, 0xFA16, 0x732A, 0, + 1, 0xFA17, 0x76CA, 0, + 1, 0xFA18, 0x793C, 0, + 1, 0xFA19, 0x795E, 0, + 1, 0xFA1A, 0x7965, 0, + 1, 0xFA1B, 0x798F, 0, + 1, 0xFA1C, 0x9756, 0, + 1, 0xFA1D, 0x7CBE, 0, + 1, 0xFA1E, 0x7FBD, 0, + 1, 0xFA20, 0x8612, 0, + 1, 0xFA22, 0x8AF8, 0, + 1, 0xFA25, 0x9038, 0, + 1, 0xFA26, 0x90FD, 0, + 1, 0xFA2A, 0x98EF, 0, + 1, 0xFA2B, 0x98FC, 0, + 1, 0xFA2C, 0x9928, 0, + 1, 0xFA2D, 0x9DB4, 0, + 16, 0xFB00, 0x0066, 0x0066, 0, + 16, 0xFB01, 0x0066, 0x0069, 0, + 16, 0xFB02, 0x0066, 0x006C, 0, + 16, 0xFB03, 0x0066, 0x0066, 0x0069, 0, + 16, 0xFB04, 0x0066, 0x0066, 0x006C, 0, + 16, 0xFB05, 0x017F, 0x0074, 0, + 16, 0xFB06, 0x0073, 0x0074, 0, + 16, 0xFB13, 0x0574, 0x0576, 0, + 16, 0xFB14, 0x0574, 0x0565, 0, + 16, 0xFB15, 0x0574, 0x056B, 0, + 16, 0xFB16, 0x057E, 0x0576, 0, + 16, 0xFB17, 0x0574, 0x056D, 0, + 1, 0xFB1D, 0x05D9, 0x05B4, 0, + 1, 0xFB1F, 0x05F2, 0x05B7, 0, + 2, 0xFB20, 0x05E2, 0, + 2, 0xFB21, 0x05D0, 0, + 2, 0xFB22, 0x05D3, 0, + 2, 0xFB23, 0x05D4, 0, + 2, 0xFB24, 0x05DB, 0, + 2, 0xFB25, 0x05DC, 0, + 2, 0xFB26, 0x05DD, 0, + 2, 0xFB27, 0x05E8, 0, + 2, 0xFB28, 0x05EA, 0, + 2, 0xFB29, 0x002B, 0, + 1, 0xFB2A, 0x05E9, 0x05C1, 0, + 1, 0xFB2B, 0x05E9, 0x05C2, 0, + 1, 0xFB2C, 0xFB49, 0x05C1, 0, + 1, 0xFB2D, 0xFB49, 0x05C2, 0, + 1, 0xFB2E, 0x05D0, 0x05B7, 0, + 1, 0xFB2F, 0x05D0, 0x05B8, 0, + 1, 0xFB30, 0x05D0, 0x05BC, 0, + 1, 0xFB31, 0x05D1, 0x05BC, 0, + 1, 0xFB32, 0x05D2, 0x05BC, 0, + 1, 0xFB33, 0x05D3, 0x05BC, 0, + 1, 0xFB34, 0x05D4, 0x05BC, 0, + 1, 0xFB35, 0x05D5, 0x05BC, 0, + 1, 0xFB36, 0x05D6, 0x05BC, 0, + 1, 0xFB38, 0x05D8, 0x05BC, 0, + 1, 0xFB39, 0x05D9, 0x05BC, 0, + 1, 0xFB3A, 0x05DA, 0x05BC, 0, + 1, 0xFB3B, 0x05DB, 0x05BC, 0, + 1, 0xFB3C, 0x05DC, 0x05BC, 0, + 1, 0xFB3E, 0x05DE, 0x05BC, 0, + 1, 0xFB40, 0x05E0, 0x05BC, 0, + 1, 0xFB41, 0x05E1, 0x05BC, 0, + 1, 0xFB43, 0x05E3, 0x05BC, 0, + 1, 0xFB44, 0x05E4, 0x05BC, 0, + 1, 0xFB46, 0x05E6, 0x05BC, 0, + 1, 0xFB47, 0x05E7, 0x05BC, 0, + 1, 0xFB48, 0x05E8, 0x05BC, 0, + 1, 0xFB49, 0x05E9, 0x05BC, 0, + 1, 0xFB4A, 0x05EA, 0x05BC, 0, + 1, 0xFB4B, 0x05D5, 0x05B9, 0, + 1, 0xFB4C, 0x05D1, 0x05BF, 0, + 1, 0xFB4D, 0x05DB, 0x05BF, 0, + 1, 0xFB4E, 0x05E4, 0x05BF, 0, + 16, 0xFB4F, 0x05D0, 0x05DC, 0, + 7, 0xFB50, 0x0671, 0, + 6, 0xFB51, 0x0671, 0, + 7, 0xFB52, 0x067B, 0, + 6, 0xFB53, 0x067B, 0, + 4, 0xFB54, 0x067B, 0, + 5, 0xFB55, 0x067B, 0, + 7, 0xFB56, 0x067E, 0, + 6, 0xFB57, 0x067E, 0, + 4, 0xFB58, 0x067E, 0, + 5, 0xFB59, 0x067E, 0, + 7, 0xFB5A, 0x0680, 0, + 6, 0xFB5B, 0x0680, 0, + 4, 0xFB5C, 0x0680, 0, + 5, 0xFB5D, 0x0680, 0, + 7, 0xFB5E, 0x067A, 0, + 6, 0xFB5F, 0x067A, 0, + 4, 0xFB60, 0x067A, 0, + 5, 0xFB61, 0x067A, 0, + 7, 0xFB62, 0x067F, 0, + 6, 0xFB63, 0x067F, 0, + 4, 0xFB64, 0x067F, 0, + 5, 0xFB65, 0x067F, 0, + 7, 0xFB66, 0x0679, 0, + 6, 0xFB67, 0x0679, 0, + 4, 0xFB68, 0x0679, 0, + 5, 0xFB69, 0x0679, 0, + 7, 0xFB6A, 0x06A4, 0, + 6, 0xFB6B, 0x06A4, 0, + 4, 0xFB6C, 0x06A4, 0, + 5, 0xFB6D, 0x06A4, 0, + 7, 0xFB6E, 0x06A6, 0, + 6, 0xFB6F, 0x06A6, 0, + 4, 0xFB70, 0x06A6, 0, + 5, 0xFB71, 0x06A6, 0, + 7, 0xFB72, 0x0684, 0, + 6, 0xFB73, 0x0684, 0, + 4, 0xFB74, 0x0684, 0, + 5, 0xFB75, 0x0684, 0, + 7, 0xFB76, 0x0683, 0, + 6, 0xFB77, 0x0683, 0, + 4, 0xFB78, 0x0683, 0, + 5, 0xFB79, 0x0683, 0, + 7, 0xFB7A, 0x0686, 0, + 6, 0xFB7B, 0x0686, 0, + 4, 0xFB7C, 0x0686, 0, + 5, 0xFB7D, 0x0686, 0, + 7, 0xFB7E, 0x0687, 0, + 6, 0xFB7F, 0x0687, 0, + 4, 0xFB80, 0x0687, 0, + 5, 0xFB81, 0x0687, 0, + 7, 0xFB82, 0x068D, 0, + 6, 0xFB83, 0x068D, 0, + 7, 0xFB84, 0x068C, 0, + 6, 0xFB85, 0x068C, 0, + 7, 0xFB86, 0x068E, 0, + 6, 0xFB87, 0x068E, 0, + 7, 0xFB88, 0x0688, 0, + 6, 0xFB89, 0x0688, 0, + 7, 0xFB8A, 0x0698, 0, + 6, 0xFB8B, 0x0698, 0, + 7, 0xFB8C, 0x0691, 0, + 6, 0xFB8D, 0x0691, 0, + 7, 0xFB8E, 0x06A9, 0, + 6, 0xFB8F, 0x06A9, 0, + 4, 0xFB90, 0x06A9, 0, + 5, 0xFB91, 0x06A9, 0, + 7, 0xFB92, 0x06AF, 0, + 6, 0xFB93, 0x06AF, 0, + 4, 0xFB94, 0x06AF, 0, + 5, 0xFB95, 0x06AF, 0, + 7, 0xFB96, 0x06B3, 0, + 6, 0xFB97, 0x06B3, 0, + 4, 0xFB98, 0x06B3, 0, + 5, 0xFB99, 0x06B3, 0, + 7, 0xFB9A, 0x06B1, 0, + 6, 0xFB9B, 0x06B1, 0, + 4, 0xFB9C, 0x06B1, 0, + 5, 0xFB9D, 0x06B1, 0, + 7, 0xFB9E, 0x06BA, 0, + 6, 0xFB9F, 0x06BA, 0, + 7, 0xFBA0, 0x06BB, 0, + 6, 0xFBA1, 0x06BB, 0, + 4, 0xFBA2, 0x06BB, 0, + 5, 0xFBA3, 0x06BB, 0, + 7, 0xFBA4, 0x06C0, 0, + 6, 0xFBA5, 0x06C0, 0, + 7, 0xFBA6, 0x06C1, 0, + 6, 0xFBA7, 0x06C1, 0, + 4, 0xFBA8, 0x06C1, 0, + 5, 0xFBA9, 0x06C1, 0, + 7, 0xFBAA, 0x06BE, 0, + 6, 0xFBAB, 0x06BE, 0, + 4, 0xFBAC, 0x06BE, 0, + 5, 0xFBAD, 0x06BE, 0, + 7, 0xFBAE, 0x06D2, 0, + 6, 0xFBAF, 0x06D2, 0, + 7, 0xFBB0, 0x06D3, 0, + 6, 0xFBB1, 0x06D3, 0, + 7, 0xFBD3, 0x06AD, 0, + 6, 0xFBD4, 0x06AD, 0, + 4, 0xFBD5, 0x06AD, 0, + 5, 0xFBD6, 0x06AD, 0, + 7, 0xFBD7, 0x06C7, 0, + 6, 0xFBD8, 0x06C7, 0, + 7, 0xFBD9, 0x06C6, 0, + 6, 0xFBDA, 0x06C6, 0, + 7, 0xFBDB, 0x06C8, 0, + 6, 0xFBDC, 0x06C8, 0, + 7, 0xFBDD, 0x0677, 0, + 7, 0xFBDE, 0x06CB, 0, + 6, 0xFBDF, 0x06CB, 0, + 7, 0xFBE0, 0x06C5, 0, + 6, 0xFBE1, 0x06C5, 0, + 7, 0xFBE2, 0x06C9, 0, + 6, 0xFBE3, 0x06C9, 0, + 7, 0xFBE4, 0x06D0, 0, + 6, 0xFBE5, 0x06D0, 0, + 4, 0xFBE6, 0x06D0, 0, + 5, 0xFBE7, 0x06D0, 0, + 4, 0xFBE8, 0x0649, 0, + 5, 0xFBE9, 0x0649, 0, + 7, 0xFBEA, 0x0626, 0x0627, 0, + 6, 0xFBEB, 0x0626, 0x0627, 0, + 7, 0xFBEC, 0x0626, 0x06D5, 0, + 6, 0xFBED, 0x0626, 0x06D5, 0, + 7, 0xFBEE, 0x0626, 0x0648, 0, + 6, 0xFBEF, 0x0626, 0x0648, 0, + 7, 0xFBF0, 0x0626, 0x06C7, 0, + 6, 0xFBF1, 0x0626, 0x06C7, 0, + 7, 0xFBF2, 0x0626, 0x06C6, 0, + 6, 0xFBF3, 0x0626, 0x06C6, 0, + 7, 0xFBF4, 0x0626, 0x06C8, 0, + 6, 0xFBF5, 0x0626, 0x06C8, 0, + 7, 0xFBF6, 0x0626, 0x06D0, 0, + 6, 0xFBF7, 0x0626, 0x06D0, 0, + 4, 0xFBF8, 0x0626, 0x06D0, 0, + 7, 0xFBF9, 0x0626, 0x0649, 0, + 6, 0xFBFA, 0x0626, 0x0649, 0, + 4, 0xFBFB, 0x0626, 0x0649, 0, + 7, 0xFBFC, 0x06CC, 0, + 6, 0xFBFD, 0x06CC, 0, + 4, 0xFBFE, 0x06CC, 0, + 5, 0xFBFF, 0x06CC, 0, + 7, 0xFC00, 0x0626, 0x062C, 0, + 7, 0xFC01, 0x0626, 0x062D, 0, + 7, 0xFC02, 0x0626, 0x0645, 0, + 7, 0xFC03, 0x0626, 0x0649, 0, + 7, 0xFC04, 0x0626, 0x064A, 0, + 7, 0xFC05, 0x0628, 0x062C, 0, + 7, 0xFC06, 0x0628, 0x062D, 0, + 7, 0xFC07, 0x0628, 0x062E, 0, + 7, 0xFC08, 0x0628, 0x0645, 0, + 7, 0xFC09, 0x0628, 0x0649, 0, + 7, 0xFC0A, 0x0628, 0x064A, 0, + 7, 0xFC0B, 0x062A, 0x062C, 0, + 7, 0xFC0C, 0x062A, 0x062D, 0, + 7, 0xFC0D, 0x062A, 0x062E, 0, + 7, 0xFC0E, 0x062A, 0x0645, 0, + 7, 0xFC0F, 0x062A, 0x0649, 0, + 7, 0xFC10, 0x062A, 0x064A, 0, + 7, 0xFC11, 0x062B, 0x062C, 0, + 7, 0xFC12, 0x062B, 0x0645, 0, + 7, 0xFC13, 0x062B, 0x0649, 0, + 7, 0xFC14, 0x062B, 0x064A, 0, + 7, 0xFC15, 0x062C, 0x062D, 0, + 7, 0xFC16, 0x062C, 0x0645, 0, + 7, 0xFC17, 0x062D, 0x062C, 0, + 7, 0xFC18, 0x062D, 0x0645, 0, + 7, 0xFC19, 0x062E, 0x062C, 0, + 7, 0xFC1A, 0x062E, 0x062D, 0, + 7, 0xFC1B, 0x062E, 0x0645, 0, + 7, 0xFC1C, 0x0633, 0x062C, 0, + 7, 0xFC1D, 0x0633, 0x062D, 0, + 7, 0xFC1E, 0x0633, 0x062E, 0, + 7, 0xFC1F, 0x0633, 0x0645, 0, + 7, 0xFC20, 0x0635, 0x062D, 0, + 7, 0xFC21, 0x0635, 0x0645, 0, + 7, 0xFC22, 0x0636, 0x062C, 0, + 7, 0xFC23, 0x0636, 0x062D, 0, + 7, 0xFC24, 0x0636, 0x062E, 0, + 7, 0xFC25, 0x0636, 0x0645, 0, + 7, 0xFC26, 0x0637, 0x062D, 0, + 7, 0xFC27, 0x0637, 0x0645, 0, + 7, 0xFC28, 0x0638, 0x0645, 0, + 7, 0xFC29, 0x0639, 0x062C, 0, + 7, 0xFC2A, 0x0639, 0x0645, 0, + 7, 0xFC2B, 0x063A, 0x062C, 0, + 7, 0xFC2C, 0x063A, 0x0645, 0, + 7, 0xFC2D, 0x0641, 0x062C, 0, + 7, 0xFC2E, 0x0641, 0x062D, 0, + 7, 0xFC2F, 0x0641, 0x062E, 0, + 7, 0xFC30, 0x0641, 0x0645, 0, + 7, 0xFC31, 0x0641, 0x0649, 0, + 7, 0xFC32, 0x0641, 0x064A, 0, + 7, 0xFC33, 0x0642, 0x062D, 0, + 7, 0xFC34, 0x0642, 0x0645, 0, + 7, 0xFC35, 0x0642, 0x0649, 0, + 7, 0xFC36, 0x0642, 0x064A, 0, + 7, 0xFC37, 0x0643, 0x0627, 0, + 7, 0xFC38, 0x0643, 0x062C, 0, + 7, 0xFC39, 0x0643, 0x062D, 0, + 7, 0xFC3A, 0x0643, 0x062E, 0, + 7, 0xFC3B, 0x0643, 0x0644, 0, + 7, 0xFC3C, 0x0643, 0x0645, 0, + 7, 0xFC3D, 0x0643, 0x0649, 0, + 7, 0xFC3E, 0x0643, 0x064A, 0, + 7, 0xFC3F, 0x0644, 0x062C, 0, + 7, 0xFC40, 0x0644, 0x062D, 0, + 7, 0xFC41, 0x0644, 0x062E, 0, + 7, 0xFC42, 0x0644, 0x0645, 0, + 7, 0xFC43, 0x0644, 0x0649, 0, + 7, 0xFC44, 0x0644, 0x064A, 0, + 7, 0xFC45, 0x0645, 0x062C, 0, + 7, 0xFC46, 0x0645, 0x062D, 0, + 7, 0xFC47, 0x0645, 0x062E, 0, + 7, 0xFC48, 0x0645, 0x0645, 0, + 7, 0xFC49, 0x0645, 0x0649, 0, + 7, 0xFC4A, 0x0645, 0x064A, 0, + 7, 0xFC4B, 0x0646, 0x062C, 0, + 7, 0xFC4C, 0x0646, 0x062D, 0, + 7, 0xFC4D, 0x0646, 0x062E, 0, + 7, 0xFC4E, 0x0646, 0x0645, 0, + 7, 0xFC4F, 0x0646, 0x0649, 0, + 7, 0xFC50, 0x0646, 0x064A, 0, + 7, 0xFC51, 0x0647, 0x062C, 0, + 7, 0xFC52, 0x0647, 0x0645, 0, + 7, 0xFC53, 0x0647, 0x0649, 0, + 7, 0xFC54, 0x0647, 0x064A, 0, + 7, 0xFC55, 0x064A, 0x062C, 0, + 7, 0xFC56, 0x064A, 0x062D, 0, + 7, 0xFC57, 0x064A, 0x062E, 0, + 7, 0xFC58, 0x064A, 0x0645, 0, + 7, 0xFC59, 0x064A, 0x0649, 0, + 7, 0xFC5A, 0x064A, 0x064A, 0, + 7, 0xFC5B, 0x0630, 0x0670, 0, + 7, 0xFC5C, 0x0631, 0x0670, 0, + 7, 0xFC5D, 0x0649, 0x0670, 0, + 7, 0xFC5E, 0x0020, 0x064C, 0x0651, 0, + 7, 0xFC5F, 0x0020, 0x064D, 0x0651, 0, + 7, 0xFC60, 0x0020, 0x064E, 0x0651, 0, + 7, 0xFC61, 0x0020, 0x064F, 0x0651, 0, + 7, 0xFC62, 0x0020, 0x0650, 0x0651, 0, + 7, 0xFC63, 0x0020, 0x0651, 0x0670, 0, + 6, 0xFC64, 0x0626, 0x0631, 0, + 6, 0xFC65, 0x0626, 0x0632, 0, + 6, 0xFC66, 0x0626, 0x0645, 0, + 6, 0xFC67, 0x0626, 0x0646, 0, + 6, 0xFC68, 0x0626, 0x0649, 0, + 6, 0xFC69, 0x0626, 0x064A, 0, + 6, 0xFC6A, 0x0628, 0x0631, 0, + 6, 0xFC6B, 0x0628, 0x0632, 0, + 6, 0xFC6C, 0x0628, 0x0645, 0, + 6, 0xFC6D, 0x0628, 0x0646, 0, + 6, 0xFC6E, 0x0628, 0x0649, 0, + 6, 0xFC6F, 0x0628, 0x064A, 0, + 6, 0xFC70, 0x062A, 0x0631, 0, + 6, 0xFC71, 0x062A, 0x0632, 0, + 6, 0xFC72, 0x062A, 0x0645, 0, + 6, 0xFC73, 0x062A, 0x0646, 0, + 6, 0xFC74, 0x062A, 0x0649, 0, + 6, 0xFC75, 0x062A, 0x064A, 0, + 6, 0xFC76, 0x062B, 0x0631, 0, + 6, 0xFC77, 0x062B, 0x0632, 0, + 6, 0xFC78, 0x062B, 0x0645, 0, + 6, 0xFC79, 0x062B, 0x0646, 0, + 6, 0xFC7A, 0x062B, 0x0649, 0, + 6, 0xFC7B, 0x062B, 0x064A, 0, + 6, 0xFC7C, 0x0641, 0x0649, 0, + 6, 0xFC7D, 0x0641, 0x064A, 0, + 6, 0xFC7E, 0x0642, 0x0649, 0, + 6, 0xFC7F, 0x0642, 0x064A, 0, + 6, 0xFC80, 0x0643, 0x0627, 0, + 6, 0xFC81, 0x0643, 0x0644, 0, + 6, 0xFC82, 0x0643, 0x0645, 0, + 6, 0xFC83, 0x0643, 0x0649, 0, + 6, 0xFC84, 0x0643, 0x064A, 0, + 6, 0xFC85, 0x0644, 0x0645, 0, + 6, 0xFC86, 0x0644, 0x0649, 0, + 6, 0xFC87, 0x0644, 0x064A, 0, + 6, 0xFC88, 0x0645, 0x0627, 0, + 6, 0xFC89, 0x0645, 0x0645, 0, + 6, 0xFC8A, 0x0646, 0x0631, 0, + 6, 0xFC8B, 0x0646, 0x0632, 0, + 6, 0xFC8C, 0x0646, 0x0645, 0, + 6, 0xFC8D, 0x0646, 0x0646, 0, + 6, 0xFC8E, 0x0646, 0x0649, 0, + 6, 0xFC8F, 0x0646, 0x064A, 0, + 6, 0xFC90, 0x0649, 0x0670, 0, + 6, 0xFC91, 0x064A, 0x0631, 0, + 6, 0xFC92, 0x064A, 0x0632, 0, + 6, 0xFC93, 0x064A, 0x0645, 0, + 6, 0xFC94, 0x064A, 0x0646, 0, + 6, 0xFC95, 0x064A, 0x0649, 0, + 6, 0xFC96, 0x064A, 0x064A, 0, + 4, 0xFC97, 0x0626, 0x062C, 0, + 4, 0xFC98, 0x0626, 0x062D, 0, + 4, 0xFC99, 0x0626, 0x062E, 0, + 4, 0xFC9A, 0x0626, 0x0645, 0, + 4, 0xFC9B, 0x0626, 0x0647, 0, + 4, 0xFC9C, 0x0628, 0x062C, 0, + 4, 0xFC9D, 0x0628, 0x062D, 0, + 4, 0xFC9E, 0x0628, 0x062E, 0, + 4, 0xFC9F, 0x0628, 0x0645, 0, + 4, 0xFCA0, 0x0628, 0x0647, 0, + 4, 0xFCA1, 0x062A, 0x062C, 0, + 4, 0xFCA2, 0x062A, 0x062D, 0, + 4, 0xFCA3, 0x062A, 0x062E, 0, + 4, 0xFCA4, 0x062A, 0x0645, 0, + 4, 0xFCA5, 0x062A, 0x0647, 0, + 4, 0xFCA6, 0x062B, 0x0645, 0, + 4, 0xFCA7, 0x062C, 0x062D, 0, + 4, 0xFCA8, 0x062C, 0x0645, 0, + 4, 0xFCA9, 0x062D, 0x062C, 0, + 4, 0xFCAA, 0x062D, 0x0645, 0, + 4, 0xFCAB, 0x062E, 0x062C, 0, + 4, 0xFCAC, 0x062E, 0x0645, 0, + 4, 0xFCAD, 0x0633, 0x062C, 0, + 4, 0xFCAE, 0x0633, 0x062D, 0, + 4, 0xFCAF, 0x0633, 0x062E, 0, + 4, 0xFCB0, 0x0633, 0x0645, 0, + 4, 0xFCB1, 0x0635, 0x062D, 0, + 4, 0xFCB2, 0x0635, 0x062E, 0, + 4, 0xFCB3, 0x0635, 0x0645, 0, + 4, 0xFCB4, 0x0636, 0x062C, 0, + 4, 0xFCB5, 0x0636, 0x062D, 0, + 4, 0xFCB6, 0x0636, 0x062E, 0, + 4, 0xFCB7, 0x0636, 0x0645, 0, + 4, 0xFCB8, 0x0637, 0x062D, 0, + 4, 0xFCB9, 0x0638, 0x0645, 0, + 4, 0xFCBA, 0x0639, 0x062C, 0, + 4, 0xFCBB, 0x0639, 0x0645, 0, + 4, 0xFCBC, 0x063A, 0x062C, 0, + 4, 0xFCBD, 0x063A, 0x0645, 0, + 4, 0xFCBE, 0x0641, 0x062C, 0, + 4, 0xFCBF, 0x0641, 0x062D, 0, + 4, 0xFCC0, 0x0641, 0x062E, 0, + 4, 0xFCC1, 0x0641, 0x0645, 0, + 4, 0xFCC2, 0x0642, 0x062D, 0, + 4, 0xFCC3, 0x0642, 0x0645, 0, + 4, 0xFCC4, 0x0643, 0x062C, 0, + 4, 0xFCC5, 0x0643, 0x062D, 0, + 4, 0xFCC6, 0x0643, 0x062E, 0, + 4, 0xFCC7, 0x0643, 0x0644, 0, + 4, 0xFCC8, 0x0643, 0x0645, 0, + 4, 0xFCC9, 0x0644, 0x062C, 0, + 4, 0xFCCA, 0x0644, 0x062D, 0, + 4, 0xFCCB, 0x0644, 0x062E, 0, + 4, 0xFCCC, 0x0644, 0x0645, 0, + 4, 0xFCCD, 0x0644, 0x0647, 0, + 4, 0xFCCE, 0x0645, 0x062C, 0, + 4, 0xFCCF, 0x0645, 0x062D, 0, + 4, 0xFCD0, 0x0645, 0x062E, 0, + 4, 0xFCD1, 0x0645, 0x0645, 0, + 4, 0xFCD2, 0x0646, 0x062C, 0, + 4, 0xFCD3, 0x0646, 0x062D, 0, + 4, 0xFCD4, 0x0646, 0x062E, 0, + 4, 0xFCD5, 0x0646, 0x0645, 0, + 4, 0xFCD6, 0x0646, 0x0647, 0, + 4, 0xFCD7, 0x0647, 0x062C, 0, + 4, 0xFCD8, 0x0647, 0x0645, 0, + 4, 0xFCD9, 0x0647, 0x0670, 0, + 4, 0xFCDA, 0x064A, 0x062C, 0, + 4, 0xFCDB, 0x064A, 0x062D, 0, + 4, 0xFCDC, 0x064A, 0x062E, 0, + 4, 0xFCDD, 0x064A, 0x0645, 0, + 4, 0xFCDE, 0x064A, 0x0647, 0, + 5, 0xFCDF, 0x0626, 0x0645, 0, + 5, 0xFCE0, 0x0626, 0x0647, 0, + 5, 0xFCE1, 0x0628, 0x0645, 0, + 5, 0xFCE2, 0x0628, 0x0647, 0, + 5, 0xFCE3, 0x062A, 0x0645, 0, + 5, 0xFCE4, 0x062A, 0x0647, 0, + 5, 0xFCE5, 0x062B, 0x0645, 0, + 5, 0xFCE6, 0x062B, 0x0647, 0, + 5, 0xFCE7, 0x0633, 0x0645, 0, + 5, 0xFCE8, 0x0633, 0x0647, 0, + 5, 0xFCE9, 0x0634, 0x0645, 0, + 5, 0xFCEA, 0x0634, 0x0647, 0, + 5, 0xFCEB, 0x0643, 0x0644, 0, + 5, 0xFCEC, 0x0643, 0x0645, 0, + 5, 0xFCED, 0x0644, 0x0645, 0, + 5, 0xFCEE, 0x0646, 0x0645, 0, + 5, 0xFCEF, 0x0646, 0x0647, 0, + 5, 0xFCF0, 0x064A, 0x0645, 0, + 5, 0xFCF1, 0x064A, 0x0647, 0, + 5, 0xFCF2, 0x0640, 0x064E, 0x0651, 0, + 5, 0xFCF3, 0x0640, 0x064F, 0x0651, 0, + 5, 0xFCF4, 0x0640, 0x0650, 0x0651, 0, + 7, 0xFCF5, 0x0637, 0x0649, 0, + 7, 0xFCF6, 0x0637, 0x064A, 0, + 7, 0xFCF7, 0x0639, 0x0649, 0, + 7, 0xFCF8, 0x0639, 0x064A, 0, + 7, 0xFCF9, 0x063A, 0x0649, 0, + 7, 0xFCFA, 0x063A, 0x064A, 0, + 7, 0xFCFB, 0x0633, 0x0649, 0, + 7, 0xFCFC, 0x0633, 0x064A, 0, + 7, 0xFCFD, 0x0634, 0x0649, 0, + 7, 0xFCFE, 0x0634, 0x064A, 0, + 7, 0xFCFF, 0x062D, 0x0649, 0, + 7, 0xFD00, 0x062D, 0x064A, 0, + 7, 0xFD01, 0x062C, 0x0649, 0, + 7, 0xFD02, 0x062C, 0x064A, 0, + 7, 0xFD03, 0x062E, 0x0649, 0, + 7, 0xFD04, 0x062E, 0x064A, 0, + 7, 0xFD05, 0x0635, 0x0649, 0, + 7, 0xFD06, 0x0635, 0x064A, 0, + 7, 0xFD07, 0x0636, 0x0649, 0, + 7, 0xFD08, 0x0636, 0x064A, 0, + 7, 0xFD09, 0x0634, 0x062C, 0, + 7, 0xFD0A, 0x0634, 0x062D, 0, + 7, 0xFD0B, 0x0634, 0x062E, 0, + 7, 0xFD0C, 0x0634, 0x0645, 0, + 7, 0xFD0D, 0x0634, 0x0631, 0, + 7, 0xFD0E, 0x0633, 0x0631, 0, + 7, 0xFD0F, 0x0635, 0x0631, 0, + 7, 0xFD10, 0x0636, 0x0631, 0, + 6, 0xFD11, 0x0637, 0x0649, 0, + 6, 0xFD12, 0x0637, 0x064A, 0, + 6, 0xFD13, 0x0639, 0x0649, 0, + 6, 0xFD14, 0x0639, 0x064A, 0, + 6, 0xFD15, 0x063A, 0x0649, 0, + 6, 0xFD16, 0x063A, 0x064A, 0, + 6, 0xFD17, 0x0633, 0x0649, 0, + 6, 0xFD18, 0x0633, 0x064A, 0, + 6, 0xFD19, 0x0634, 0x0649, 0, + 6, 0xFD1A, 0x0634, 0x064A, 0, + 6, 0xFD1B, 0x062D, 0x0649, 0, + 6, 0xFD1C, 0x062D, 0x064A, 0, + 6, 0xFD1D, 0x062C, 0x0649, 0, + 6, 0xFD1E, 0x062C, 0x064A, 0, + 6, 0xFD1F, 0x062E, 0x0649, 0, + 6, 0xFD20, 0x062E, 0x064A, 0, + 6, 0xFD21, 0x0635, 0x0649, 0, + 6, 0xFD22, 0x0635, 0x064A, 0, + 6, 0xFD23, 0x0636, 0x0649, 0, + 6, 0xFD24, 0x0636, 0x064A, 0, + 6, 0xFD25, 0x0634, 0x062C, 0, + 6, 0xFD26, 0x0634, 0x062D, 0, + 6, 0xFD27, 0x0634, 0x062E, 0, + 6, 0xFD28, 0x0634, 0x0645, 0, + 6, 0xFD29, 0x0634, 0x0631, 0, + 6, 0xFD2A, 0x0633, 0x0631, 0, + 6, 0xFD2B, 0x0635, 0x0631, 0, + 6, 0xFD2C, 0x0636, 0x0631, 0, + 4, 0xFD2D, 0x0634, 0x062C, 0, + 4, 0xFD2E, 0x0634, 0x062D, 0, + 4, 0xFD2F, 0x0634, 0x062E, 0, + 4, 0xFD30, 0x0634, 0x0645, 0, + 4, 0xFD31, 0x0633, 0x0647, 0, + 4, 0xFD32, 0x0634, 0x0647, 0, + 4, 0xFD33, 0x0637, 0x0645, 0, + 5, 0xFD34, 0x0633, 0x062C, 0, + 5, 0xFD35, 0x0633, 0x062D, 0, + 5, 0xFD36, 0x0633, 0x062E, 0, + 5, 0xFD37, 0x0634, 0x062C, 0, + 5, 0xFD38, 0x0634, 0x062D, 0, + 5, 0xFD39, 0x0634, 0x062E, 0, + 5, 0xFD3A, 0x0637, 0x0645, 0, + 5, 0xFD3B, 0x0638, 0x0645, 0, + 6, 0xFD3C, 0x0627, 0x064B, 0, + 7, 0xFD3D, 0x0627, 0x064B, 0, + 4, 0xFD50, 0x062A, 0x062C, 0x0645, 0, + 6, 0xFD51, 0x062A, 0x062D, 0x062C, 0, + 4, 0xFD52, 0x062A, 0x062D, 0x062C, 0, + 4, 0xFD53, 0x062A, 0x062D, 0x0645, 0, + 4, 0xFD54, 0x062A, 0x062E, 0x0645, 0, + 4, 0xFD55, 0x062A, 0x0645, 0x062C, 0, + 4, 0xFD56, 0x062A, 0x0645, 0x062D, 0, + 4, 0xFD57, 0x062A, 0x0645, 0x062E, 0, + 6, 0xFD58, 0x062C, 0x0645, 0x062D, 0, + 4, 0xFD59, 0x062C, 0x0645, 0x062D, 0, + 6, 0xFD5A, 0x062D, 0x0645, 0x064A, 0, + 6, 0xFD5B, 0x062D, 0x0645, 0x0649, 0, + 4, 0xFD5C, 0x0633, 0x062D, 0x062C, 0, + 4, 0xFD5D, 0x0633, 0x062C, 0x062D, 0, + 6, 0xFD5E, 0x0633, 0x062C, 0x0649, 0, + 6, 0xFD5F, 0x0633, 0x0645, 0x062D, 0, + 4, 0xFD60, 0x0633, 0x0645, 0x062D, 0, + 4, 0xFD61, 0x0633, 0x0645, 0x062C, 0, + 6, 0xFD62, 0x0633, 0x0645, 0x0645, 0, + 4, 0xFD63, 0x0633, 0x0645, 0x0645, 0, + 6, 0xFD64, 0x0635, 0x062D, 0x062D, 0, + 4, 0xFD65, 0x0635, 0x062D, 0x062D, 0, + 6, 0xFD66, 0x0635, 0x0645, 0x0645, 0, + 6, 0xFD67, 0x0634, 0x062D, 0x0645, 0, + 4, 0xFD68, 0x0634, 0x062D, 0x0645, 0, + 6, 0xFD69, 0x0634, 0x062C, 0x064A, 0, + 6, 0xFD6A, 0x0634, 0x0645, 0x062E, 0, + 4, 0xFD6B, 0x0634, 0x0645, 0x062E, 0, + 6, 0xFD6C, 0x0634, 0x0645, 0x0645, 0, + 4, 0xFD6D, 0x0634, 0x0645, 0x0645, 0, + 6, 0xFD6E, 0x0636, 0x062D, 0x0649, 0, + 6, 0xFD6F, 0x0636, 0x062E, 0x0645, 0, + 4, 0xFD70, 0x0636, 0x062E, 0x0645, 0, + 6, 0xFD71, 0x0637, 0x0645, 0x062D, 0, + 4, 0xFD72, 0x0637, 0x0645, 0x062D, 0, + 4, 0xFD73, 0x0637, 0x0645, 0x0645, 0, + 6, 0xFD74, 0x0637, 0x0645, 0x064A, 0, + 6, 0xFD75, 0x0639, 0x062C, 0x0645, 0, + 6, 0xFD76, 0x0639, 0x0645, 0x0645, 0, + 4, 0xFD77, 0x0639, 0x0645, 0x0645, 0, + 6, 0xFD78, 0x0639, 0x0645, 0x0649, 0, + 6, 0xFD79, 0x063A, 0x0645, 0x0645, 0, + 6, 0xFD7A, 0x063A, 0x0645, 0x064A, 0, + 6, 0xFD7B, 0x063A, 0x0645, 0x0649, 0, + 6, 0xFD7C, 0x0641, 0x062E, 0x0645, 0, + 4, 0xFD7D, 0x0641, 0x062E, 0x0645, 0, + 6, 0xFD7E, 0x0642, 0x0645, 0x062D, 0, + 6, 0xFD7F, 0x0642, 0x0645, 0x0645, 0, + 6, 0xFD80, 0x0644, 0x062D, 0x0645, 0, + 6, 0xFD81, 0x0644, 0x062D, 0x064A, 0, + 6, 0xFD82, 0x0644, 0x062D, 0x0649, 0, + 4, 0xFD83, 0x0644, 0x062C, 0x062C, 0, + 6, 0xFD84, 0x0644, 0x062C, 0x062C, 0, + 6, 0xFD85, 0x0644, 0x062E, 0x0645, 0, + 4, 0xFD86, 0x0644, 0x062E, 0x0645, 0, + 6, 0xFD87, 0x0644, 0x0645, 0x062D, 0, + 4, 0xFD88, 0x0644, 0x0645, 0x062D, 0, + 4, 0xFD89, 0x0645, 0x062D, 0x062C, 0, + 4, 0xFD8A, 0x0645, 0x062D, 0x0645, 0, + 6, 0xFD8B, 0x0645, 0x062D, 0x064A, 0, + 4, 0xFD8C, 0x0645, 0x062C, 0x062D, 0, + 4, 0xFD8D, 0x0645, 0x062C, 0x0645, 0, + 4, 0xFD8E, 0x0645, 0x062E, 0x062C, 0, + 4, 0xFD8F, 0x0645, 0x062E, 0x0645, 0, + 4, 0xFD92, 0x0645, 0x062C, 0x062E, 0, + 4, 0xFD93, 0x0647, 0x0645, 0x062C, 0, + 4, 0xFD94, 0x0647, 0x0645, 0x0645, 0, + 4, 0xFD95, 0x0646, 0x062D, 0x0645, 0, + 6, 0xFD96, 0x0646, 0x062D, 0x0649, 0, + 6, 0xFD97, 0x0646, 0x062C, 0x0645, 0, + 4, 0xFD98, 0x0646, 0x062C, 0x0645, 0, + 6, 0xFD99, 0x0646, 0x062C, 0x0649, 0, + 6, 0xFD9A, 0x0646, 0x0645, 0x064A, 0, + 6, 0xFD9B, 0x0646, 0x0645, 0x0649, 0, + 6, 0xFD9C, 0x064A, 0x0645, 0x0645, 0, + 4, 0xFD9D, 0x064A, 0x0645, 0x0645, 0, + 6, 0xFD9E, 0x0628, 0x062E, 0x064A, 0, + 6, 0xFD9F, 0x062A, 0x062C, 0x064A, 0, + 6, 0xFDA0, 0x062A, 0x062C, 0x0649, 0, + 6, 0xFDA1, 0x062A, 0x062E, 0x064A, 0, + 6, 0xFDA2, 0x062A, 0x062E, 0x0649, 0, + 6, 0xFDA3, 0x062A, 0x0645, 0x064A, 0, + 6, 0xFDA4, 0x062A, 0x0645, 0x0649, 0, + 6, 0xFDA5, 0x062C, 0x0645, 0x064A, 0, + 6, 0xFDA6, 0x062C, 0x062D, 0x0649, 0, + 6, 0xFDA7, 0x062C, 0x0645, 0x0649, 0, + 6, 0xFDA8, 0x0633, 0x062E, 0x0649, 0, + 6, 0xFDA9, 0x0635, 0x062D, 0x064A, 0, + 6, 0xFDAA, 0x0634, 0x062D, 0x064A, 0, + 6, 0xFDAB, 0x0636, 0x062D, 0x064A, 0, + 6, 0xFDAC, 0x0644, 0x062C, 0x064A, 0, + 6, 0xFDAD, 0x0644, 0x0645, 0x064A, 0, + 6, 0xFDAE, 0x064A, 0x062D, 0x064A, 0, + 6, 0xFDAF, 0x064A, 0x062C, 0x064A, 0, + 6, 0xFDB0, 0x064A, 0x0645, 0x064A, 0, + 6, 0xFDB1, 0x0645, 0x0645, 0x064A, 0, + 6, 0xFDB2, 0x0642, 0x0645, 0x064A, 0, + 6, 0xFDB3, 0x0646, 0x062D, 0x064A, 0, + 4, 0xFDB4, 0x0642, 0x0645, 0x062D, 0, + 4, 0xFDB5, 0x0644, 0x062D, 0x0645, 0, + 6, 0xFDB6, 0x0639, 0x0645, 0x064A, 0, + 6, 0xFDB7, 0x0643, 0x0645, 0x064A, 0, + 4, 0xFDB8, 0x0646, 0x062C, 0x062D, 0, + 6, 0xFDB9, 0x0645, 0x062E, 0x064A, 0, + 4, 0xFDBA, 0x0644, 0x062C, 0x0645, 0, + 6, 0xFDBB, 0x0643, 0x0645, 0x0645, 0, + 6, 0xFDBC, 0x0644, 0x062C, 0x0645, 0, + 6, 0xFDBD, 0x0646, 0x062C, 0x062D, 0, + 6, 0xFDBE, 0x062C, 0x062D, 0x064A, 0, + 6, 0xFDBF, 0x062D, 0x062C, 0x064A, 0, + 6, 0xFDC0, 0x0645, 0x062C, 0x064A, 0, + 6, 0xFDC1, 0x0641, 0x0645, 0x064A, 0, + 6, 0xFDC2, 0x0628, 0x062D, 0x064A, 0, + 4, 0xFDC3, 0x0643, 0x0645, 0x0645, 0, + 4, 0xFDC4, 0x0639, 0x062C, 0x0645, 0, + 4, 0xFDC5, 0x0635, 0x0645, 0x0645, 0, + 6, 0xFDC6, 0x0633, 0x062E, 0x064A, 0, + 6, 0xFDC7, 0x0646, 0x062C, 0x064A, 0, + 7, 0xFDF0, 0x0635, 0x0644, 0x06D2, 0, + 7, 0xFDF1, 0x0642, 0x0644, 0x06D2, 0, + 7, 0xFDF2, 0x0627, 0x0644, 0x0644, 0x0647, 0, + 7, 0xFDF3, 0x0627, 0x0643, 0x0628, 0x0631, 0, + 7, 0xFDF4, 0x0645, 0x062D, 0x0645, 0x062F, 0, + 7, 0xFDF5, 0x0635, 0x0644, 0x0639, 0x0645, 0, + 7, 0xFDF6, 0x0631, 0x0633, 0x0648, 0x0644, 0, + 7, 0xFDF7, 0x0639, 0x0644, 0x064A, 0x0647, 0, + 7, 0xFDF8, 0x0648, 0x0633, 0x0644, 0x0645, 0, + 7, 0xFDF9, 0x0635, 0x0644, 0x0649, 0, + 7, 0xFDFA, 0x0635, 0x0644, 0x0649, 0x0020, 0x0627, 0x0644, 0x0644, 0x0647, 0x0020, 0x0639, 0x0644, 0x064A, 0x0647, 0x0020, 0x0648, 0x0633, 0x0644, 0x0645, 0, + 7, 0xFDFB, 0x062C, 0x0644, 0x0020, 0x062C, 0x0644, 0x0627, 0x0644, 0x0647, 0, + 11, 0xFE30, 0x2025, 0, + 11, 0xFE31, 0x2014, 0, + 11, 0xFE32, 0x2013, 0, + 11, 0xFE33, 0x005F, 0, + 11, 0xFE34, 0x005F, 0, + 11, 0xFE35, 0x0028, 0, + 11, 0xFE36, 0x0029, 0, + 11, 0xFE37, 0x007B, 0, + 11, 0xFE38, 0x007D, 0, + 11, 0xFE39, 0x3014, 0, + 11, 0xFE3A, 0x3015, 0, + 11, 0xFE3B, 0x3010, 0, + 11, 0xFE3C, 0x3011, 0, + 11, 0xFE3D, 0x300A, 0, + 11, 0xFE3E, 0x300B, 0, + 11, 0xFE3F, 0x3008, 0, + 11, 0xFE40, 0x3009, 0, + 11, 0xFE41, 0x300C, 0, + 11, 0xFE42, 0x300D, 0, + 11, 0xFE43, 0x300E, 0, + 11, 0xFE44, 0x300F, 0, + 16, 0xFE49, 0x203E, 0, + 16, 0xFE4A, 0x203E, 0, + 16, 0xFE4B, 0x203E, 0, + 16, 0xFE4C, 0x203E, 0, + 16, 0xFE4D, 0x005F, 0, + 16, 0xFE4E, 0x005F, 0, + 16, 0xFE4F, 0x005F, 0, + 14, 0xFE50, 0x002C, 0, + 14, 0xFE51, 0x3001, 0, + 14, 0xFE52, 0x002E, 0, + 14, 0xFE54, 0x003B, 0, + 14, 0xFE55, 0x003A, 0, + 14, 0xFE56, 0x003F, 0, + 14, 0xFE57, 0x0021, 0, + 14, 0xFE58, 0x2014, 0, + 14, 0xFE59, 0x0028, 0, + 14, 0xFE5A, 0x0029, 0, + 14, 0xFE5B, 0x007B, 0, + 14, 0xFE5C, 0x007D, 0, + 14, 0xFE5D, 0x3014, 0, + 14, 0xFE5E, 0x3015, 0, + 14, 0xFE5F, 0x0023, 0, + 14, 0xFE60, 0x0026, 0, + 14, 0xFE61, 0x002A, 0, + 14, 0xFE62, 0x002B, 0, + 14, 0xFE63, 0x002D, 0, + 14, 0xFE64, 0x003C, 0, + 14, 0xFE65, 0x003E, 0, + 14, 0xFE66, 0x003D, 0, + 14, 0xFE68, 0x005C, 0, + 14, 0xFE69, 0x0024, 0, + 14, 0xFE6A, 0x0025, 0, + 14, 0xFE6B, 0x0040, 0, + 7, 0xFE70, 0x0020, 0x064B, 0, + 5, 0xFE71, 0x0640, 0x064B, 0, + 7, 0xFE72, 0x0020, 0x064C, 0, + 7, 0xFE74, 0x0020, 0x064D, 0, + 7, 0xFE76, 0x0020, 0x064E, 0, + 5, 0xFE77, 0x0640, 0x064E, 0, + 7, 0xFE78, 0x0020, 0x064F, 0, + 5, 0xFE79, 0x0640, 0x064F, 0, + 7, 0xFE7A, 0x0020, 0x0650, 0, + 5, 0xFE7B, 0x0640, 0x0650, 0, + 7, 0xFE7C, 0x0020, 0x0651, 0, + 5, 0xFE7D, 0x0640, 0x0651, 0, + 7, 0xFE7E, 0x0020, 0x0652, 0, + 5, 0xFE7F, 0x0640, 0x0652, 0, + 7, 0xFE80, 0x0621, 0, + 7, 0xFE81, 0x0622, 0, + 6, 0xFE82, 0x0622, 0, + 7, 0xFE83, 0x0623, 0, + 6, 0xFE84, 0x0623, 0, + 7, 0xFE85, 0x0624, 0, + 6, 0xFE86, 0x0624, 0, + 7, 0xFE87, 0x0625, 0, + 6, 0xFE88, 0x0625, 0, + 7, 0xFE89, 0x0626, 0, + 6, 0xFE8A, 0x0626, 0, + 4, 0xFE8B, 0x0626, 0, + 5, 0xFE8C, 0x0626, 0, + 7, 0xFE8D, 0x0627, 0, + 6, 0xFE8E, 0x0627, 0, + 7, 0xFE8F, 0x0628, 0, + 6, 0xFE90, 0x0628, 0, + 4, 0xFE91, 0x0628, 0, + 5, 0xFE92, 0x0628, 0, + 7, 0xFE93, 0x0629, 0, + 6, 0xFE94, 0x0629, 0, + 7, 0xFE95, 0x062A, 0, + 6, 0xFE96, 0x062A, 0, + 4, 0xFE97, 0x062A, 0, + 5, 0xFE98, 0x062A, 0, + 7, 0xFE99, 0x062B, 0, + 6, 0xFE9A, 0x062B, 0, + 4, 0xFE9B, 0x062B, 0, + 5, 0xFE9C, 0x062B, 0, + 7, 0xFE9D, 0x062C, 0, + 6, 0xFE9E, 0x062C, 0, + 4, 0xFE9F, 0x062C, 0, + 5, 0xFEA0, 0x062C, 0, + 7, 0xFEA1, 0x062D, 0, + 6, 0xFEA2, 0x062D, 0, + 4, 0xFEA3, 0x062D, 0, + 5, 0xFEA4, 0x062D, 0, + 7, 0xFEA5, 0x062E, 0, + 6, 0xFEA6, 0x062E, 0, + 4, 0xFEA7, 0x062E, 0, + 5, 0xFEA8, 0x062E, 0, + 7, 0xFEA9, 0x062F, 0, + 6, 0xFEAA, 0x062F, 0, + 7, 0xFEAB, 0x0630, 0, + 6, 0xFEAC, 0x0630, 0, + 7, 0xFEAD, 0x0631, 0, + 6, 0xFEAE, 0x0631, 0, + 7, 0xFEAF, 0x0632, 0, + 6, 0xFEB0, 0x0632, 0, + 7, 0xFEB1, 0x0633, 0, + 6, 0xFEB2, 0x0633, 0, + 4, 0xFEB3, 0x0633, 0, + 5, 0xFEB4, 0x0633, 0, + 7, 0xFEB5, 0x0634, 0, + 6, 0xFEB6, 0x0634, 0, + 4, 0xFEB7, 0x0634, 0, + 5, 0xFEB8, 0x0634, 0, + 7, 0xFEB9, 0x0635, 0, + 6, 0xFEBA, 0x0635, 0, + 4, 0xFEBB, 0x0635, 0, + 5, 0xFEBC, 0x0635, 0, + 7, 0xFEBD, 0x0636, 0, + 6, 0xFEBE, 0x0636, 0, + 4, 0xFEBF, 0x0636, 0, + 5, 0xFEC0, 0x0636, 0, + 7, 0xFEC1, 0x0637, 0, + 6, 0xFEC2, 0x0637, 0, + 4, 0xFEC3, 0x0637, 0, + 5, 0xFEC4, 0x0637, 0, + 7, 0xFEC5, 0x0638, 0, + 6, 0xFEC6, 0x0638, 0, + 4, 0xFEC7, 0x0638, 0, + 5, 0xFEC8, 0x0638, 0, + 7, 0xFEC9, 0x0639, 0, + 6, 0xFECA, 0x0639, 0, + 4, 0xFECB, 0x0639, 0, + 5, 0xFECC, 0x0639, 0, + 7, 0xFECD, 0x063A, 0, + 6, 0xFECE, 0x063A, 0, + 4, 0xFECF, 0x063A, 0, + 5, 0xFED0, 0x063A, 0, + 7, 0xFED1, 0x0641, 0, + 6, 0xFED2, 0x0641, 0, + 4, 0xFED3, 0x0641, 0, + 5, 0xFED4, 0x0641, 0, + 7, 0xFED5, 0x0642, 0, + 6, 0xFED6, 0x0642, 0, + 4, 0xFED7, 0x0642, 0, + 5, 0xFED8, 0x0642, 0, + 7, 0xFED9, 0x0643, 0, + 6, 0xFEDA, 0x0643, 0, + 4, 0xFEDB, 0x0643, 0, + 5, 0xFEDC, 0x0643, 0, + 7, 0xFEDD, 0x0644, 0, + 6, 0xFEDE, 0x0644, 0, + 4, 0xFEDF, 0x0644, 0, + 5, 0xFEE0, 0x0644, 0, + 7, 0xFEE1, 0x0645, 0, + 6, 0xFEE2, 0x0645, 0, + 4, 0xFEE3, 0x0645, 0, + 5, 0xFEE4, 0x0645, 0, + 7, 0xFEE5, 0x0646, 0, + 6, 0xFEE6, 0x0646, 0, + 4, 0xFEE7, 0x0646, 0, + 5, 0xFEE8, 0x0646, 0, + 7, 0xFEE9, 0x0647, 0, + 6, 0xFEEA, 0x0647, 0, + 4, 0xFEEB, 0x0647, 0, + 5, 0xFEEC, 0x0647, 0, + 7, 0xFEED, 0x0648, 0, + 6, 0xFEEE, 0x0648, 0, + 7, 0xFEEF, 0x0649, 0, + 6, 0xFEF0, 0x0649, 0, + 7, 0xFEF1, 0x064A, 0, + 6, 0xFEF2, 0x064A, 0, + 4, 0xFEF3, 0x064A, 0, + 5, 0xFEF4, 0x064A, 0, + 7, 0xFEF5, 0x0644, 0x0622, 0, + 6, 0xFEF6, 0x0644, 0x0622, 0, + 7, 0xFEF7, 0x0644, 0x0623, 0, + 6, 0xFEF8, 0x0644, 0x0623, 0, + 7, 0xFEF9, 0x0644, 0x0625, 0, + 6, 0xFEFA, 0x0644, 0x0625, 0, + 7, 0xFEFB, 0x0644, 0x0627, 0, + 6, 0xFEFC, 0x0644, 0x0627, 0, + 12, 0xFF01, 0x0021, 0, + 12, 0xFF02, 0x0022, 0, + 12, 0xFF03, 0x0023, 0, + 12, 0xFF04, 0x0024, 0, + 12, 0xFF05, 0x0025, 0, + 12, 0xFF06, 0x0026, 0, + 12, 0xFF07, 0x0027, 0, + 12, 0xFF08, 0x0028, 0, + 12, 0xFF09, 0x0029, 0, + 12, 0xFF0A, 0x002A, 0, + 12, 0xFF0B, 0x002B, 0, + 12, 0xFF0C, 0x002C, 0, + 12, 0xFF0D, 0x002D, 0, + 12, 0xFF0E, 0x002E, 0, + 12, 0xFF0F, 0x002F, 0, + 12, 0xFF10, 0x0030, 0, + 12, 0xFF11, 0x0031, 0, + 12, 0xFF12, 0x0032, 0, + 12, 0xFF13, 0x0033, 0, + 12, 0xFF14, 0x0034, 0, + 12, 0xFF15, 0x0035, 0, + 12, 0xFF16, 0x0036, 0, + 12, 0xFF17, 0x0037, 0, + 12, 0xFF18, 0x0038, 0, + 12, 0xFF19, 0x0039, 0, + 12, 0xFF1A, 0x003A, 0, + 12, 0xFF1B, 0x003B, 0, + 12, 0xFF1C, 0x003C, 0, + 12, 0xFF1D, 0x003D, 0, + 12, 0xFF1E, 0x003E, 0, + 12, 0xFF1F, 0x003F, 0, + 12, 0xFF20, 0x0040, 0, + 12, 0xFF21, 0x0041, 0, + 12, 0xFF22, 0x0042, 0, + 12, 0xFF23, 0x0043, 0, + 12, 0xFF24, 0x0044, 0, + 12, 0xFF25, 0x0045, 0, + 12, 0xFF26, 0x0046, 0, + 12, 0xFF27, 0x0047, 0, + 12, 0xFF28, 0x0048, 0, + 12, 0xFF29, 0x0049, 0, + 12, 0xFF2A, 0x004A, 0, + 12, 0xFF2B, 0x004B, 0, + 12, 0xFF2C, 0x004C, 0, + 12, 0xFF2D, 0x004D, 0, + 12, 0xFF2E, 0x004E, 0, + 12, 0xFF2F, 0x004F, 0, + 12, 0xFF30, 0x0050, 0, + 12, 0xFF31, 0x0051, 0, + 12, 0xFF32, 0x0052, 0, + 12, 0xFF33, 0x0053, 0, + 12, 0xFF34, 0x0054, 0, + 12, 0xFF35, 0x0055, 0, + 12, 0xFF36, 0x0056, 0, + 12, 0xFF37, 0x0057, 0, + 12, 0xFF38, 0x0058, 0, + 12, 0xFF39, 0x0059, 0, + 12, 0xFF3A, 0x005A, 0, + 12, 0xFF3B, 0x005B, 0, + 12, 0xFF3C, 0x005C, 0, + 12, 0xFF3D, 0x005D, 0, + 12, 0xFF3E, 0x005E, 0, + 12, 0xFF3F, 0x005F, 0, + 12, 0xFF40, 0x0060, 0, + 12, 0xFF41, 0x0061, 0, + 12, 0xFF42, 0x0062, 0, + 12, 0xFF43, 0x0063, 0, + 12, 0xFF44, 0x0064, 0, + 12, 0xFF45, 0x0065, 0, + 12, 0xFF46, 0x0066, 0, + 12, 0xFF47, 0x0067, 0, + 12, 0xFF48, 0x0068, 0, + 12, 0xFF49, 0x0069, 0, + 12, 0xFF4A, 0x006A, 0, + 12, 0xFF4B, 0x006B, 0, + 12, 0xFF4C, 0x006C, 0, + 12, 0xFF4D, 0x006D, 0, + 12, 0xFF4E, 0x006E, 0, + 12, 0xFF4F, 0x006F, 0, + 12, 0xFF50, 0x0070, 0, + 12, 0xFF51, 0x0071, 0, + 12, 0xFF52, 0x0072, 0, + 12, 0xFF53, 0x0073, 0, + 12, 0xFF54, 0x0074, 0, + 12, 0xFF55, 0x0075, 0, + 12, 0xFF56, 0x0076, 0, + 12, 0xFF57, 0x0077, 0, + 12, 0xFF58, 0x0078, 0, + 12, 0xFF59, 0x0079, 0, + 12, 0xFF5A, 0x007A, 0, + 12, 0xFF5B, 0x007B, 0, + 12, 0xFF5C, 0x007C, 0, + 12, 0xFF5D, 0x007D, 0, + 12, 0xFF5E, 0x007E, 0, + 13, 0xFF61, 0x3002, 0, + 13, 0xFF62, 0x300C, 0, + 13, 0xFF63, 0x300D, 0, + 13, 0xFF64, 0x3001, 0, + 13, 0xFF65, 0x30FB, 0, + 13, 0xFF66, 0x30F2, 0, + 13, 0xFF67, 0x30A1, 0, + 13, 0xFF68, 0x30A3, 0, + 13, 0xFF69, 0x30A5, 0, + 13, 0xFF6A, 0x30A7, 0, + 13, 0xFF6B, 0x30A9, 0, + 13, 0xFF6C, 0x30E3, 0, + 13, 0xFF6D, 0x30E5, 0, + 13, 0xFF6E, 0x30E7, 0, + 13, 0xFF6F, 0x30C3, 0, + 13, 0xFF70, 0x30FC, 0, + 13, 0xFF71, 0x30A2, 0, + 13, 0xFF72, 0x30A4, 0, + 13, 0xFF73, 0x30A6, 0, + 13, 0xFF74, 0x30A8, 0, + 13, 0xFF75, 0x30AA, 0, + 13, 0xFF76, 0x30AB, 0, + 13, 0xFF77, 0x30AD, 0, + 13, 0xFF78, 0x30AF, 0, + 13, 0xFF79, 0x30B1, 0, + 13, 0xFF7A, 0x30B3, 0, + 13, 0xFF7B, 0x30B5, 0, + 13, 0xFF7C, 0x30B7, 0, + 13, 0xFF7D, 0x30B9, 0, + 13, 0xFF7E, 0x30BB, 0, + 13, 0xFF7F, 0x30BD, 0, + 13, 0xFF80, 0x30BF, 0, + 13, 0xFF81, 0x30C1, 0, + 13, 0xFF82, 0x30C4, 0, + 13, 0xFF83, 0x30C6, 0, + 13, 0xFF84, 0x30C8, 0, + 13, 0xFF85, 0x30CA, 0, + 13, 0xFF86, 0x30CB, 0, + 13, 0xFF87, 0x30CC, 0, + 13, 0xFF88, 0x30CD, 0, + 13, 0xFF89, 0x30CE, 0, + 13, 0xFF8A, 0x30CF, 0, + 13, 0xFF8B, 0x30D2, 0, + 13, 0xFF8C, 0x30D5, 0, + 13, 0xFF8D, 0x30D8, 0, + 13, 0xFF8E, 0x30DB, 0, + 13, 0xFF8F, 0x30DE, 0, + 13, 0xFF90, 0x30DF, 0, + 13, 0xFF91, 0x30E0, 0, + 13, 0xFF92, 0x30E1, 0, + 13, 0xFF93, 0x30E2, 0, + 13, 0xFF94, 0x30E4, 0, + 13, 0xFF95, 0x30E6, 0, + 13, 0xFF96, 0x30E8, 0, + 13, 0xFF97, 0x30E9, 0, + 13, 0xFF98, 0x30EA, 0, + 13, 0xFF99, 0x30EB, 0, + 13, 0xFF9A, 0x30EC, 0, + 13, 0xFF9B, 0x30ED, 0, + 13, 0xFF9C, 0x30EF, 0, + 13, 0xFF9D, 0x30F3, 0, + 13, 0xFF9E, 0x3099, 0, + 13, 0xFF9F, 0x309A, 0, + 13, 0xFFA0, 0x3164, 0, + 13, 0xFFA1, 0x3131, 0, + 13, 0xFFA2, 0x3132, 0, + 13, 0xFFA3, 0x3133, 0, + 13, 0xFFA4, 0x3134, 0, + 13, 0xFFA5, 0x3135, 0, + 13, 0xFFA6, 0x3136, 0, + 13, 0xFFA7, 0x3137, 0, + 13, 0xFFA8, 0x3138, 0, + 13, 0xFFA9, 0x3139, 0, + 13, 0xFFAA, 0x313A, 0, + 13, 0xFFAB, 0x313B, 0, + 13, 0xFFAC, 0x313C, 0, + 13, 0xFFAD, 0x313D, 0, + 13, 0xFFAE, 0x313E, 0, + 13, 0xFFAF, 0x313F, 0, + 13, 0xFFB0, 0x3140, 0, + 13, 0xFFB1, 0x3141, 0, + 13, 0xFFB2, 0x3142, 0, + 13, 0xFFB3, 0x3143, 0, + 13, 0xFFB4, 0x3144, 0, + 13, 0xFFB5, 0x3145, 0, + 13, 0xFFB6, 0x3146, 0, + 13, 0xFFB7, 0x3147, 0, + 13, 0xFFB8, 0x3148, 0, + 13, 0xFFB9, 0x3149, 0, + 13, 0xFFBA, 0x314A, 0, + 13, 0xFFBB, 0x314B, 0, + 13, 0xFFBC, 0x314C, 0, + 13, 0xFFBD, 0x314D, 0, + 13, 0xFFBE, 0x314E, 0, + 13, 0xFFC2, 0x314F, 0, + 13, 0xFFC3, 0x3150, 0, + 13, 0xFFC4, 0x3151, 0, + 13, 0xFFC5, 0x3152, 0, + 13, 0xFFC6, 0x3153, 0, + 13, 0xFFC7, 0x3154, 0, + 13, 0xFFCA, 0x3155, 0, + 13, 0xFFCB, 0x3156, 0, + 13, 0xFFCC, 0x3157, 0, + 13, 0xFFCD, 0x3158, 0, + 13, 0xFFCE, 0x3159, 0, + 13, 0xFFCF, 0x315A, 0, + 13, 0xFFD2, 0x315B, 0, + 13, 0xFFD3, 0x315C, 0, + 13, 0xFFD4, 0x315D, 0, + 13, 0xFFD5, 0x315E, 0, + 13, 0xFFD6, 0x315F, 0, + 13, 0xFFD7, 0x3160, 0, + 13, 0xFFDA, 0x3161, 0, + 13, 0xFFDB, 0x3162, 0, + 13, 0xFFDC, 0x3163, 0, + 12, 0xFFE0, 0x00A2, 0, + 12, 0xFFE1, 0x00A3, 0, + 12, 0xFFE2, 0x00AC, 0, + 12, 0xFFE3, 0x00AF, 0, + 12, 0xFFE4, 0x00A6, 0, + 12, 0xFFE5, 0x00A5, 0, + 12, 0xFFE6, 0x20A9, 0, + 13, 0xFFE8, 0x2502, 0, + 13, 0xFFE9, 0x2190, 0, + 13, 0xFFEA, 0x2191, 0, + 13, 0xFFEB, 0x2192, 0, + 13, 0xFFEC, 0x2193, 0, + 13, 0xFFED, 0x25A0, 0, + 13, 0xFFEE, 0x25CB, 0, + +}; + +static const Q_UINT16 di_00[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 10, 0, 0, 0, 0, 14, + 0, 0, 19, 23, 27, 32, 0, 0, + 36, 41, 45, 0, 49, 55, 61, 0, + 67, 72, 77, 82, 87, 92, 0, 97, + 102, 107, 112, 117, 122, 127, 132, 137, + 0, 142, 147, 152, 157, 162, 167, 0, + 0, 172, 177, 182, 187, 192, 0, 0, + 197, 202, 207, 212, 217, 222, 0, 227, + 232, 237, 242, 247, 252, 257, 262, 267, + 0, 272, 277, 282, 287, 292, 297, 0, + 0, 302, 307, 312, 317, 322, 0, 327, +}; + +static const Q_UINT16 di_01[] = { + 332, 337, 342, 347, 352, 357, 362, 367, + 372, 377, 382, 387, 392, 397, 402, 407, + 0, 0, 412, 417, 422, 427, 432, 437, + 442, 447, 452, 457, 462, 467, 472, 477, + 482, 487, 492, 497, 502, 507, 0, 0, + 512, 517, 522, 527, 532, 537, 542, 547, + 552, 0, 557, 562, 567, 572, 577, 582, + 0, 587, 592, 597, 602, 607, 612, 617, + 622, 0, 0, 627, 632, 637, 642, 647, + 652, 657, 0, 0, 662, 667, 672, 677, + 682, 687, 0, 0, 692, 697, 702, 707, + 712, 717, 722, 727, 732, 737, 742, 747, + 752, 757, 762, 767, 772, 777, 0, 0, + 782, 787, 792, 797, 802, 807, 812, 817, + 822, 827, 832, 837, 842, 847, 852, 857, + 862, 867, 872, 877, 882, 887, 892, 897, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 901, 906, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 911, + 916, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 921, 926, 931, 936, + 941, 946, 951, 956, 961, 966, 971, 976, + 981, 986, 991, 996, 1001, 1006, 1011, 1016, + 1021, 1026, 1031, 1036, 1041, 0, 1046, 1051, + 1056, 1061, 1066, 1071, 0, 0, 1076, 1081, + 1086, 1091, 1096, 1101, 1106, 1111, 1116, 1121, + 1126, 1131, 1136, 1141, 1146, 1151, 0, 0, + 1156, 1161, 1166, 1171, 1176, 1181, 1186, 1191, +}; + +static const Q_UINT16 di_02[] = { + 1196, 1201, 1206, 1211, 1216, 1221, 1226, 1231, + 1236, 1241, 1246, 1251, 1256, 1261, 1266, 1271, + 1276, 1281, 1286, 1291, 1296, 1301, 1306, 1311, + 1316, 1321, 1326, 1331, 0, 0, 1336, 1341, + 0, 0, 0, 0, 0, 0, 1346, 1351, + 1356, 1361, 1366, 1371, 1376, 1381, 1386, 1391, + 1396, 1401, 1406, 1411, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1416, 1420, 1424, 1428, 1432, 1436, 1440, 1444, + 1448, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1452, 1457, 1462, 1467, 1472, 1477, 0, 0, + 1482, 1486, 1490, 1494, 1498, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_03[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1502, 1506, 0, 1510, 1514, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1519, 0, 0, 0, + 0, 0, 1523, 0, 0, 0, 1528, 0, + 0, 0, 0, 0, 1532, 1537, 1542, 1547, + 1551, 1556, 1561, 0, 1566, 0, 1571, 1576, + 1581, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1586, 1591, 1596, 1601, 1606, 1611, + 1616, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1621, 1626, 1631, 1636, 1641, 0, + 1646, 1650, 1654, 1658, 1663, 1668, 1672, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1676, 1680, 1684, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_04[] = { + 1688, 1693, 0, 1698, 0, 0, 0, 1703, + 0, 0, 0, 0, 1708, 1713, 1718, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1723, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1728, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1733, 1738, 0, 1743, 0, 0, 0, 1748, + 0, 0, 0, 0, 1753, 1758, 1763, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1768, 1773, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1778, 1783, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1788, 1793, 1798, 1803, 0, 0, 1808, 1813, + 0, 0, 1818, 1823, 1828, 1833, 1838, 1843, + 0, 0, 1848, 1853, 1858, 1863, 1868, 1873, + 0, 0, 1878, 1883, 1888, 1893, 1898, 1903, + 1908, 1913, 1918, 1923, 1928, 1933, 0, 0, + 1938, 1943, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_05[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1948, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_06[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1953, 1958, 1963, 1968, 1973, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1978, 1983, 1988, + 1993, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1998, 0, 2003, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2008, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_07[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_09[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2013, 0, 0, 0, 0, 0, 0, + 0, 2018, 0, 0, 2023, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2028, 2033, 2038, 2043, 2048, 2053, 2058, 2063, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2068, 2073, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2078, 2083, 0, 2088, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_0A[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2093, 0, 0, 2098, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2103, 2108, 2113, 0, 0, 2118, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_0B[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2123, 0, 0, 2128, 2133, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2138, 2143, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2148, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2153, 2158, 2163, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_0C[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2168, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2173, 0, 0, 0, 0, 0, 0, 2178, + 2183, 0, 2188, 2193, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_0D[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2198, 2203, 2208, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2213, 0, 2218, 2223, 2228, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_0E[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2233, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2238, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2243, 2248, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_0F[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2253, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2257, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2262, 0, 0, + 0, 0, 2267, 0, 0, 0, 0, 2272, + 0, 0, 0, 0, 2277, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2282, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2287, 0, 2292, 2297, 2302, + 2307, 2312, 0, 0, 0, 0, 0, 0, + 0, 2317, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2322, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2327, 0, 0, + 0, 0, 2332, 0, 0, 0, 0, 2337, + 0, 0, 0, 0, 2342, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2347, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_10[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2352, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_1E[] = { + 2357, 2362, 2367, 2372, 2377, 2382, 2387, 2392, + 2397, 2402, 2407, 2412, 2417, 2422, 2427, 2432, + 2437, 2442, 2447, 2452, 2457, 2462, 2467, 2472, + 2477, 2482, 2487, 2492, 2497, 2502, 2507, 2512, + 2517, 2522, 2527, 2532, 2537, 2542, 2547, 2552, + 2557, 2562, 2567, 2572, 2577, 2582, 2587, 2592, + 2597, 2602, 2607, 2612, 2617, 2622, 2627, 2632, + 2637, 2642, 2647, 2652, 2657, 2662, 2667, 2672, + 2677, 2682, 2687, 2692, 2697, 2702, 2707, 2712, + 2717, 2722, 2727, 2732, 2737, 2742, 2747, 2752, + 2757, 2762, 2767, 2772, 2777, 2782, 2787, 2792, + 2797, 2802, 2807, 2812, 2817, 2822, 2827, 2832, + 2837, 2842, 2847, 2852, 2857, 2862, 2867, 2872, + 2877, 2882, 2887, 2892, 2897, 2902, 2907, 2912, + 2917, 2922, 2927, 2932, 2937, 2942, 2947, 2952, + 2957, 2962, 2967, 2972, 2977, 2982, 2987, 2992, + 2997, 3002, 3007, 3012, 3017, 3022, 3027, 3032, + 3037, 3042, 3047, 3052, 3057, 3062, 3067, 3072, + 3077, 3082, 3087, 3092, 3097, 3102, 3107, 3112, + 3117, 3122, 3127, 3132, 0, 0, 0, 0, + 3137, 3142, 3147, 3152, 3157, 3162, 3167, 3172, + 3177, 3182, 3187, 3192, 3197, 3202, 3207, 3212, + 3217, 3222, 3227, 3232, 3237, 3242, 3247, 3252, + 3257, 3262, 3267, 3272, 3277, 3282, 3287, 3292, + 3297, 3302, 3307, 3312, 3317, 3322, 3327, 3332, + 3337, 3342, 3347, 3352, 3357, 3362, 3367, 3372, + 3377, 3382, 3387, 3392, 3397, 3402, 3407, 3412, + 3417, 3422, 3427, 3432, 3437, 3442, 3447, 3452, + 3457, 3462, 3467, 3472, 3477, 3482, 3487, 3492, + 3497, 3502, 3507, 3512, 3517, 3522, 3527, 3532, + 3537, 3542, 3547, 3552, 3557, 3562, 3567, 3572, + 3577, 3582, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_1F[] = { + 3587, 3592, 3597, 3602, 3607, 3612, 3617, 3622, + 3627, 3632, 3637, 3642, 3647, 3652, 3657, 3662, + 3667, 3672, 3677, 3682, 3687, 3692, 0, 0, + 3697, 3702, 3707, 3712, 3717, 3722, 0, 0, + 3727, 3732, 3737, 3742, 3747, 3752, 3757, 3762, + 3767, 3772, 3777, 3782, 3787, 3792, 3797, 3802, + 3807, 3812, 3817, 3822, 3827, 3832, 3837, 3842, + 3847, 3852, 3857, 3862, 3867, 3872, 3877, 3882, + 3887, 3892, 3897, 3902, 3907, 3912, 0, 0, + 3917, 3922, 3927, 3932, 3937, 3942, 0, 0, + 3947, 3952, 3957, 3962, 3967, 3972, 3977, 3982, + 0, 3987, 0, 3992, 0, 3997, 0, 4002, + 4007, 4012, 4017, 4022, 4027, 4032, 4037, 4042, + 4047, 4052, 4057, 4062, 4067, 4072, 4077, 4082, + 4087, 4092, 4096, 4101, 4105, 4110, 4114, 4119, + 4123, 4128, 4132, 4137, 4141, 4146, 0, 0, + 4150, 4155, 4160, 4165, 4170, 4175, 4180, 4185, + 4190, 4195, 4200, 4205, 4210, 4215, 4220, 4225, + 4230, 4235, 4240, 4245, 4250, 4255, 4260, 4265, + 4270, 4275, 4280, 4285, 4290, 4295, 4300, 4305, + 4310, 4315, 4320, 4325, 4330, 4335, 4340, 4345, + 4350, 4355, 4360, 4365, 4370, 4375, 4380, 4385, + 4390, 4395, 4400, 4405, 4410, 0, 4415, 4420, + 4425, 4430, 4435, 4440, 4444, 4449, 4454, 4458, + 4463, 4468, 4473, 4478, 4483, 0, 4488, 4493, + 4498, 4503, 4507, 4512, 4516, 4521, 4526, 4531, + 4536, 4541, 4546, 4551, 0, 0, 4555, 4560, + 4565, 4570, 4575, 4580, 0, 4584, 4589, 4594, + 4599, 4604, 4609, 4614, 4618, 4623, 4628, 4633, + 4638, 4643, 4648, 4653, 4657, 4662, 4667, 4671, + 0, 0, 4675, 4680, 4685, 0, 4690, 4695, + 4700, 4705, 4709, 4714, 4718, 4723, 4727, 0, +}; + +static const Q_UINT16 di_20[] = { + 4732, 4736, 4740, 4744, 4748, 4752, 4756, 4760, + 4764, 4768, 4772, 0, 0, 0, 0, 0, + 0, 4776, 0, 0, 0, 0, 0, 4780, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4785, 4789, 4794, 0, + 0, 0, 0, 0, 0, 0, 0, 4800, + 0, 0, 0, 4804, 4809, 0, 4815, 4820, + 0, 0, 0, 0, 4826, 0, 4831, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4836, 4841, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4846, 0, 0, 0, 4850, 4854, 4858, 4862, + 4866, 4870, 4874, 4878, 4882, 4886, 4890, 4894, + 4898, 4902, 4906, 4910, 4914, 4918, 4922, 4926, + 4930, 4934, 4938, 4942, 4946, 4950, 4954, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4958, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_21[] = { + 4963, 4969, 4975, 4979, 0, 4984, 4990, 4996, + 0, 5000, 5005, 5009, 5013, 5017, 5021, 5025, + 5029, 5033, 5037, 5041, 0, 5045, 5049, 0, + 0, 5054, 5058, 5062, 5066, 5070, 0, 0, + 5074, 5079, 5085, 0, 5090, 0, 5094, 0, + 5098, 0, 5102, 5106, 5110, 5114, 0, 5118, + 5122, 5126, 0, 5130, 5134, 5138, 5142, 5146, + 5150, 5154, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 5158, 5164, 5170, 5176, 5182, + 5188, 5194, 5200, 5206, 5212, 5218, 5224, 5230, + 5235, 5239, 5244, 5250, 5255, 5259, 5264, 5270, + 5277, 5282, 5286, 5291, 5297, 5301, 5305, 5309, + 5313, 5317, 5322, 5328, 5333, 5337, 5342, 5348, + 5355, 5360, 5364, 5369, 5375, 5379, 5383, 5387, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 5391, 5396, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 5401, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 5406, 5411, 5416, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_22[] = { + 0, 0, 0, 0, 5421, 0, 0, 0, + 0, 5426, 0, 0, 5431, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5436, 0, 5441, 0, + 0, 0, 0, 0, 5446, 5451, 0, 5457, + 5462, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5468, 0, 0, 5473, 0, 0, 5478, + 0, 5483, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5488, 0, 5493, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 5498, 5503, 5508, + 5513, 5518, 0, 0, 5523, 5528, 0, 0, + 5533, 5538, 0, 0, 0, 0, 0, 0, + 5543, 5548, 0, 0, 5553, 5558, 0, 0, + 5563, 5568, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 5573, 5578, 5583, 5588, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5593, 5598, 5603, 5608, 0, 0, 0, 0, + 0, 0, 5613, 5618, 5623, 5628, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_23[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5633, 5637, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_24[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5641, 5645, 5649, 5653, 5657, 5661, 5665, 5669, + 5673, 5677, 5682, 5687, 5692, 5697, 5702, 5707, + 5712, 5717, 5722, 5727, 5732, 5738, 5744, 5750, + 5756, 5762, 5768, 5774, 5780, 5786, 5793, 5800, + 5807, 5814, 5821, 5828, 5835, 5842, 5849, 5856, + 5863, 5868, 5873, 5878, 5883, 5888, 5893, 5898, + 5903, 5908, 5914, 5920, 5926, 5932, 5938, 5944, + 5950, 5956, 5962, 5968, 5974, 5980, 5986, 5992, + 5998, 6004, 6010, 6016, 6022, 6028, 6034, 6040, + 6046, 6052, 6058, 6064, 6070, 6076, 6082, 6088, + 6094, 6100, 6106, 6112, 6118, 6124, 6130, 6134, + 6138, 6142, 6146, 6150, 6154, 6158, 6162, 6166, + 6170, 6174, 6178, 6182, 6186, 6190, 6194, 6198, + 6202, 6206, 6210, 6214, 6218, 6222, 6226, 6230, + 6234, 6238, 6242, 6246, 6250, 6254, 6258, 6262, + 6266, 6270, 6274, 6278, 6282, 6286, 6290, 6294, + 6298, 6302, 6306, 6310, 6314, 6318, 6322, 6326, + 6330, 6334, 6338, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_2E[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 6342, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 6346, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_2F[] = { + 6350, 6354, 6358, 6362, 6366, 6370, 6374, 6378, + 6382, 6386, 6390, 6394, 6398, 6402, 6406, 6410, + 6414, 6418, 6422, 6426, 6430, 6434, 6438, 6442, + 6446, 6450, 6454, 6458, 6462, 6466, 6470, 6474, + 6478, 6482, 6486, 6490, 6494, 6498, 6502, 6506, + 6510, 6514, 6518, 6522, 6526, 6530, 6534, 6538, + 6542, 6546, 6550, 6554, 6558, 6562, 6566, 6570, + 6574, 6578, 6582, 6586, 6590, 6594, 6598, 6602, + 6606, 6610, 6614, 6618, 6622, 6626, 6630, 6634, + 6638, 6642, 6646, 6650, 6654, 6658, 6662, 6666, + 6670, 6674, 6678, 6682, 6686, 6690, 6694, 6698, + 6702, 6706, 6710, 6714, 6718, 6722, 6726, 6730, + 6734, 6738, 6742, 6746, 6750, 6754, 6758, 6762, + 6766, 6770, 6774, 6778, 6782, 6786, 6790, 6794, + 6798, 6802, 6806, 6810, 6814, 6818, 6822, 6826, + 6830, 6834, 6838, 6842, 6846, 6850, 6854, 6858, + 6862, 6866, 6870, 6874, 6878, 6882, 6886, 6890, + 6894, 6898, 6902, 6906, 6910, 6914, 6918, 6922, + 6926, 6930, 6934, 6938, 6942, 6946, 6950, 6954, + 6958, 6962, 6966, 6970, 6974, 6978, 6982, 6986, + 6990, 6994, 6998, 7002, 7006, 7010, 7014, 7018, + 7022, 7026, 7030, 7034, 7038, 7042, 7046, 7050, + 7054, 7058, 7062, 7066, 7070, 7074, 7078, 7082, + 7086, 7090, 7094, 7098, 7102, 7106, 7110, 7114, + 7118, 7122, 7126, 7130, 7134, 7138, 7142, 7146, + 7150, 7154, 7158, 7162, 7166, 7170, 7174, 7178, + 7182, 7186, 7190, 7194, 7198, 7202, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_30[] = { + 7206, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 7210, 0, + 7214, 7218, 7222, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7226, 0, 7231, 0, + 7236, 0, 7241, 0, 7246, 0, 7251, 0, + 7256, 0, 7261, 0, 7266, 0, 7271, 0, + 7276, 0, 7281, 0, 0, 7286, 0, 7291, + 0, 7296, 0, 0, 0, 0, 0, 0, + 7301, 7306, 0, 7311, 7316, 0, 7321, 7326, + 0, 7331, 7336, 0, 7341, 7346, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7351, 0, 0, 0, + 0, 0, 0, 7356, 7361, 0, 7366, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7371, 0, 7376, 0, + 7381, 0, 7386, 0, 7391, 0, 7396, 0, + 7401, 0, 7406, 0, 7411, 0, 7416, 0, + 7421, 0, 7426, 0, 0, 7431, 0, 7436, + 0, 7441, 0, 0, 0, 0, 0, 0, + 7446, 7451, 0, 7456, 7461, 0, 7466, 7471, + 0, 7476, 7481, 0, 7486, 7491, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 7496, 0, 0, 7501, + 7506, 7511, 7516, 0, 0, 0, 7521, 0, +}; + +static const Q_UINT16 di_31[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7526, 7530, 7534, 7538, 7542, 7546, 7550, + 7554, 7558, 7562, 7566, 7570, 7574, 7578, 7582, + 7586, 7590, 7594, 7598, 7602, 7606, 7610, 7614, + 7618, 7622, 7626, 7630, 7634, 7638, 7642, 7646, + 7650, 7654, 7658, 7662, 7666, 7670, 7674, 7678, + 7682, 7686, 7690, 7694, 7698, 7702, 7706, 7710, + 7714, 7718, 7722, 7726, 7730, 7734, 7738, 7742, + 7746, 7750, 7754, 7758, 7762, 7766, 7770, 7774, + 7778, 7782, 7786, 7790, 7794, 7798, 7802, 7806, + 7810, 7814, 7818, 7822, 7826, 7830, 7834, 7838, + 7842, 7846, 7850, 7854, 7858, 7862, 7866, 7870, + 7874, 7878, 7882, 7886, 7890, 7894, 7898, 0, + 0, 0, 7902, 7906, 7910, 7914, 7918, 7922, + 7926, 7930, 7934, 7938, 7942, 7946, 7950, 7954, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_32[] = { + 7958, 7964, 7970, 7976, 7982, 7988, 7994, 8000, + 8006, 8012, 8018, 8024, 8030, 8036, 8042, 8049, + 8056, 8063, 8070, 8077, 8084, 8091, 8098, 8105, + 8112, 8119, 8126, 8133, 8140, 0, 0, 0, + 8147, 8153, 8159, 8165, 8171, 8177, 8183, 8189, + 8195, 8201, 8207, 8213, 8219, 8225, 8231, 8237, + 8243, 8249, 8255, 8261, 8267, 8273, 8279, 8285, + 8291, 8297, 8303, 8309, 8315, 8321, 8327, 8333, + 8339, 8345, 8351, 8357, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8363, 8367, 8371, 8375, 8379, 8383, 8387, 8391, + 8395, 8399, 8403, 8407, 8411, 8415, 8419, 8424, + 8429, 8434, 8439, 8444, 8449, 8454, 8459, 8464, + 8469, 8474, 8479, 8484, 0, 0, 0, 0, + 8489, 8493, 8497, 8501, 8505, 8509, 8513, 8517, + 8521, 8525, 8529, 8533, 8537, 8541, 8545, 8549, + 8553, 8557, 8561, 8565, 8569, 8573, 8577, 8581, + 8585, 8589, 8593, 8597, 8601, 8605, 8609, 8613, + 8617, 8621, 8625, 8629, 8633, 8637, 8641, 8645, + 8649, 8653, 8657, 8661, 8665, 8669, 8673, 8677, + 8681, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 8685, 8690, 8695, 8700, 8705, 8710, 8715, 8720, + 8725, 8730, 8736, 8742, 0, 0, 0, 0, + 8748, 8752, 8756, 8760, 8764, 8768, 8772, 8776, + 8780, 8784, 8788, 8792, 8796, 8800, 8804, 8808, + 8812, 8816, 8820, 8824, 8828, 8832, 8836, 8840, + 8844, 8848, 8852, 8856, 8860, 8864, 8868, 8872, + 8876, 8880, 8884, 8888, 8892, 8896, 8900, 8904, + 8908, 8912, 8916, 8920, 8924, 8928, 8932, 0, +}; + +static const Q_UINT16 di_33[] = { + 8936, 8943, 8950, 8957, 8963, 8970, 8976, 8982, + 8990, 8997, 9003, 9009, 9015, 9022, 9029, 9035, + 9041, 9046, 9052, 9059, 9066, 9071, 9079, 9088, + 9096, 9102, 9110, 9118, 9125, 9131, 9137, 9143, + 9150, 9158, 9165, 9171, 9177, 9183, 9188, 9193, + 9198, 9203, 9209, 9215, 9223, 9229, 9236, 9244, + 9250, 9255, 9260, 9268, 9275, 9283, 9289, 9297, + 9302, 9308, 9314, 9320, 9326, 9332, 9339, 9345, + 9350, 9356, 9362, 9368, 9375, 9381, 9387, 9393, + 9401, 9408, 9413, 9421, 9426, 9433, 9440, 9446, + 9452, 9458, 9465, 9470, 9476, 9483, 9488, 9496, + 9502, 9507, 9512, 9517, 9522, 9527, 9532, 9537, + 9542, 9547, 9552, 9558, 9564, 9570, 9576, 9582, + 9588, 9594, 9600, 9606, 9612, 9618, 9624, 9630, + 9636, 9642, 9648, 9653, 9658, 9664, 9669, 0, + 0, 0, 0, 9674, 9679, 9684, 9689, 9694, + 9701, 9706, 9711, 9716, 9721, 9726, 9731, 9736, + 9741, 9747, 9754, 9759, 9764, 9769, 9774, 9779, + 9784, 9789, 9795, 9801, 9807, 9813, 9818, 9823, + 9828, 9833, 9838, 9843, 9848, 9853, 9858, 9863, + 9869, 9875, 9880, 9886, 9892, 9898, 9903, 9909, + 9915, 9922, 9927, 9933, 9939, 9945, 9951, 9959, + 9968, 9973, 9978, 9983, 9988, 9993, 9998, 10003, + 10008, 10013, 10018, 10023, 10028, 10033, 10038, 10043, + 10048, 10053, 10058, 10065, 10070, 10075, 10080, 10087, + 10093, 10098, 10103, 10108, 10113, 10118, 10123, 10128, + 10133, 10138, 10143, 10149, 10154, 10159, 10165, 10171, + 10176, 10183, 10189, 10194, 10199, 10204, 0, 0, + 10209, 10214, 10219, 10224, 10229, 10234, 10239, 10244, + 10249, 10254, 10260, 10266, 10272, 10278, 10284, 10290, + 10296, 10302, 10308, 10314, 10320, 10326, 10332, 10338, + 10344, 10350, 10356, 10362, 10368, 10374, 10380, 0, +}; + +static const Q_UINT16 di_F9[] = { + 10386, 10390, 10394, 10398, 10402, 10406, 10410, 10414, + 10418, 10422, 10426, 10430, 10434, 10438, 10442, 10446, + 10450, 10454, 10458, 10462, 10466, 10470, 10474, 10478, + 10482, 10486, 10490, 10494, 10498, 10502, 10506, 10510, + 10514, 10518, 10522, 10526, 10530, 10534, 10538, 10542, + 10546, 10550, 10554, 10558, 10562, 10566, 10570, 10574, + 10578, 10582, 10586, 10590, 10594, 10598, 10602, 10606, + 10610, 10614, 10618, 10622, 10626, 10630, 10634, 10638, + 10642, 10646, 10650, 10654, 10658, 10662, 10666, 10670, + 10674, 10678, 10682, 10686, 10690, 10694, 10698, 10702, + 10706, 10710, 10714, 10718, 10722, 10726, 10730, 10734, + 10738, 10742, 10746, 10750, 10754, 10758, 10762, 10766, + 10770, 10774, 10778, 10782, 10786, 10790, 10794, 10798, + 10802, 10806, 10810, 10814, 10818, 10822, 10826, 10830, + 10834, 10838, 10842, 10846, 10850, 10854, 10858, 10862, + 10866, 10870, 10874, 10878, 10882, 10886, 10890, 10894, + 10898, 10902, 10906, 10910, 10914, 10918, 10922, 10926, + 10930, 10934, 10938, 10942, 10946, 10950, 10954, 10958, + 10962, 10966, 10970, 10974, 10978, 10982, 10986, 10990, + 10994, 10998, 11002, 11006, 11010, 11014, 11018, 11022, + 11026, 11030, 11034, 11038, 11042, 11046, 11050, 11054, + 11058, 11062, 11066, 11070, 11074, 11078, 11082, 11086, + 11090, 11094, 11098, 11102, 11106, 11110, 11114, 11118, + 11122, 11126, 11130, 11134, 11138, 11142, 11146, 11150, + 11154, 11158, 11162, 11166, 11170, 11174, 11178, 11182, + 11186, 11190, 11194, 11198, 11202, 11206, 11210, 11214, + 11218, 11222, 11226, 11230, 11234, 11238, 11242, 11246, + 11250, 11254, 11258, 11262, 11266, 11270, 11274, 11278, + 11282, 11286, 11290, 11294, 11298, 11302, 11306, 11310, + 11314, 11318, 11322, 11326, 11330, 11334, 11338, 11342, + 11346, 11350, 11354, 11358, 11362, 11366, 11370, 11374, + 11378, 11382, 11386, 11390, 11394, 11398, 11402, 11406, +}; + +static const Q_UINT16 di_FA[] = { + 11410, 11414, 11418, 11422, 11426, 11430, 11434, 11438, + 11442, 11446, 11450, 11454, 11458, 11462, 0, 0, + 11466, 0, 11470, 0, 0, 11474, 11478, 11482, + 11486, 11490, 11494, 11498, 11502, 11506, 11510, 0, + 11514, 0, 11518, 0, 0, 11522, 11526, 0, + 0, 0, 11530, 11534, 11538, 11542, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_FB[] = { + 11546, 11551, 11556, 11561, 11567, 11573, 11578, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 11583, 11588, 11593, 11598, 11603, + 0, 0, 0, 0, 0, 11608, 0, 11613, + 11618, 11622, 11626, 11630, 11634, 11638, 11642, 11646, + 11650, 11654, 11658, 11663, 11668, 11673, 11678, 11683, + 11688, 11693, 11698, 11703, 11708, 11713, 11718, 0, + 11723, 11728, 11733, 11738, 11743, 0, 11748, 0, + 11753, 11758, 0, 11763, 11768, 0, 11773, 11778, + 11783, 11788, 11793, 11798, 11803, 11808, 11813, 11818, + 11823, 11827, 11831, 11835, 11839, 11843, 11847, 11851, + 11855, 11859, 11863, 11867, 11871, 11875, 11879, 11883, + 11887, 11891, 11895, 11899, 11903, 11907, 11911, 11915, + 11919, 11923, 11927, 11931, 11935, 11939, 11943, 11947, + 11951, 11955, 11959, 11963, 11967, 11971, 11975, 11979, + 11983, 11987, 11991, 11995, 11999, 12003, 12007, 12011, + 12015, 12019, 12023, 12027, 12031, 12035, 12039, 12043, + 12047, 12051, 12055, 12059, 12063, 12067, 12071, 12075, + 12079, 12083, 12087, 12091, 12095, 12099, 12103, 12107, + 12111, 12115, 12119, 12123, 12127, 12131, 12135, 12139, + 12143, 12147, 12151, 12155, 12159, 12163, 12167, 12171, + 12175, 12179, 12183, 12187, 12191, 12195, 12199, 12203, + 12207, 12211, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 12215, 12219, 12223, 12227, 12231, + 12235, 12239, 12243, 12247, 12251, 12255, 12259, 12263, + 12267, 12271, 12275, 12279, 12283, 12287, 12291, 12295, + 12299, 12303, 12307, 12312, 12317, 12322, 12327, 12332, + 12337, 12342, 12347, 12352, 12357, 12362, 12367, 12372, + 12377, 12382, 12387, 12392, 12397, 12401, 12405, 12409, +}; + +static const Q_UINT16 di_FC[] = { + 12413, 12418, 12423, 12428, 12433, 12438, 12443, 12448, + 12453, 12458, 12463, 12468, 12473, 12478, 12483, 12488, + 12493, 12498, 12503, 12508, 12513, 12518, 12523, 12528, + 12533, 12538, 12543, 12548, 12553, 12558, 12563, 12568, + 12573, 12578, 12583, 12588, 12593, 12598, 12603, 12608, + 12613, 12618, 12623, 12628, 12633, 12638, 12643, 12648, + 12653, 12658, 12663, 12668, 12673, 12678, 12683, 12688, + 12693, 12698, 12703, 12708, 12713, 12718, 12723, 12728, + 12733, 12738, 12743, 12748, 12753, 12758, 12763, 12768, + 12773, 12778, 12783, 12788, 12793, 12798, 12803, 12808, + 12813, 12818, 12823, 12828, 12833, 12838, 12843, 12848, + 12853, 12858, 12863, 12868, 12873, 12878, 12883, 12889, + 12895, 12901, 12907, 12913, 12919, 12924, 12929, 12934, + 12939, 12944, 12949, 12954, 12959, 12964, 12969, 12974, + 12979, 12984, 12989, 12994, 12999, 13004, 13009, 13014, + 13019, 13024, 13029, 13034, 13039, 13044, 13049, 13054, + 13059, 13064, 13069, 13074, 13079, 13084, 13089, 13094, + 13099, 13104, 13109, 13114, 13119, 13124, 13129, 13134, + 13139, 13144, 13149, 13154, 13159, 13164, 13169, 13174, + 13179, 13184, 13189, 13194, 13199, 13204, 13209, 13214, + 13219, 13224, 13229, 13234, 13239, 13244, 13249, 13254, + 13259, 13264, 13269, 13274, 13279, 13284, 13289, 13294, + 13299, 13304, 13309, 13314, 13319, 13324, 13329, 13334, + 13339, 13344, 13349, 13354, 13359, 13364, 13369, 13374, + 13379, 13384, 13389, 13394, 13399, 13404, 13409, 13414, + 13419, 13424, 13429, 13434, 13439, 13444, 13449, 13454, + 13459, 13464, 13469, 13474, 13479, 13484, 13489, 13494, + 13499, 13504, 13509, 13514, 13519, 13524, 13529, 13534, + 13539, 13544, 13549, 13554, 13559, 13564, 13569, 13574, + 13579, 13584, 13589, 13594, 13599, 13604, 13609, 13614, + 13619, 13624, 13629, 13635, 13641, 13647, 13652, 13657, + 13662, 13667, 13672, 13677, 13682, 13687, 13692, 13697, +}; + +static const Q_UINT16 di_FD[] = { + 13702, 13707, 13712, 13717, 13722, 13727, 13732, 13737, + 13742, 13747, 13752, 13757, 13762, 13767, 13772, 13777, + 13782, 13787, 13792, 13797, 13802, 13807, 13812, 13817, + 13822, 13827, 13832, 13837, 13842, 13847, 13852, 13857, + 13862, 13867, 13872, 13877, 13882, 13887, 13892, 13897, + 13902, 13907, 13912, 13917, 13922, 13927, 13932, 13937, + 13942, 13947, 13952, 13957, 13962, 13967, 13972, 13977, + 13982, 13987, 13992, 13997, 14002, 14007, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14012, 14018, 14024, 14030, 14036, 14042, 14048, 14054, + 14060, 14066, 14072, 14078, 14084, 14090, 14096, 14102, + 14108, 14114, 14120, 14126, 14132, 14138, 14144, 14150, + 14156, 14162, 14168, 14174, 14180, 14186, 14192, 14198, + 14204, 14210, 14216, 14222, 14228, 14234, 14240, 14246, + 14252, 14258, 14264, 14270, 14276, 14282, 14288, 14294, + 14300, 14306, 14312, 14318, 14324, 14330, 14336, 14342, + 14348, 14354, 14360, 14366, 14372, 14378, 14384, 14390, + 0, 0, 14396, 14402, 14408, 14414, 14420, 14426, + 14432, 14438, 14444, 14450, 14456, 14462, 14468, 14474, + 14480, 14486, 14492, 14498, 14504, 14510, 14516, 14522, + 14528, 14534, 14540, 14546, 14552, 14558, 14564, 14570, + 14576, 14582, 14588, 14594, 14600, 14606, 14612, 14618, + 14624, 14630, 14636, 14642, 14648, 14654, 14660, 14666, + 14672, 14678, 14684, 14690, 14696, 14702, 14708, 14714, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14720, 14726, 14732, 14739, 14746, 14753, 14760, 14767, + 14774, 14781, 14787, 14808, 0, 0, 0, 0, +}; + +static const Q_UINT16 di_FE[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 14819, 14823, 14827, 14831, 14835, 14839, 14843, 14847, + 14851, 14855, 14859, 14863, 14867, 14871, 14875, 14879, + 14883, 14887, 14891, 14895, 14899, 0, 0, 0, + 0, 14903, 14907, 14911, 14915, 14919, 14923, 14927, + 14931, 14935, 14939, 0, 14943, 14947, 14951, 14955, + 14959, 14963, 14967, 14971, 14975, 14979, 14983, 14987, + 14991, 14995, 14999, 15003, 15007, 15011, 15015, 0, + 15019, 15023, 15027, 15031, 0, 0, 0, 0, + 15035, 15040, 15045, 0, 15050, 0, 15055, 15060, + 15065, 15070, 15075, 15080, 15085, 15090, 15095, 15100, + 15105, 15109, 15113, 15117, 15121, 15125, 15129, 15133, + 15137, 15141, 15145, 15149, 15153, 15157, 15161, 15165, + 15169, 15173, 15177, 15181, 15185, 15189, 15193, 15197, + 15201, 15205, 15209, 15213, 15217, 15221, 15225, 15229, + 15233, 15237, 15241, 15245, 15249, 15253, 15257, 15261, + 15265, 15269, 15273, 15277, 15281, 15285, 15289, 15293, + 15297, 15301, 15305, 15309, 15313, 15317, 15321, 15325, + 15329, 15333, 15337, 15341, 15345, 15349, 15353, 15357, + 15361, 15365, 15369, 15373, 15377, 15381, 15385, 15389, + 15393, 15397, 15401, 15405, 15409, 15413, 15417, 15421, + 15425, 15429, 15433, 15437, 15441, 15445, 15449, 15453, + 15457, 15461, 15465, 15469, 15473, 15477, 15481, 15485, + 15489, 15493, 15497, 15501, 15505, 15509, 15513, 15517, + 15521, 15525, 15529, 15533, 15537, 15541, 15545, 15549, + 15553, 15557, 15561, 15565, 15569, 15573, 15578, 15583, + 15588, 15593, 15598, 15603, 15608, 0, 0, 0, +}; + +static const Q_UINT16 di_FF[] = { + 0, 15613, 15617, 15621, 15625, 15629, 15633, 15637, + 15641, 15645, 15649, 15653, 15657, 15661, 15665, 15669, + 15673, 15677, 15681, 15685, 15689, 15693, 15697, 15701, + 15705, 15709, 15713, 15717, 15721, 15725, 15729, 15733, + 15737, 15741, 15745, 15749, 15753, 15757, 15761, 15765, + 15769, 15773, 15777, 15781, 15785, 15789, 15793, 15797, + 15801, 15805, 15809, 15813, 15817, 15821, 15825, 15829, + 15833, 15837, 15841, 15845, 15849, 15853, 15857, 15861, + 15865, 15869, 15873, 15877, 15881, 15885, 15889, 15893, + 15897, 15901, 15905, 15909, 15913, 15917, 15921, 15925, + 15929, 15933, 15937, 15941, 15945, 15949, 15953, 15957, + 15961, 15965, 15969, 15973, 15977, 15981, 15985, 0, + 0, 15989, 15993, 15997, 16001, 16005, 16009, 16013, + 16017, 16021, 16025, 16029, 16033, 16037, 16041, 16045, + 16049, 16053, 16057, 16061, 16065, 16069, 16073, 16077, + 16081, 16085, 16089, 16093, 16097, 16101, 16105, 16109, + 16113, 16117, 16121, 16125, 16129, 16133, 16137, 16141, + 16145, 16149, 16153, 16157, 16161, 16165, 16169, 16173, + 16177, 16181, 16185, 16189, 16193, 16197, 16201, 16205, + 16209, 16213, 16217, 16221, 16225, 16229, 16233, 16237, + 16241, 16245, 16249, 16253, 16257, 16261, 16265, 16269, + 16273, 16277, 16281, 16285, 16289, 16293, 16297, 16301, + 16305, 16309, 16313, 16317, 16321, 16325, 16329, 16333, + 16337, 16341, 16345, 16349, 16353, 16357, 16361, 0, + 0, 0, 16365, 16369, 16373, 16377, 16381, 16385, + 0, 0, 16389, 16393, 16397, 16401, 16405, 16409, + 0, 0, 16413, 16417, 16421, 16425, 16429, 16433, + 0, 0, 16437, 16441, 16445, 0, 0, 0, + 16449, 16453, 16457, 16461, 16465, 16469, 16473, 0, + 16477, 16481, 16485, 16489, 16493, 16497, 16501, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 * const decomposition_info[256] = { + di_00, di_01, di_02, di_03, di_04, di_05, di_06, di_07, + di_07, di_09, di_0A, di_0B, di_0C, di_0D, di_0E, di_0F, + di_10, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_1E, di_1F, + di_20, di_21, di_22, di_23, di_24, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_2E, di_2F, + di_30, di_31, di_32, di_33, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_07, di_07, di_07, di_07, di_07, di_07, di_07, + di_07, di_F9, di_FA, di_FB, di_FC, di_FD, di_FE, di_FF, +}; +// 68080 bytes + +static const Q_UINT16 ligature_map [] = { + 0, + 12883, 12889, 12895, 12901, 12907, 12913, 15035, 15045, 15050, 15055, 15065, 15075, 15085, 15095, 0, + 5503, 0, + 5488, 0, + 5508, 0, + 67, 72, 77, 82, 87, 92, 332, 342, 352, 966, 1196, 1206, 1346, 2357, 3137, 3147, 0, + 2367, 2377, 2387, 0, + 97, 362, 372, 382, 392, 0, + 402, 2407, 2417, 2427, 2437, 2447, 0, + 102, 107, 112, 117, 412, 422, 432, 442, 452, 1216, 1226, 1356, 2477, 2487, 3257, 3267, 3277, 0, + 2507, 0, + 462, 472, 482, 492, 1076, 1146, 2517, 0, + 502, 1336, 2527, 2537, 2547, 2557, 2567, 0, + 122, 127, 132, 137, 512, 522, 532, 542, 552, 976, 1236, 1246, 2577, 3337, 3347, 0, + 567, 0, + 577, 1086, 2597, 2607, 2617, 0, + 587, 597, 607, 2627, 2647, 2657, 0, + 2667, 2677, 2687, 0, + 142, 627, 637, 647, 1156, 2697, 2707, 2717, 2727, 0, + 147, 152, 157, 162, 167, 662, 672, 682, 901, 986, 1096, 1256, 1266, 1386, 3357, 3367, 0, + 2777, 2787, 0, + 692, 702, 712, 1276, 1286, 2797, 2807, 2827, 0, + 722, 732, 742, 752, 1316, 2837, 2847, 0, + 762, 772, 1326, 2887, 2897, 2907, 2917, 0, + 172, 177, 182, 187, 782, 792, 802, 812, 822, 832, 911, 996, 1296, 1306, 2927, 2937, 2947, 3477, 3487, 0, + 2977, 2987, 0, + 842, 2997, 3007, 3017, 3027, 3037, 0, + 3047, 3057, 0, + 192, 852, 862, 1406, 3067, 3547, 3557, 3567, 3577, 0, + 867, 877, 887, 3077, 3087, 3097, 0, + 197, 202, 207, 212, 217, 222, 337, 347, 357, 971, 1201, 1211, 1351, 2362, 3142, 3152, 0, + 2372, 2382, 2392, 0, + 227, 367, 377, 387, 397, 0, + 407, 2412, 2422, 2432, 2442, 2452, 0, + 232, 237, 242, 247, 417, 427, 437, 447, 457, 1221, 1231, 1361, 2482, 2492, 3262, 3272, 3282, 0, + 2512, 0, + 467, 477, 487, 497, 1081, 1151, 2522, 0, + 507, 1341, 2532, 2542, 2552, 2562, 2572, 3107, 0, + 252, 257, 262, 267, 517, 527, 537, 547, 981, 1241, 1251, 2582, 3342, 3352, 0, + 572, 1126, 0, + 582, 1091, 2602, 2612, 2622, 0, + 592, 602, 612, 2632, 2652, 2662, 0, + 2672, 2682, 2692, 0, + 272, 632, 642, 652, 1161, 2702, 2712, 2722, 2732, 0, + 277, 282, 287, 292, 297, 667, 677, 687, 906, 991, 1101, 1261, 1271, 1391, 3362, 3372, 0, + 2782, 2792, 0, + 697, 707, 717, 1281, 1291, 2802, 2812, 2832, 0, + 727, 737, 747, 757, 1321, 2842, 2852, 0, + 767, 777, 1331, 2892, 2902, 2912, 2922, 3112, 0, + 302, 307, 312, 317, 787, 797, 807, 817, 827, 837, 916, 1001, 1301, 1311, 2932, 2942, 2952, 3482, 3492, 0, + 2982, 2992, 0, + 847, 3002, 3012, 3022, 3032, 3042, 3117, 0, + 3052, 3062, 0, + 322, 327, 857, 1411, 3072, 3122, 3552, 3562, 3572, 3582, 0, + 872, 882, 892, 3082, 3092, 3102, 0, + 1537, 4468, 4662, 0, + 3157, 3167, 3177, 3187, 0, + 1046, 0, + 1166, 0, + 1066, 1176, 0, + 2397, 0, + 3287, 3297, 3307, 3317, 0, + 2587, 0, + 3377, 3387, 3397, 3407, 0, + 1376, 2737, 2747, 0, + 1366, 0, + 1186, 0, + 1006, 1016, 1026, 1036, 0, + 3162, 3172, 3182, 3192, 0, + 1051, 0, + 1171, 0, + 1071, 1181, 0, + 2402, 0, + 3292, 3302, 3312, 3322, 0, + 2592, 0, + 3382, 3392, 3402, 3412, 0, + 1381, 2742, 2752, 0, + 1371, 0, + 1191, 0, + 1011, 1021, 1031, 1041, 0, + 3207, 3217, 3227, 3237, 0, + 3212, 3222, 3232, 3242, 0, + 2457, 2467, 0, + 2462, 2472, 0, + 2757, 2767, 0, + 2762, 2772, 0, + 2857, 0, + 2862, 0, + 2867, 0, + 2872, 0, + 2957, 0, + 2962, 0, + 2967, 0, + 2972, 0, + 3132, 0, + 3427, 3437, 3447, 3457, 3467, 0, + 3432, 3442, 3452, 3462, 3472, 0, + 3497, 3507, 3517, 3527, 3537, 0, + 3502, 3512, 3522, 3532, 3542, 0, + 1116, 0, + 1106, 0, + 1111, 0, + 1056, 0, + 1061, 0, + 2497, 0, + 2502, 0, + 1396, 0, + 1401, 0, + 1121, 0, + 1514, 0, + 1542, 3627, 3632, 4425, 4430, 4435, 4444, 0, + 1551, 3697, 3702, 4498, 0, + 1556, 3767, 3772, 4507, 4516, 0, + 1561, 1586, 3847, 3852, 4565, 4570, 4575, 0, + 1566, 3917, 3922, 4700, 0, + 4657, 0, + 1571, 1591, 3987, 4638, 4643, 4648, 0, + 1576, 4047, 4052, 4709, 4718, 0, + 4410, 0, + 4483, 0, + 1596, 3587, 3592, 4087, 4390, 4395, 4405, 4415, 0, + 1601, 3667, 3672, 4096, 0, + 1606, 3727, 3732, 4105, 4478, 4488, 0, + 1611, 1621, 3807, 3812, 4114, 4536, 4541, 4555, 0, + 1631, 3887, 3892, 4123, 0, + 4618, 4623, 0, + 1626, 1636, 3947, 3952, 4132, 4599, 4604, 4628, 0, + 1641, 4007, 4012, 4141, 4680, 4690, 0, + 1581, 4546, 4560, 0, + 1616, 4609, 4633, 0, + 4685, 0, + 1658, 1663, 0, + 1703, 0, + 1788, 1798, 0, + 1698, 0, + 1688, 1693, 1808, 0, + 1778, 1828, 0, + 1838, 0, + 1713, 1723, 1848, 1858, 0, + 1708, 0, + 1868, 0, + 1718, 1898, 1908, 1918, 0, + 1928, 0, + 1938, 0, + 1888, 0, + 1793, 1803, 0, + 1743, 0, + 1733, 1738, 1813, 0, + 1783, 1833, 0, + 1843, 0, + 1728, 1758, 1853, 1863, 0, + 1753, 0, + 1873, 0, + 1763, 1903, 1913, 1923, 0, + 1933, 0, + 1943, 0, + 1893, 0, + 1748, 0, + 1768, 0, + 1773, 0, + 1818, 0, + 1823, 0, + 1878, 0, + 1883, 0, + 11678, 11683, 11688, 0, + 11693, 11803, 0, + 11698, 0, + 11703, 0, + 11708, 0, + 11713, 11798, 0, + 11718, 0, + 11723, 0, + 11608, 11728, 0, + 11733, 0, + 11738, 11808, 0, + 11743, 0, + 11748, 0, + 11753, 0, + 11758, 0, + 11763, 0, + 11768, 11813, 0, + 11773, 0, + 11778, 0, + 11783, 0, + 11658, 11663, 11788, 0, + 11793, 0, + 11613, 0, + 15105, 0, + 15109, 15113, 0, + 15117, 15121, 0, + 15125, 15129, 0, + 15133, 15137, 0, + 12307, 12312, 12317, 12322, 12327, 12332, 12337, 12342, 12347, 12352, 12357, 12362, 12367, 12372, 12377, 12382, 12387, 12392, 12413, 12418, 12423, 12428, 12433, 12919, 12924, 12929, 12934, 12939, 12944, 13174, 13179, 13184, 13189, 13194, 13534, 13539, 15141, 15145, 15149, 15153, 0, + 14732, 14739, 1958, 1968, 14007, 14002, 1953, 15157, 15161, 0, + 14468, 14684, 12448, 12453, 12458, 12463, 12949, 12954, 12959, 12964, 12969, 12974, 13199, 13204, 13209, 13214, 13219, 13544, 13549, 12438, 12443, 15165, 15169, 15173, 15177, 0, + 15181, 15185, 0, + 14012, 14018, 14024, 14030, 14036, 14042, 14048, 14054, 14474, 14480, 14486, 14492, 14498, 14504, 13229, 13234, 13239, 13244, 13559, 13554, 12468, 12473, 12478, 12483, 12488, 12493, 12979, 12984, 12989, 12994, 12999, 13004, 13224, 15189, 15193, 15197, 15201, 0, + 12498, 12503, 12508, 12513, 13009, 13014, 13019, 13024, 13029, 13034, 13249, 13564, 13569, 15205, 15209, 15213, 15217, 0, + 14808, 14660, 14060, 14066, 14510, 14516, 14522, 12518, 12523, 13254, 13259, 13707, 13712, 13847, 13852, 15221, 15225, 15229, 15233, 0, + 14072, 14078, 14666, 13264, 13269, 13697, 13702, 13842, 13837, 12528, 12533, 15237, 15241, 15245, 15249, 0, + 12538, 12543, 12548, 13274, 13279, 13717, 13722, 13857, 13862, 15253, 15257, 15261, 15265, 0, + 15269, 15273, 0, + 12868, 15277, 15281, 0, + 14760, 12873, 15285, 15289, 0, + 15293, 15297, 0, + 14084, 14090, 14096, 14102, 14108, 14114, 14120, 14126, 14528, 14708, 13677, 13682, 13772, 13817, 13822, 13912, 13947, 13962, 13967, 13972, 12553, 12558, 12563, 12568, 13284, 13289, 13294, 13299, 13574, 13579, 15301, 15305, 15309, 15313, 0, + 14150, 14156, 14162, 14168, 14174, 14180, 14186, 14540, 13767, 13827, 13832, 13887, 13892, 13897, 13902, 13907, 13927, 13932, 13937, 13942, 13952, 13977, 13982, 13987, 13584, 13589, 13687, 13692, 13747, 13752, 13757, 13762, 15317, 15321, 15325, 15329, 0, + 14787, 14753, 14781, 14138, 14132, 14144, 14534, 14702, 14720, 12573, 12578, 13304, 13309, 13314, 13727, 13732, 13777, 13872, 13917, 13867, 15333, 15337, 15341, 15345, 0, + 14192, 14198, 14204, 14546, 13319, 13324, 13329, 13334, 13737, 13742, 13782, 13877, 13882, 13922, 12583, 12588, 12593, 12598, 15349, 15353, 15357, 15361, 0, + 14210, 14216, 14222, 14228, 13647, 13652, 13787, 13792, 13992, 13957, 12603, 12608, 13339, 15365, 15369, 15373, 15377, 0, + 12613, 13344, 13997, 15381, 15385, 15389, 15393, 0, + 14767, 14696, 14234, 14240, 14246, 14252, 14612, 12618, 12623, 13349, 13354, 13657, 13662, 13797, 13802, 15397, 15401, 15405, 15409, 0, + 14258, 14264, 14270, 13359, 13364, 13667, 13672, 13812, 13807, 12628, 12633, 15413, 15417, 15421, 15425, 0, + 13629, 13635, 13641, 15040, 15060, 15070, 15080, 15090, 15100, 0, + 14276, 14282, 14678, 12653, 12658, 12663, 13039, 13044, 13369, 13374, 13379, 13384, 12638, 12643, 12648, 15429, 15433, 15437, 15441, 0, + 14600, 14726, 14294, 14288, 14588, 12668, 12673, 12678, 12683, 13049, 13054, 13389, 13394, 15445, 15449, 15453, 15457, 0, + 14618, 14642, 14690, 12703, 12708, 12713, 12718, 12723, 13059, 13064, 13069, 13074, 13079, 13399, 13404, 13409, 13414, 13419, 13594, 13599, 12688, 12693, 12698, 15461, 15465, 15469, 15473, 0, + 14648, 14300, 14306, 14312, 14318, 14324, 14330, 14336, 14342, 14348, 14552, 14558, 14606, 14636, 12728, 12733, 12738, 12743, 12748, 12753, 13084, 13089, 13094, 13424, 13429, 13434, 13439, 13444, 13604, 15573, 15578, 15583, 15588, 15593, 15598, 15603, 15608, 15477, 15481, 15485, 15489, 0, + 14746, 14354, 14360, 14366, 14372, 14378, 14384, 14390, 14396, 14582, 14630, 14672, 12758, 12763, 12768, 12773, 12778, 12783, 13099, 13104, 13449, 13454, 13459, 13464, 15493, 15497, 15501, 15505, 0, + 14414, 14420, 14426, 14432, 14438, 14444, 14450, 14594, 14624, 14654, 14714, 13134, 13469, 13474, 13479, 13484, 13489, 13609, 13614, 12788, 12793, 12798, 12803, 12808, 12813, 13109, 13114, 13119, 13124, 13129, 15509, 15513, 15517, 15521, 0, + 14402, 14408, 12823, 12828, 12833, 13494, 13504, 13499, 12818, 15525, 15529, 15533, 15537, 0, + 14774, 1963, 15541, 15545, 0, + 12878, 13139, 12299, 12303, 15549, 15553, 0, + 14456, 14462, 14564, 14570, 14576, 12858, 12863, 13144, 13149, 13154, 13159, 13164, 13169, 13509, 13514, 13519, 13524, 13529, 13619, 13624, 1973, 12838, 12843, 12848, 12853, 15557, 15561, 15565, 15569, 0, + 11823, 11827, 0, + 12255, 0, + 11911, 11915, 11919, 11923, 0, + 11879, 11883, 11887, 11891, 0, + 11831, 11835, 11839, 11843, 0, + 11847, 11851, 11855, 11859, 0, + 11895, 11899, 11903, 11907, 0, + 11863, 11867, 11871, 11875, 0, + 11975, 11979, 11983, 11987, 0, + 11959, 11963, 11967, 11971, 0, + 11991, 11995, 11999, 12003, 0, + 12007, 12011, 12015, 12019, 0, + 12047, 12051, 0, + 12031, 12035, 0, + 12023, 12027, 0, + 12039, 12043, 0, + 12063, 12067, 0, + 12055, 12059, 0, + 11927, 11931, 11935, 11939, 0, + 11943, 11947, 11951, 11955, 0, + 12071, 12075, 12079, 12083, 0, + 12215, 12219, 12223, 12227, 0, + 12087, 12091, 12095, 12099, 0, + 12119, 12123, 12127, 12131, 0, + 12103, 12107, 12111, 12115, 0, + 12135, 12139, 0, + 12143, 12147, 12151, 12155, 0, + 12183, 12187, 12191, 12195, 0, + 12159, 12163, 0, + 2003, 12167, 12171, 12175, 12179, 0, + 12267, 12271, 0, + 12239, 12243, 0, + 12231, 12235, 0, + 12247, 12251, 0, + 12275, 12279, 0, + 12259, 12263, 0, + 12397, 12401, 12405, 12409, 0, + 12283, 12287, 12291, 12295, 0, + 2008, 12199, 12203, 0, + 12207, 12211, 0, + 1998, 0, + 2028, 0, + 2033, 0, + 2038, 0, + 2043, 0, + 2048, 0, + 2053, 0, + 2013, 0, + 2058, 0, + 2063, 0, + 2018, 0, + 2023, 0, + 2078, 0, + 2083, 0, + 2088, 0, + 2068, 2073, 0, + 2103, 0, + 2108, 0, + 2113, 0, + 2118, 0, + 2093, 0, + 2098, 0, + 2138, 0, + 2143, 0, + 2123, 2128, 2133, 0, + 2148, 0, + 2153, 2163, 0, + 2158, 0, + 2168, 0, + 2173, 0, + 2178, 2183, 2188, 0, + 2193, 0, + 2198, 2208, 0, + 2203, 0, + 2213, 2218, 2228, 0, + 2223, 0, + 2282, 0, + 2257, 0, + 2262, 0, + 2267, 0, + 2272, 0, + 2277, 0, + 2287, 2292, 2317, 0, + 2347, 0, + 2322, 0, + 2327, 0, + 2332, 0, + 2337, 0, + 2342, 0, + 2297, 0, + 2307, 0, + 2352, 0, + 2637, 0, + 2642, 0, + 2817, 0, + 2822, 0, + 2877, 0, + 2882, 0, + 3197, 3247, 0, + 3202, 3252, 0, + 3327, 0, + 3332, 0, + 3417, 0, + 3422, 0, + 3597, 3607, 3617, 4150, 0, + 3602, 3612, 3622, 4155, 0, + 4160, 0, + 4165, 0, + 4170, 0, + 4175, 0, + 4180, 0, + 4185, 0, + 3637, 3647, 3657, 4190, 0, + 3642, 3652, 3662, 4195, 0, + 4200, 0, + 4205, 0, + 4210, 0, + 4215, 0, + 4220, 0, + 4225, 0, + 3677, 3687, 0, + 3682, 3692, 0, + 3707, 3717, 0, + 3712, 3722, 0, + 3737, 3747, 3757, 4230, 0, + 3742, 3752, 3762, 4235, 0, + 4240, 0, + 4245, 0, + 4250, 0, + 4255, 0, + 4260, 0, + 4265, 0, + 3777, 3787, 3797, 4270, 0, + 3782, 3792, 3802, 4275, 0, + 4280, 0, + 4285, 0, + 4290, 0, + 4295, 0, + 4300, 0, + 4305, 0, + 3817, 3827, 3837, 0, + 3822, 3832, 3842, 0, + 3857, 3867, 3877, 0, + 3862, 3872, 3882, 0, + 3897, 3907, 0, + 3902, 3912, 0, + 3927, 3937, 0, + 3932, 3942, 0, + 3957, 3967, 3977, 0, + 3962, 3972, 3982, 0, + 3992, 3997, 4002, 0, + 4017, 4027, 4037, 4310, 0, + 4022, 4032, 4042, 4315, 0, + 4320, 0, + 4325, 0, + 4330, 0, + 4335, 0, + 4340, 0, + 4345, 0, + 4057, 4067, 4077, 4350, 0, + 4062, 4072, 4082, 4355, 0, + 4360, 0, + 4365, 0, + 4370, 0, + 4375, 0, + 4380, 0, + 4385, 0, + 4400, 0, + 4473, 0, + 4675, 0, + 4420, 0, + 4521, 4526, 4531, 0, + 4493, 0, + 4695, 0, + 4584, 4589, 4594, 0, + 5391, 0, + 5396, 0, + 5401, 0, + 5406, 0, + 5416, 0, + 5411, 0, + 5421, 0, + 5426, 0, + 5431, 0, + 5436, 0, + 5441, 0, + 5468, 0, + 5473, 0, + 5478, 0, + 5483, 0, + 5498, 0, + 5493, 0, + 5513, 0, + 5518, 0, + 5523, 0, + 5528, 0, + 5533, 0, + 5538, 0, + 5543, 0, + 5548, 0, + 5593, 0, + 5598, 0, + 5553, 0, + 5558, 0, + 5563, 0, + 5568, 0, + 5603, 0, + 5608, 0, + 5573, 0, + 5578, 0, + 5583, 0, + 5588, 0, + 5613, 0, + 5618, 0, + 5623, 0, + 5628, 0, + 7351, 0, + 7226, 0, + 7231, 0, + 7236, 0, + 7241, 0, + 7246, 0, + 7251, 0, + 7256, 0, + 7261, 0, + 7266, 0, + 7271, 0, + 7276, 0, + 7281, 0, + 7286, 0, + 7291, 0, + 7296, 0, + 7301, 7306, 0, + 7311, 7316, 0, + 7321, 7326, 0, + 7331, 7336, 0, + 7341, 7346, 0, + 7366, 0, + 7496, 0, + 7371, 0, + 7376, 0, + 7381, 0, + 7386, 0, + 7391, 0, + 7396, 0, + 7401, 0, + 7406, 0, + 7411, 0, + 7416, 0, + 7421, 0, + 7426, 0, + 7431, 0, + 7436, 0, + 7441, 0, + 7446, 7451, 0, + 7456, 7461, 0, + 7466, 7471, 0, + 7476, 7481, 0, + 7486, 7491, 0, + 7501, 0, + 7506, 0, + 7511, 0, + 7516, 0, + 7521, 0, + 11668, 11673, 0, + +}; + +static const Q_UINT16 li_00[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 16, 18, 20, 0, + 0, 22, 39, 43, 49, 56, 74, 76, + 84, 92, 108, 110, 116, 123, 127, 137, + 154, 0, 157, 166, 174, 182, 202, 205, + 212, 215, 225, 0, 0, 0, 0, 0, + 0, 232, 249, 253, 259, 266, 284, 286, + 294, 303, 318, 321, 327, 334, 338, 348, + 365, 0, 368, 377, 385, 394, 414, 417, + 425, 428, 439, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 446, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 450, 0, 455, 457, 459, 462, + 0, 0, 464, 0, 0, 0, 0, 469, + 0, 0, 0, 0, 471, 476, 480, 0, + 482, 0, 0, 0, 484, 0, 0, 0, + 0, 0, 489, 0, 494, 496, 498, 501, + 0, 0, 503, 0, 0, 0, 0, 508, + 0, 0, 0, 0, 510, 515, 519, 0, + 521, 0, 0, 0, 523, 0, 0, 0, +}; + +static const Q_UINT16 li_01[] = { + 0, 0, 528, 533, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 538, 541, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 544, 547, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 550, 552, 0, 0, 0, 0, + 554, 556, 0, 0, 0, 0, 0, 0, + 558, 560, 562, 564, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 566, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 568, 574, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 580, + 586, 0, 0, 0, 0, 0, 0, 592, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 594, 596, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_02[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 598, 600, + 602, 604, 0, 0, 0, 0, 606, 608, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 610, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_03[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 612, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 614, 0, 0, 0, 622, 0, 627, + 0, 633, 0, 0, 0, 0, 0, 641, + 0, 646, 0, 0, 0, 648, 0, 0, + 0, 655, 0, 0, 661, 0, 663, 0, + 0, 665, 0, 0, 0, 674, 0, 679, + 0, 686, 0, 0, 0, 0, 0, 695, + 0, 700, 0, 0, 0, 703, 0, 0, + 0, 712, 719, 723, 0, 0, 727, 0, + 0, 0, 729, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_04[] = { + 0, 0, 0, 0, 0, 0, 732, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 734, 0, 0, 737, 0, 739, 743, 746, + 748, 0, 753, 0, 0, 0, 755, 0, + 0, 0, 0, 757, 0, 0, 0, 762, + 0, 0, 0, 764, 0, 766, 0, 0, + 768, 0, 0, 771, 0, 773, 777, 780, + 782, 0, 787, 0, 0, 0, 789, 0, + 0, 0, 0, 791, 0, 0, 0, 796, + 0, 0, 0, 798, 0, 800, 0, 0, + 0, 0, 0, 0, 0, 0, 802, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 804, 806, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 808, 810, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 812, 814, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_05[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 816, 820, 823, 825, 827, 829, 832, 0, + 834, 836, 839, 841, 844, 0, 846, 0, + 848, 850, 0, 852, 854, 0, 857, 859, + 861, 863, 867, 0, 0, 0, 0, 0, + 0, 0, 869, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_06[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 871, 873, 876, 879, 882, 885, 926, + 936, 962, 965, 1003, 1021, 1041, 1057, 1071, + 1074, 1078, 1083, 1086, 1121, 1158, 1183, 1206, + 1224, 1232, 1252, 0, 0, 0, 0, 0, + 1268, 1278, 1298, 1316, 1344, 1386, 1415, 1450, + 1464, 1469, 1476, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1506, 0, 0, 0, 0, 0, 1509, + 0, 1511, 1516, 1521, 0, 0, 1526, 1531, + 1536, 0, 0, 1541, 1546, 0, 1551, 1556, + 1561, 0, 0, 0, 1564, 1567, 1570, 0, + 0, 1573, 0, 0, 0, 0, 0, 0, + 1576, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1579, 0, 1584, 0, + 0, 1589, 0, 0, 0, 1594, 0, 1599, + 0, 1604, 0, 1609, 0, 0, 0, 0, + 0, 0, 1614, 1617, 0, 0, 1622, 0, + 1627, 1630, 0, 0, 0, 1636, 1639, 1642, + 1645, 1648, 0, 1651, 1654, 0, 0, 0, + 1659, 0, 1664, 1668, 0, 1671, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_07[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_09[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1673, 1675, 1677, + 0, 0, 0, 0, 1679, 0, 0, 0, + 0, 1681, 1683, 0, 0, 0, 0, 0, + 1685, 0, 0, 1687, 0, 0, 0, 1689, + 1691, 0, 0, 1693, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1695, 1697, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1699, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1701, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_0A[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1704, 1706, + 0, 0, 0, 0, 1708, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1710, 0, 0, 0, 0, + 0, 0, 1712, 0, 0, 0, 0, 0, + 1714, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_0B[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1716, 1718, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1720, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1724, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1726, 1729, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_0C[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1731, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1733, + 0, 0, 0, 0, 0, 0, 1735, 0, + 0, 0, 1739, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_0D[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1741, 1744, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1746, 0, 0, 1750, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_0F[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1752, 0, 1754, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1756, 0, 0, 0, + 0, 1758, 0, 0, 0, 0, 1760, 0, + 0, 0, 0, 1762, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1764, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1768, 0, 1770, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1772, 0, 0, 0, + 0, 1774, 0, 0, 0, 0, 1776, 0, + 0, 0, 0, 1778, 0, 0, 0, 0, + 0, 0, 1780, 1782, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_10[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1784, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_1E[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1786, 1788, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1790, 1792, 0, 0, 0, 0, + 0, 0, 1794, 1796, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1798, 1801, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1804, 1806, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1808, 1810, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_1F[] = { + 1812, 1817, 1822, 1824, 1826, 1828, 1830, 1832, + 1834, 1839, 1844, 1846, 1848, 1850, 1852, 1854, + 1856, 1859, 0, 0, 0, 0, 0, 0, + 1862, 1865, 0, 0, 0, 0, 0, 0, + 1868, 1873, 1878, 1880, 1882, 1884, 1886, 1888, + 1890, 1895, 1900, 1902, 1904, 1906, 1908, 1910, + 1912, 1916, 0, 0, 0, 0, 0, 0, + 1920, 1924, 0, 0, 0, 0, 0, 0, + 1928, 1931, 0, 0, 0, 0, 0, 0, + 1934, 1937, 0, 0, 0, 0, 0, 0, + 1940, 1944, 0, 0, 0, 0, 0, 0, + 0, 1948, 0, 0, 0, 0, 0, 0, + 1952, 1957, 1962, 1964, 1966, 1968, 1970, 1972, + 1974, 1979, 1984, 1986, 1988, 1990, 1992, 1994, + 1996, 0, 0, 0, 1998, 0, 0, 0, + 0, 0, 0, 0, 2000, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2002, 0, + 0, 0, 0, 0, 0, 0, 0, 2004, + 0, 0, 0, 0, 0, 0, 2008, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2010, 0, + 0, 0, 0, 0, 0, 0, 2012, 0, +}; + +static const Q_UINT16 li_21[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2016, 0, 2018, 0, 2020, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2022, 0, 2024, 0, 2026, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_22[] = { + 0, 0, 0, 2028, 0, 0, 0, 0, + 2030, 0, 0, 2032, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 2034, 0, 2036, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2038, 0, 0, 0, + 0, 0, 0, 2040, 0, 2042, 0, 0, + 2044, 0, 0, 0, 0, 2046, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2048, 0, 0, 2050, 2052, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2054, 2056, 0, 0, 2058, 2060, + 0, 0, 2062, 2064, 2066, 2068, 0, 0, + 0, 0, 2070, 2072, 0, 0, 2074, 2076, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2078, 2080, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2082, 0, 0, 0, 0, 0, + 2084, 2086, 0, 2088, 0, 0, 0, 0, + 0, 0, 2090, 2092, 2094, 2096, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 li_30[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 2098, 0, + 0, 0, 0, 2100, 0, 2102, 0, 2104, + 0, 2106, 0, 2108, 0, 2110, 0, 2112, + 0, 2114, 0, 2116, 0, 2118, 0, 2120, + 0, 2122, 0, 0, 2124, 0, 2126, 0, + 2128, 0, 0, 0, 0, 0, 0, 2130, + 0, 0, 2133, 0, 0, 2136, 0, 0, + 2139, 0, 0, 2142, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2145, 0, 0, + 0, 0, 0, 0, 0, 0, 2147, 0, + 0, 0, 0, 2149, 0, 2151, 0, 2153, + 0, 2155, 0, 2157, 0, 2159, 0, 2161, + 0, 2163, 0, 2165, 0, 2167, 0, 2169, + 0, 2171, 0, 0, 2173, 0, 2175, 0, + 2177, 0, 0, 0, 0, 0, 0, 2179, + 0, 0, 2182, 0, 0, 2185, 0, 0, + 2188, 0, 0, 2191, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2194, + 2196, 2198, 2200, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 2202, 0, 0, +}; + +static const Q_UINT16 li_FB[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2204, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 * const ligature_info[256] = { + li_00, li_01, li_02, li_03, li_04, li_05, li_06, li_07, + li_07, li_09, li_0A, li_0B, li_0C, li_0D, li_07, li_0F, + li_10, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_1E, li_1F, + li_07, li_21, li_22, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_30, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_07, li_07, li_07, li_07, li_07, + li_07, li_07, li_07, li_FB, li_07, li_07, li_07, li_07, +}; +// 16188 bytes + +static const Q_UINT8 dir_00[] = { + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 8, 7, 8, 9, 7, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 7, 7, 7, 8, + 9, 10, 10, 4, 4, 4, 10, 10, + 138, 138, 10, 4, 6, 4, 6, 3, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 6, 10, 138, 10, 138, 10, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 138, 10, 138, 10, 10, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 138, 10, 138, 10, 18, + 18, 18, 18, 18, 18, 7, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, + 6, 10, 4, 4, 4, 4, 10, 10, + 10, 10, 0, 138, 10, 10, 10, 10, + 4, 4, 2, 2, 10, 0, 10, 10, + 10, 2, 0, 138, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_01[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_02[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 10, 10, 0, 0, 0, 0, 0, + 0, 0, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_03[] = { + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 10, 0, + 0, 0, 0, 0, 10, 10, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_04[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 17, 17, 17, 17, 0, + 17, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_05[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, 0, 0, + 0, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 0, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 0, 17, 17, 17, 1, 17, + 1, 17, 17, 1, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_06[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 13, 0, 0, 0, 13, + 0, 13, 77, 77, 77, 77, 45, 77, + 45, 77, 45, 45, 45, 45, 45, 77, + 77, 77, 77, 45, 45, 45, 45, 45, + 45, 45, 45, 0, 0, 0, 0, 0, + 109, 45, 45, 45, 45, 45, 45, 45, + 77, 77, 45, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 4, 5, 5, 13, 0, 0, + 17, 13, 77, 77, 13, 77, 77, 77, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 77, 45, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 45, 77, 45, 77, + 45, 45, 77, 77, 13, 13, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 13, 13, 17, + 17, 10, 17, 17, 17, 17, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 45, 45, 45, 13, 13, 0, +}; + +static const Q_UINT8 dir_07[] = { + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 0, 18, + 77, 17, 45, 45, 45, 77, 77, 77, + 77, 77, 45, 45, 45, 45, 77, 45, + 45, 45, 45, 45, 45, 45, 45, 45, + 77, 45, 77, 45, 77, 0, 0, 0, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 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, + 13, 13, 13, 13, 13, 13, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_09[] = { + 0, 17, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 0, + 0, 17, 17, 17, 17, 17, 17, 17, + 17, 0, 0, 0, 0, 17, 0, 0, + 0, 17, 17, 17, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 0, + 0, 17, 17, 17, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_0A[] = { + 0, 0, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 0, + 0, 17, 17, 0, 0, 0, 0, 17, + 17, 0, 0, 17, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 0, + 0, 17, 17, 17, 17, 17, 0, 17, + 17, 0, 0, 0, 0, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_0B[] = { + 0, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 17, 0, 0, 17, + 0, 17, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 17, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_0C[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 17, 17, + 17, 0, 0, 0, 0, 0, 17, 17, + 17, 0, 17, 17, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 17, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 17, + 0, 0, 0, 0, 0, 0, 17, 0, + 0, 0, 0, 0, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_0D[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 17, 0, 0, 0, 0, 0, + 0, 0, 17, 17, 17, 0, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_0E[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 0, 0, 17, 17, 17, 17, + 17, 17, 17, 0, 0, 0, 0, 4, + 0, 0, 0, 0, 0, 0, 0, 17, + 17, 17, 17, 17, 17, 17, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 0, 0, 17, 17, 17, 17, + 17, 17, 0, 17, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 17, 17, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_0F[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 0, 17, + 0, 17, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 0, + 17, 17, 17, 17, 17, 0, 17, 17, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 17, 17, 17, 17, 17, 17, + 0, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 17, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_10[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 17, 17, 17, + 17, 0, 17, 0, 0, 0, 17, 17, + 0, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_16[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_17[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 17, + 17, 17, 17, 17, 17, 17, 0, 0, + 0, 0, 0, 0, 0, 0, 17, 0, + 0, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 4, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_18[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 18, 18, 18, 18, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_1F[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 0, 10, + 10, 10, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 10, 10, 0, +}; + +static const Q_UINT8 dir_20[] = { + 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 18, 18, 18, 0, 1, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 9, 7, 11, 14, 16, 12, 15, 9, + 4, 4, 4, 4, 4, 10, 10, 10, + 10, 138, 138, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 138, 138, 0, + 10, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 18, 18, 18, 18, 18, 18, + 2, 0, 0, 0, 2, 2, 2, 2, + 2, 2, 4, 4, 10, 138, 138, 0, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 4, 4, 10, 138, 138, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_21[] = { + 10, 10, 0, 10, 10, 10, 10, 0, + 10, 10, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 10, 0, 10, 10, + 10, 0, 0, 0, 0, 0, 10, 10, + 10, 10, 10, 10, 0, 10, 0, 10, + 0, 10, 0, 0, 0, 0, 4, 0, + 0, 0, 10, 0, 0, 0, 0, 0, + 0, 0, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_22[] = { + 10, 138, 138, 138, 138, 10, 10, 10, + 138, 138, 138, 138, 138, 138, 10, 10, + 10, 138, 4, 4, 10, 138, 138, 10, + 10, 10, 138, 138, 138, 138, 10, 138, + 138, 138, 138, 10, 138, 10, 138, 10, + 10, 10, 10, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 10, 10, 10, 10, + 10, 138, 10, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 10, 10, 10, + 10, 10, 138, 138, 138, 138, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 138, + 138, 10, 138, 10, 138, 138, 138, 138, + 138, 138, 138, 138, 10, 10, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 10, 10, 138, + 138, 138, 138, 10, 10, 10, 10, 10, + 138, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 138, 138, 10, 10, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 10, 10, 10, 10, 10, 138, 138, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 138, 138, 138, 138, 138, 10, 10, + 138, 138, 10, 10, 10, 10, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 138, 138, 138, 138, 10, 10, + 138, 138, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_23[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 138, 138, 138, 138, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 138, 138, 10, 10, 10, 10, 10, 10, + 10, 138, 138, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 0, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 0, 10, 10, + 10, 10, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_24[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 2, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_25[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_26[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 0, 0, 0, 0, + 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_27[] = { + 0, 10, 10, 10, 10, 0, 10, 10, + 10, 10, 0, 0, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 0, 10, 0, 10, + 10, 10, 10, 0, 0, 0, 10, 0, + 10, 10, 10, 10, 10, 10, 10, 0, + 0, 10, 10, 10, 10, 10, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 0, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_28[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, +}; + +static const Q_UINT8 dir_2E[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 0, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_2F[] = { + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_30[] = { + 9, 10, 10, 10, 10, 0, 0, 0, + 138, 138, 138, 138, 138, 138, 138, 138, + 138, 138, 10, 10, 138, 138, 138, 138, + 138, 138, 138, 138, 10, 10, 10, 10, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 17, 17, 17, 17, 17, 17, + 10, 0, 0, 0, 0, 0, 10, 10, + 0, 0, 0, 0, 0, 0, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 17, 10, 10, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_A4[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 0, 0, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 0, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 0, 10, 10, 10, 0, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_FB[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1, 17, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 4, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 1, 1, 1, 1, 0, 1, 0, + 1, 1, 0, 1, 1, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 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, + 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, + 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, + 13, 13, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 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, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, +}; + +static const Q_UINT8 dir_FC[] = { + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, +}; + +static const Q_UINT8 dir_FD[] = { + 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, + 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, 10, 10, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 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, + 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, + 0, 0, 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, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 0, 0, 0, 0, +}; + +static const Q_UINT8 dir_FE[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 17, 17, 17, 17, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 0, 0, 0, + 0, 10, 10, 10, 10, 10, 10, 10, + 6, 10, 6, 0, 10, 6, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 4, + 10, 10, 4, 4, 10, 10, 10, 0, + 10, 4, 4, 10, 0, 0, 0, 0, + 13, 13, 13, 0, 13, 0, 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, 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, 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, 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, 13, 13, + 13, 13, 13, 13, 13, 0, 0, 18, +}; + +static const Q_UINT8 dir_FF[] = { + 0, 10, 10, 4, 4, 4, 10, 10, + 10, 10, 10, 4, 6, 4, 6, 3, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 6, 10, 10, 10, 10, 10, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 10, 10, 10, 10, + 10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 10, 10, 10, 10, 0, + 0, 10, 10, 10, 10, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 10, 10, 10, 4, 4, 0, + 10, 10, 10, 10, 10, 10, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 18, 18, 18, 10, 10, 0, 0, +}; + +static const Q_UINT8 * const direction_info[256] = { + dir_00, dir_01, dir_02, dir_03, dir_04, dir_05, dir_06, dir_07, + dir_01, dir_09, dir_0A, dir_0B, dir_0C, dir_0D, dir_0E, dir_0F, + dir_10, dir_01, dir_01, dir_01, dir_01, dir_01, dir_16, dir_17, + dir_18, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_1F, + dir_20, dir_21, dir_22, dir_23, dir_24, dir_25, dir_26, dir_27, + dir_28, dir_01, dir_01, dir_01, dir_01, dir_01, dir_2E, dir_2F, + dir_30, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_A4, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, dir_01, + dir_01, dir_01, dir_01, dir_FB, dir_FC, dir_FD, dir_FE, dir_FF, +}; +// 26940 bytes + +#endif + +// END OF GENERATED DATA + +// This is generated too. Script? + +#ifndef QT_NO_UNICODETABLES + +static const Q_UINT16 case_0 [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0, 0, 0, 0, 0, + 0, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0x0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0x0, 0, 0, + 0, 0, 0x0, 0, 0, 0, 0, 0, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x0, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x178, +}; + +static const Q_UINT16 case_1 [] = { + 0x101, 0x100, 0x103, 0x102, 0x105, 0x104, 0x107, 0x106, + 0x109, 0x108, 0x10b, 0x10a, 0x10d, 0x10c, 0x10f, 0x10e, + 0x111, 0x110, 0x113, 0x112, 0x115, 0x114, 0x117, 0x116, + 0x119, 0x118, 0x11b, 0x11a, 0x11d, 0x11c, 0x11f, 0x11e, + 0x121, 0x120, 0x123, 0x122, 0x125, 0x124, 0x127, 0x126, + 0x129, 0x128, 0x12b, 0x12a, 0x12d, 0x12c, 0x12f, 0x12e, + 0x69, 0x49, 0x133, 0x132, 0x135, 0x134, 0x137, 0x136, + 0x0, 0x13a, 0x139, 0x13c, 0x13b, 0x13e, 0x13d, 0x140, + 0x13f, 0x142, 0x141, 0x144, 0x143, 0x146, 0x145, 0x148, + 0x147, 0x0, 0x14b, 0x14a, 0x14d, 0x14c, 0x14f, 0x14e, + 0x151, 0x150, 0x153, 0x152, 0x155, 0x154, 0x157, 0x156, + 0x159, 0x158, 0x15b, 0x15a, 0x15d, 0x15c, 0x15f, 0x15e, + 0x161, 0x160, 0x163, 0x162, 0x165, 0x164, 0x167, 0x166, + 0x169, 0x168, 0x16b, 0x16a, 0x16d, 0x16c, 0x16f, 0x16e, + 0x171, 0x170, 0x173, 0x172, 0x175, 0x174, 0x177, 0x176, + 0xff, 0x17a, 0x179, 0x17c, 0x17b, 0x17e, 0x17d, 0x53, + 0x0, 0x253, 0x183, 0x182, 0x185, 0x184, 0x254, 0x188, + 0x187, 0x256, 0x257, 0x18c, 0x18b, 0x0, 0x1dd, 0x259, + 0x25b, 0x192, 0x191, 0x260, 0x263, 0x3d9, 0x269, 0x268, + 0x199, 0x198, 0x51, 0x0, 0x26f, 0x272, 0x0, 0x275, + 0x1a1, 0x1a0, 0x1a3, 0x1a2, 0x1a5, 0x1a4, 0x280, 0x1a8, + 0x1a7, 0x283, 0, 0x0, 0x1ad, 0x1ac, 0x288, 0x1b0, + 0x1af, 0x28a, 0x28b, 0x1b4, 0x1b3, 0x1b6, 0x1b5, 0x292, + 0x1b9, 0x1b8, 0x0, 0, 0x1bd, 0x1bc, 0, 0, + 0, 0, 0, 0, 0x1c6, 0, 0x1c4, 0x1c9, + 0, 0x1c7, 0x1cc, 0, 0x1ca, 0x1ce, 0x1cd, 0x1d0, + 0x1cf, 0x1d2, 0x1d1, 0x1d4, 0x1d3, 0x1d6, 0x1d5, 0x1d8, + 0x1d7, 0x1da, 0x1d9, 0x1dc, 0x1db, 0x18e, 0x1df, 0x1de, + 0x1e1, 0x1e0, 0x1e3, 0x1e2, 0x1e5, 0x1e4, 0x1e7, 0x1e6, + 0x1e9, 0x1e8, 0x1eb, 0x1ea, 0x1ed, 0x1ec, 0x1ef, 0x1ee, + 0x0, 0x1f3, 0, 0x1f1, 0x1f5, 0x1f4, 0, 0, + 0, 0, 0x1fb, 0x1fa, 0x1fd, 0x1fc, 0x1ff, 0x1fe, +}; + +static const Q_UINT16 case_2 [] = { + 0x201, 0x200, 0x203, 0x202, 0x205, 0x204, 0x207, 0x206, + 0x209, 0x208, 0x20b, 0x20a, 0x20d, 0x20c, 0x20f, 0x20e, + 0x211, 0x210, 0x213, 0x212, 0x215, 0x214, 0x217, 0x216, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x0, 0x0, 0x0, 0x181, 0x186, 0x0, 0x189, 0x18a, + 0x0, 0x18f, 0x0, 0x190, 0x0, 0x0, 0x0, 0x0, + 0x193, 0x0, 0x0, 0x194, 0x0, 0x0, 0x631, 0x579, + 0x197, 0x196, 0x0, 0x0, 0x0, 0x0, 0x0, 0x19c, + 0x0, 0x0, 0x19d, 0x0, 0x0, 0x19f, 0x0, 0x0, + 0x0, 0x0, 0x7e1, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x1a6, 0x0, 0x0, 0x1a9, 0x0, 0x0, 0x0, 0x0, + 0x1ae, 0x0, 0x1b1, 0x1b2, 0x0, 0xa21, 0x971, 0x0, + 0x0, 0x0, 0x1b7, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_3 [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0x3ac, 0, + 0x3ad, 0x3ae, 0x3af, 0, 0x3cc, 0, 0x3cd, 0x3ce, + 0x0, 0x3b1, 0x3b2, 0x3b3, 0x3b4, 0x3b5, 0x3b6, 0x3b7, + 0x3b8, 0x3b9, 0x3ba, 0x3bb, 0x3bc, 0x3bd, 0x3be, 0x3bf, + 0x3c0, 0x3c1, 0, 0x3c3, 0x3c4, 0x3c5, 0x3c6, 0x3c7, + 0x3c8, 0x3c9, 0x3ca, 0x3cb, 0x386, 0x388, 0x389, 0x38a, + 0x0, 0x391, 0x392, 0x393, 0x394, 0x395, 0x396, 0x397, + 0x398, 0x399, 0x39a, 0x39b, 0x39c, 0x39d, 0x39e, 0x39f, + 0x3a0, 0x3a1, 0x3a3, 0x3a3, 0x3a4, 0x3a5, 0x3a6, 0x3a7, + 0x3a8, 0x3a9, 0x3aa, 0x3ab, 0x38c, 0x38e, 0x38f, 0, + 0x392, 0x398, 0x0, 0x0, 0x0, 0x3a6, 0x3a0, 0, + 0, 0, 0x0, 0, 0x0, 0, 0x0, 0, + 0x0, 0, 0x3e3, 0x3e2, 0x3e5, 0x3e4, 0x3e7, 0x3e6, + 0x3e9, 0x3e8, 0x3eb, 0x3ea, 0x3ed, 0x3ec, 0x3ef, 0x3ee, + 0x39a, 0x3a1, 0x3a3, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_4 [] = { + 0, 0x451, 0x452, 0x453, 0x454, 0x455, 0x456, 0x457, + 0x458, 0x459, 0x45a, 0x45b, 0x45c, 0, 0x45e, 0x45f, + 0x430, 0x431, 0x432, 0x433, 0x434, 0x435, 0x436, 0x437, + 0x438, 0x439, 0x43a, 0x43b, 0x43c, 0x43d, 0x43e, 0x43f, + 0x440, 0x441, 0x442, 0x443, 0x444, 0x445, 0x446, 0x447, + 0x448, 0x449, 0x44a, 0x44b, 0x44c, 0x44d, 0x44e, 0x44f, + 0x410, 0x411, 0x412, 0x413, 0x414, 0x415, 0x416, 0x417, + 0x418, 0x419, 0x41a, 0x41b, 0x41c, 0x41d, 0x41e, 0x41f, + 0x420, 0x421, 0x422, 0x423, 0x424, 0x425, 0x426, 0x427, + 0x428, 0x429, 0x42a, 0x42b, 0x42c, 0x42d, 0x42e, 0x42f, + 0, 0x401, 0x402, 0x403, 0x404, 0x405, 0x406, 0x407, + 0x408, 0x409, 0x40a, 0x40b, 0x40c, 0, 0x40e, 0x40f, + 0x461, 0x460, 0x463, 0x462, 0x465, 0x464, 0x467, 0x466, + 0x469, 0x468, 0x46b, 0x46a, 0x46d, 0x46c, 0x46f, 0x46e, + 0x471, 0x470, 0x473, 0x472, 0x475, 0x474, 0x477, 0x476, + 0x479, 0x478, 0x47b, 0x47a, 0x47d, 0x47c, 0x47f, 0x47e, + 0x481, 0x480, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x491, 0x490, 0x493, 0x492, 0x495, 0x494, 0x497, 0x496, + 0x499, 0x498, 0x49b, 0x49a, 0x49d, 0x49c, 0x49f, 0x49e, + 0x4a1, 0x4a0, 0x4a3, 0x4a2, 0x4a5, 0x4a4, 0x4a7, 0x4a6, + 0x4a9, 0x4a8, 0x4ab, 0x4aa, 0x4ad, 0x4ac, 0x4af, 0x4ae, + 0x4b1, 0x4b0, 0x4b3, 0x4b2, 0x4b5, 0x4b4, 0x4b7, 0x4b6, + 0x4b9, 0x4b8, 0x4bb, 0x4ba, 0x4bd, 0x4bc, 0x4bf, 0x4be, + 0, 0x4c2, 0x4c1, 0x4c4, 0x4c3, 0, 0, 0x4c8, + 0x4c7, 0, 0, 0x4cc, 0x4cb, 0, 0, 0, + 0x4d1, 0x4d0, 0x4d3, 0x4d2, 0x4d5, 0x4d4, 0x4d7, 0x4d6, + 0x4d9, 0x4d8, 0x4db, 0x4da, 0x4dd, 0x4dc, 0x4df, 0x4de, + 0x4e1, 0x4e0, 0x4e3, 0x4e2, 0x4e5, 0x4e4, 0x4e7, 0x4e6, + 0x4e9, 0x4e8, 0x4eb, 0x4ea, 0, 0, 0x4ef, 0x4ee, + 0x4f1, 0x4f0, 0x4f3, 0x4f2, 0x4f5, 0x4f4, 0, 0, + 0x4f9, 0x4f8, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_5 [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0x561, 0x562, 0x563, 0x564, 0x565, 0x566, 0x567, + 0x568, 0x569, 0x56a, 0x56b, 0x56c, 0x56d, 0x56e, 0x56f, + 0x570, 0x571, 0x572, 0x573, 0x574, 0x575, 0x576, 0x577, + 0x578, 0x579, 0x57a, 0x57b, 0x57c, 0x57d, 0x57e, 0x57f, + 0x580, 0x581, 0x582, 0x583, 0x584, 0x585, 0x586, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0x531, 0x532, 0x533, 0x534, 0x535, 0x536, 0x537, + 0x538, 0x539, 0x53a, 0x53b, 0x53c, 0x53d, 0x53e, 0x53f, + 0x540, 0x541, 0x542, 0x543, 0x544, 0x545, 0x546, 0x547, + 0x548, 0x549, 0x54a, 0x54b, 0x54c, 0x54d, 0x54e, 0x54f, + 0x550, 0x551, 0x552, 0x553, 0x554, 0x555, 0x556, 0x0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_10 [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x10d0, 0x10d1, 0x10d2, 0x10d3, 0x10d4, 0x10d5, 0x10d6, 0x10d7, + 0x10d8, 0x10d9, 0x10da, 0x10db, 0x10dc, 0x10dd, 0x10de, 0x10df, + 0x10e0, 0x10e1, 0x10e2, 0x10e3, 0x10e4, 0x10e5, 0x10e6, 0x10e7, + 0x10e8, 0x10e9, 0x10ea, 0x10eb, 0x10ec, 0x10ed, 0x10ee, 0x10ef, + 0x10f0, 0x10f1, 0x10f2, 0x10f3, 0x10f4, 0x10f5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_1e [] = { + 0x1e01, 0x1e00, 0x1e03, 0x1e02, 0x1e05, 0x1e04, 0x1e07, 0x1e06, + 0x1e09, 0x1e08, 0x1e0b, 0x1e0a, 0x1e0d, 0x1e0c, 0x1e0f, 0x1e0e, + 0x1e11, 0x1e10, 0x1e13, 0x1e12, 0x1e15, 0x1e14, 0x1e17, 0x1e16, + 0x1e19, 0x1e18, 0x1e1b, 0x1e1a, 0x1e1d, 0x1e1c, 0x1e1f, 0x1e1e, + 0x1e21, 0x1e20, 0x1e23, 0x1e22, 0x1e25, 0x1e24, 0x1e27, 0x1e26, + 0x1e29, 0x1e28, 0x1e2b, 0x1e2a, 0x1e2d, 0x1e2c, 0x1e2f, 0x1e2e, + 0x1e31, 0x1e30, 0x1e33, 0x1e32, 0x1e35, 0x1e34, 0x1e37, 0x1e36, + 0x1e39, 0x1e38, 0x1e3b, 0x1e3a, 0x1e3d, 0x1e3c, 0x1e3f, 0x1e3e, + 0x1e41, 0x1e40, 0x1e43, 0x1e42, 0x1e45, 0x1e44, 0x1e47, 0x1e46, + 0x1e49, 0x1e48, 0x1e4b, 0x1e4a, 0x1e4d, 0x1e4c, 0x1e4f, 0x1e4e, + 0x1e51, 0x1e50, 0x1e53, 0x1e52, 0x1e55, 0x1e54, 0x1e57, 0x1e56, + 0x1e59, 0x1e58, 0x1e5b, 0x1e5a, 0x1e5d, 0x1e5c, 0x1e5f, 0x1e5e, + 0x1e61, 0x1e60, 0x1e63, 0x1e62, 0x1e65, 0x1e64, 0x1e67, 0x1e66, + 0x1e69, 0x1e68, 0x1e6b, 0x1e6a, 0x1e6d, 0x1e6c, 0x1e6f, 0x1e6e, + 0x1e71, 0x1e70, 0x1e73, 0x1e72, 0x1e75, 0x1e74, 0x1e77, 0x1e76, + 0x1e79, 0x1e78, 0x1e7b, 0x1e7a, 0x1e7d, 0x1e7c, 0x1e7f, 0x1e7e, + 0x1e81, 0x1e80, 0x1e83, 0x1e82, 0x1e85, 0x1e84, 0x1e87, 0x1e86, + 0x1e89, 0x1e88, 0x1e8b, 0x1e8a, 0x1e8d, 0x1e8c, 0x1e8f, 0x1e8e, + 0x1e91, 0x1e90, 0x1e93, 0x1e92, 0x1e95, 0x1e94, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x1e60, 0, 0, 0, 0, + 0x1ea1, 0x1ea0, 0x1ea3, 0x1ea2, 0x1ea5, 0x1ea4, 0x1ea7, 0x1ea6, + 0x1ea9, 0x1ea8, 0x1eab, 0x1eaa, 0x1ead, 0x1eac, 0x1eaf, 0x1eae, + 0x1eb1, 0x1eb0, 0x1eb3, 0x1eb2, 0x1eb5, 0x1eb4, 0x1eb7, 0x1eb6, + 0x1eb9, 0x1eb8, 0x1ebb, 0x1eba, 0x1ebd, 0x1ebc, 0x1ebf, 0x1ebe, + 0x1ec1, 0x1ec0, 0x1ec3, 0x1ec2, 0x1ec5, 0x1ec4, 0x1ec7, 0x1ec6, + 0x1ec9, 0x1ec8, 0x1ecb, 0x1eca, 0x1ecd, 0x1ecc, 0x1ecf, 0x1ece, + 0x1ed1, 0x1ed0, 0x1ed3, 0x1ed2, 0x1ed5, 0x1ed4, 0x1ed7, 0x1ed6, + 0x1ed9, 0x1ed8, 0x1edb, 0x1eda, 0x1edd, 0x1edc, 0x1edf, 0x1ede, + 0x1ee1, 0x1ee0, 0x1ee3, 0x1ee2, 0x1ee5, 0x1ee4, 0x1ee7, 0x1ee6, + 0x1ee9, 0x1ee8, 0x1eeb, 0x1eea, 0x1eed, 0x1eec, 0x1eef, 0x1eee, + 0x1ef1, 0x1ef0, 0x1ef3, 0x1ef2, 0x1ef5, 0x1ef4, 0x1ef7, 0x1ef6, + 0x1ef9, 0x1ef8, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_1f [] = { + 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, + 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, + 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, 0x1f1c, 0x1f1d, 0, 0, + 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0, 0, + 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, 0x1f2c, 0x1f2d, 0x1f2e, 0x1f2f, + 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, + 0x1f38, 0x1f39, 0x1f3a, 0x1f3b, 0x1f3c, 0x1f3d, 0x1f3e, 0x1f3f, + 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, + 0x1f48, 0x1f49, 0x1f4a, 0x1f4b, 0x1f4c, 0x1f4d, 0, 0, + 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0, 0, + 0x0, 0x1f59, 0x0, 0x1f5b, 0x0, 0x1f5d, 0x0, 0x1f5f, + 0, 0x1f51, 0, 0x1f53, 0, 0x1f55, 0, 0x1f57, + 0x1f68, 0x1f69, 0x1f6a, 0x1f6b, 0x1f6c, 0x1f6d, 0x1f6e, 0x1f6f, + 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, + 0x1fba, 0x1fbb, 0x1fc8, 0x1fc9, 0x1fca, 0x1fcb, 0x1fda, 0x1fdb, + 0x1ff8, 0x1ff9, 0x1fea, 0x1feb, 0x1ffa, 0x1ffb, 0, 0, + 0x1f88, 0x1f89, 0x1f8a, 0x1f8b, 0x1f8c, 0x1f8d, 0x1f8e, 0x1f8f, + 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, + 0x1f98, 0x1f99, 0x1f9a, 0x1f9b, 0x1f9c, 0x1f9d, 0x1f9e, 0x1f9f, + 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, + 0x1fa8, 0x1fa9, 0x1faa, 0x1fab, 0x1fac, 0x1fad, 0x1fae, 0x1faf, + 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, + 0x1fb8, 0x1fb9, 0x0, 0x1fbc, 0x0, 0, 0x0, 0x0, + 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x1fb3, 0, 0x399, 0, + 0, 0, 0x0, 0x1fcc, 0x0, 0, 0x0, 0x0, + 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1fc3, 0, 0, 0, + 0x1fd8, 0x1fd9, 0x0, 0x0, 0, 0, 0x0, 0x0, + 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0, 0, 0, 0, + 0x1fe8, 0x1fe9, 0x0, 0x0, 0x0, 0x1fec, 0x0, 0x0, + 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0, 0, 0, + 0, 0, 0x0, 0x1ffc, 0x0, 0, 0x0, 0x0, + 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x1ff3, 0, 0, 0, +}; + +static const Q_UINT16 case_20 [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0x0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_21 [] = { + 0, 0, 0x0, 0, 0, 0, 0, 0x0, + 0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0, 0x0, 0, 0, + 0x761, 0x0, 0x0, 0x0, 0x0, 0x0, 0, 0, + 0, 0, 0, 0, 0x0, 0, 0x0, 0, + 0x0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0, 0x0, 0x0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_fb [] = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 case_ff [] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, + 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, + 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, + 0xff58, 0xff59, 0xff5a, 0, 0, 0, 0, 0, + 0, 0xff21, 0xff22, 0xff23, 0xff24, 0xff25, 0xff26, 0xff27, + 0xff28, 0xff29, 0xff2a, 0xff2b, 0xff2c, 0xff2d, 0xff2e, 0xff2f, + 0xff30, 0xff31, 0xff32, 0xff33, 0xff34, 0xff35, 0xff36, 0xff37, + 0xff38, 0xff39, 0xff3a, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +static const Q_UINT16 * const case_info[256] = { + + case_0, case_1, case_2, case_3, case_4, case_5, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + case_10, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, case_1e, case_1f, + case_20, case_21, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, case_fb, 0, 0, 0, case_ff, +}; + +static const Q_INT8 num_0 [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 2, 3, -1, -1, -1, -1, + -1, 1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_6 [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_9 [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_b [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_d [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 0, 1, + 2, 3, 4, 5, 6, 7, 8, 9, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_e [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_f [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_20 [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, -1, -1, -1, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 num_ff [] = { + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, +}; + +static const Q_INT8 * const decimal_info[256] = { + num_0, 0, 0, 0, 0, 0, num_6, 0, + 0, num_9, num_9, num_b, num_9, num_d, num_e, num_f, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + num_20, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, num_ff, +}; + +static const Q_UINT16 symmetricPairs[] = { + 0x0028, 0x0029, 0x0029, 0x0028, 0x003C, 0x003E, 0x003E, 0x003C, + 0x005B, 0x005D, 0x005D, 0x005B, 0x007B, 0x007D, 0x007D, 0x007B, + 0x2045, 0x2046, 0x2046, 0x2045, 0x207D, 0x207E, 0x207E, 0x207D, + 0x208D, 0x208E, 0x208E, 0x208D, 0x3008, 0x3009, 0x3009, 0x3008, + 0x300A, 0x300B, 0x300B, 0x300A, 0x300C, 0x300D, 0x300D, 0x300C, + 0x300E, 0x300F, 0x300F, 0x300E, 0x3010, 0x3011, 0x3011, 0x3010, + 0x3014, 0x3015, 0x3015, 0x3014, 0x3016, 0x3017, 0x3017, 0x3016, + 0x3018, 0x3019, 0x3019, 0x3018, 0x301A, 0x301B, 0x301B, 0x301A, + 0xFD3E, 0xFD3F, 0xFD3F, 0xFD3E, 0xFE59, 0xFE5A, 0xFE5A, 0xFE59, + 0xFE5B, 0xFE5C, 0xFE5C, 0xFE5B, 0xFE5D, 0xFE5E, 0xFE5E, 0xFE5D, + 0xFF08, 0xFF09, 0xFF09, 0xFF08, 0xFF3B, 0xFF3D, 0xFF3D, 0xFF3B, + 0xFF5B, 0xFF5D, 0xFF5D, 0xFF5B, 0xFF62, 0xFF63, 0xFF63, 0xFF62, +}; + +static int symmetricPairsSize = + sizeof(symmetricPairs)/sizeof(symmetricPairs[0]); + +/* + * ---------------------------------------------------------------------- + * End of unicode tables + * ---------------------------------------------------------------------- + */ + +#endif + + +static int ucstrcmp( const QString &as, const QString &bs ) +{ + const QChar *a = as.unicode(); + const QChar *b = bs.unicode(); + if ( a == b ) + return 0; + if ( a == 0 ) + return 1; + if ( b == 0 ) + return -1; + int l=QMIN(as.length(),bs.length()); + while ( l-- && *a == *b ) + a++,b++; + if ( l==-1 ) + return ( as.length()-bs.length() ); + return a->unicode() - b->unicode(); +} + +static int ucstrncmp( const QChar *a, const QChar *b, int l ) +{ + while ( l-- && *a == *b ) + a++,b++; + if ( l==-1 ) + return 0; + return a->unicode() - b->unicode(); +} + +static int ucstrnicmp( const QChar *a, const QChar *b, int l ) +{ + while ( l-- && a->lower() == b->lower() ) + a++,b++; + if ( l==-1 ) + return 0; + QChar al = a->lower(); + QChar bl = b->lower(); + return al.unicode() - bl.unicode(); +} + +// NOT REVISED +/*! \class QCharRef qstring.h + \brief The QCharRef class is a helper class for QString. + + It provides the ability to work on characters in a QString in a natural + fashion. + + When you get an object of type QCharRef, you can assign to it, which + will operate on the string from which you got it. That is its whole + purpose in life. It becomes invalid once further modifications are + made to the string: If you want to keep it, copy it into a QChar. + + Most of the QChar member functions also exist in QCharRef. However, + they are not explicitly documented here. + + \sa QString::operator[]() QString::at() QChar +*/ + +/*! \class QChar qstring.h + +\brief The QChar class provides a light-weight Unicode character. + +Unicode characters are (so far) 16-bit entities without any markup or +structure. This class represents such an entity. It is rather +light-weight, so it can be used everywhere. Most compilers treat it +approximately like "short int". (In a few years, it may be necessary +to make QChar 32-bit, once more than 65536 Unicode code points have +been defined and come into use.) + +QChar provides a full complement of testing/classification functions, +conversion to and from other formats, from composed to decomposed +unicode, and will try to compare and case-convert if you ask it to. + +The classification functions include functions like those in ctype.h, +but operating on the full range of unicode characters. They all +return TRUE if the character is a certain type of character, and FALSE +otherwise. + +These functions are: isNull() (returns TRUE if the character is +U+0000), isPrint() (TRUE if the character is any sort of printable +character, including whitespace), isPunct() (any sort of punctation), +isMark() (Unicode Marks), isLetter (letters), isNumber() (any sort of +numeric characters), isLetterOrNumber(), and isDigit() (decimal digits). +All of these are wrappers around category(), which returns the +unicode-defined category of each character. + +QChar further provides direction(), which indicates the "natural" +writing direction of this character, joining(), which indicates how +this character joins with its neighbors (needed mostly for Arabic) +and finally mirrored(), which indicates whether this character needs +to be mirrored when it is printed in its unnatural writing +direction. + +Composed Unicode characters (like å) can be converted to +decomposed Unicode ("a" followed by "ring above") using +decomposition(). + +In Unicode, comparison is not necessarily possible, and case +conversion is at best very hard. Unicode, covering the "entire" +globe, also includes a globe-sized collection of case and sorting +problems. Qt tries, but not very hard: operator== and friends will do +comparison based purely on the numeric Unicode value (code point) of +the characters, and upper() and lower() will do case changes when the +character has a well-defined upper/lower-case equivalent. There is no +provision for locale-dependent case folding rules or comparison: These +functions are meant to be fast, so they can be used unambiguously in +data structures. + +The conversion functions include unicode() (to a scalar), latin1() (to +scalar, but converts all non-Latin1 characters to 0), row() (gives the +Unicode row), cell() (gives the unicode cell), digitValue() (gives the +integer value of any of the numerous digit characters), and a host of +constructors. + +\sa QString QCharRef \link unicode.html About Unicode \endlink +*/ + +/*! \enum QChar::Category + +This enum maps the Unicode character categories. The currently known +categories are: <ul> + +<li> \c NoCategory - used when Qt is dazed and confused and cannot +make sense of anything. + +<li> \c Mark_NonSpacing - (Mn) - + +<li> \c Mark_SpacingCombining - (Mc) - + +<li> \c Mark_Enclosing - (Me) - + +<li> \c Number_DecimalDigit - (Nd) - + +<li> \c Number_Letter - (Nl) - + +<li> \c Number_Other - (No) - + +<li> \c Separator_Space - (Zs) - + +<li> \c Separator_Line - (Zl) - + +<li> \c Separator_Paragraph - (Zp) - + +<li> \c Other_Control - (Cc) - + +<li> \c Other_Format - (Cf) - + +<li> \c Other_Surrogate - (Cs) - + +<li> \c Other_PrivateUse - (Co) - + +<li> \c Other_NotAssigned - (Cn) - + +<li> \c Letter_Uppercase - (Lu) - + +<li> \c Letter_Lowercase - (Ll) - + +<li> \c Letter_Titlecase - (Lt) - + +<li> \c Letter_Modifier - (Lm) - + +<li> \c Letter_Other - (Lo) - + +<li> \c Punctuation_Connector - (Pc) - + +<li> \c Punctuation_Dask - (Pd) - + +<li> \c Punctuation_Open - (Ps) - + +<li> \c Punctuation_Close - (Pe) - + +<li> \c Punctuation_InitialQuote - (Pi) - + +<li> \c Punctuation_FinalQuote - (Pf) - + +<li> \c Punctuation_Other - (Po) - + +<li> \c Symbol_Math - (Sm) - + +<li> \c Symbol_Currency - (Sc) - + +<li> \c Symbol_Modifier - (Sk) - + +<li> \c Symbol_Other - (So) - + +</ul> +*/ + +/*! \enum QChar::Direction + + This enum type defines the Unicode direction attributes. + See <a href="http://www.unicode.org">the Unicode Standard</a> + for a description of the values. + + In order to conform to C/C++ naming conventions "Dir" is + prepended to the codes used in The Unicode Standard. +*/ + +/*! \enum QChar::Decomposition + + This enum type defines the Unicode decomposition attributes. + See <a href="http://www.unicode.org">the Unicode Standard</a> + for a description of the values. +*/ + +/*! \enum QChar::Joining + + This enum type defines the Unicode decomposition attributes. + See <a href="http://www.unicode.org">the Unicode Standard</a> + for a description of the values. +*/ + + + +/*! \fn QChar::QChar() + +Constructs a null QChar (one that isNull()). +*/ + + +/*! \fn QChar::QChar( char c ) + +Constructs a QChar corresponding to ASCII/Latin1 character \a c. +*/ + + +/*! \fn QChar::QChar( uchar c ) + +Constructs a QChar corresponding to ASCII/Latin1 character \a c. +*/ + + +/*! \fn QChar::QChar( uchar c, uchar r ) + +Constructs a QChar for Unicode cell \a c in row \a r. +*/ + + +/*! \fn QChar::QChar( const QChar& c ) + +Constructs a copy of \a c. This is a deep copy, if such a +light-weight object can be said to have deep copies. +*/ + + +/*! \fn QChar::QChar( ushort rc ) + +Constructs a QChar for the character with Unicode code point \a rc. +*/ + + +/*! \fn QChar::QChar( short rc ) + +Constructs a QChar for the character with Unicode code point \a rc. +*/ + + +/*! \fn QChar::QChar( uint rc ) + +Constructs a QChar for the character with Unicode code point \a rc. +*/ + + +/*! \fn QChar::QChar( int rc ) + +Constructs a QChar for the character with Unicode code point \a rc. +*/ + + +/*! \fn bool QChar::networkOrdered () + + Returns TRUE if this character is in network byte order (MSB first), + and FALSE if it is not. This is a platform-dependent property, so + we strongly advise against using this function in portable code. +*/ + + +/*! + \fn bool QChar::isNull() const + Returns TRUE if the characters is the unicode character 0x0000, + ie. ASCII NUL. +*/ + +/*! + \fn uchar QChar::cell () const + Returns the cell (least significant byte) of the Unicode character. +*/ +/*! + \fn uchar QChar::row () const + Returns the row (most significant byte) of the Unicode character. +*/ +/*! + \fn uchar& QChar::cell () + Returns a reference to the cell (least significant byte) of the Unicode character. +*/ +/*! + \fn uchar& QChar::row () + Returns a reference to the row (most significant byte) of the Unicode character. +*/ + +/*! + Returns whether the character is a printable character. This is + any character not of category Cc or Cn. Note that this gives no indication + of whether the character is available in some font. +*/ +bool QChar::isPrint() const +{ + Category c = category(); + return !(c == Other_Control || c == Other_NotAssigned); +} + +/*! + Returns whether the character is a separator + character (Separator_* categories). +*/ +bool QChar::isSpace() const +{ + if( !row() ) + if( cell() >= 9 && cell() <=13 ) return TRUE; + Category c = category(); + return c >= Separator_Space && c <= Separator_Paragraph; +} + +/*! + Returns whether the character is a mark (Mark_* categories). +*/ +bool QChar::isMark() const +{ + Category c = category(); + return c >= Mark_NonSpacing && c <= Mark_Enclosing; +} + +/*! + Returns whether the character is punctuation (Punctuation_* categories). +*/ +bool QChar::isPunct() const +{ + Category c = category(); + return (c >= Punctuation_Connector && c <= Punctuation_Other); +} + +/*! + Returns whether the character is a letter (Letter_* categories). +*/ +bool QChar::isLetter() const +{ + Category c = category(); + return (c >= Letter_Uppercase && c <= Letter_Other); +} + +/*! + Returns whether the character is a number (of any sort - Number_* categories). + + \sa isDigit() +*/ +bool QChar::isNumber() const +{ + Category c = category(); + return c >= Number_DecimalDigit && c <= Number_Other; +} + +/*! + Returns whether the character is a letter or number (Letter_* or Number_* categories). +*/ +bool QChar::isLetterOrNumber() const +{ + Category c = category(); + return (c >= Letter_Uppercase && c <= Letter_Other) + || (c >= Number_DecimalDigit && c <= Number_Other); +} + + +/*! + Returns whether the character is a decimal digit (Number_DecimalDigit). + */ +bool QChar::isDigit() const +{ + return (category() == Number_DecimalDigit); +} + +/*! + Returns the numeric value of the digit, or -1 if the character is not + a digit. +*/ +int QChar::digitValue() const +{ +#ifndef QT_NO_UNICODETABLES + const Q_INT8 *dec_row = decimal_info[row()]; + if( !dec_row ) + return -1; + return decimal_info[row()][cell()]; +#else + // ##### just latin1 + if ( rw != 0 || cl < '0' || cl > '9' ) + return -1; + else + return cl - '0'; +#endif +} + +/*! + Returns the character category. + + \sa Category +*/ +QChar::Category QChar::category() const +{ +#ifndef QT_NO_UNICODETABLES + return (Category)(unicode_info[row()][cell()]); +#else +// ### just ASCII + if ( rw == 0 ) { + return (Category)(ui_00[cell()]); + } + return Letter_Uppercase; //####### +#endif +} + +/*! + Returns the characters directionality. + + \sa Direction +*/ +QChar::Direction QChar::direction() const +{ +#ifndef QT_NO_UNICODETABLES + const Q_UINT8 *rowp = direction_info[row()]; + if(!rowp) return QChar::DirL; + return (Direction) ( *(rowp+cell()) &0x1f ); +#else + return DirL; +#endif +} + +/*! + This function is not supported (it may change to use Unicode + character classes). + + Returns information about the joining properties of the + character (needed for arabic). +*/ +QChar::Joining QChar::joining() const +{ +#ifndef QT_NO_UNICODETABLES + const Q_UINT8 *rowp = direction_info[row()]; + if ( !rowp ) + return QChar::OtherJoining; + return (Joining) ((*(rowp+cell()) >> 5) &0x3); +#else + return OtherJoining; +#endif +} + + +/*! + Returns whether the character is a mirrored character (one that + should be reversed if the text direction is reversed). +*/ +bool QChar::mirrored() const +{ +#ifndef QT_NO_UNICODETABLES + const Q_UINT8 *rowp = direction_info[row()]; + if ( !rowp ) + return FALSE; + return *(rowp+cell())>128; +#else + return FALSE; +#endif +} + +/*! + Returns the mirrored char if this character is a mirrored char, the char + itself otherwise +*/ +QChar QChar::mirroredChar() const +{ +#ifndef QT_NO_UNICODETABLES + if(!mirrored()) return *this; + + int i; + int c = unicode(); + for (i = 0; i < symmetricPairsSize; i += 2) { + if (symmetricPairs[i] == c) + return symmetricPairs[i+1]; + } + return 0; +#else + return *this; +#endif +} + +/*! + Decomposes a character into its parts. Returns QString::null if + no decomposition exists. +*/ +QString QChar::decomposition() const +{ +#ifndef QT_NO_UNICODETABLES + const Q_UINT16 *r = decomposition_info[row()]; + if(!r) return QString::null; + + Q_UINT16 pos = r[cell()]; + if(!pos) return QString::null; + pos+=2; + + QString s; + Q_UINT16 c; + while((c = decomposition_map[pos++]) != 0) s += QChar(c); + + return s; +#else + return null; +#endif +} + +/*! + Returns the tag defining the composition of the character. + Returns QChar::Single if no decomposition exists. +*/ +QChar::Decomposition QChar::decompositionTag() const +{ +#ifndef QT_NO_UNICODETABLES + const Q_UINT16 *r = decomposition_info[row()]; + if(!r) return QChar::Single; + + Q_UINT16 pos = r[cell()]; + if(!pos) return QChar::Single; + + return (QChar::Decomposition) decomposition_map[pos]; +#else + return Single; // ########### FIX eg. just latin1 +#endif +} + +/*! + Returns the lowercase equivalent if the character is uppercase, + or the character itself otherwise. +*/ +QChar QChar::lower() const +{ +#ifndef QT_NO_UNICODETABLES + if(category() != Letter_Uppercase) return *this; + Q_UINT16 lower = *(case_info[row()]+cell()); + if(lower == 0) return *this; + return lower; +#else + if (row()) + return *this; + else + return QChar(tolower(latin1())); +#endif +} + +/*! + Returns the uppercase equivalent if the character is lowercase, + or the character itself otherwise. +*/ +QChar QChar::upper() const +{ +#ifndef QT_NO_UNICODETABLES + if(category() != Letter_Lowercase) return *this; + Q_UINT16 upper = *(case_info[row()]+cell()); + if(upper == 0) return *this; + return upper; +#else + if (row()) + return *this; + else + return QChar(toupper(latin1())); +#endif +} + +/*! + \fn QChar::operator char() const + + Returns the Latin1 character equivalent to the QChar, + or 0. This is mainly useful for non-internationalized software. + + \sa unicode() +*/ + +/*! + \fn ushort QChar::unicode() const + + Returns the numeric Unicode value equal to the QChar. Normally, you + should use QChar objects as they are equivalent, but for some low-level + tasks (eg. indexing into an array of Unicode information), this function + is useful. +*/ + +/***************************************************************************** + Documentation of QChar related functions + *****************************************************************************/ + +/*! + \fn int operator==( QChar c1, QChar c2 ) + \relates QChar + + Returns TRUE if \a c1 and \a c2 are the same Unicode character. +*/ + +/*! + \fn int operator==( char ch, QChar c ) + \relates QChar + + Returns TRUE if \a c is the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator==( QChar c, char ch ) + \relates QChar + + Returns TRUE if \a c is the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator!=( QChar c1, QChar c2 ) + \relates QChar + + Returns TRUE if \a c1 and \a c2 are not the same Unicode character. +*/ + +/*! + \fn int operator!=( char ch, QChar c ) + \relates QChar + + Returns TRUE if \a c is not the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator!=( QChar c, char ch ) + \relates QChar + + Returns TRUE if \a c is not the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator<=( QChar c1, QChar c2 ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c1 is less than that + of \a c2, or they are the same Unicode character. +*/ + +/*! + \fn int operator<=( QChar c, char ch ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c is less than or + equal to that of the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator<=( char ch, QChar c ) + \relates QChar + + Returns TRUE if the numeric Unicode value of the ASCII/Latin1 + character \a ch is less than or equal to that of \a c. +*/ + +/*! + \fn int operator>=( QChar c1, QChar c2 ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c1 is greater than that + of \a c2, or they are the same Unicode character. +*/ + +/*! + \fn int operator>=( QChar c, char ch ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c is greater than or + equal to that of the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator>=( char ch, QChar c ) + \relates QChar + + Returns TRUE if the numeric Unicode value of the ASCII/Latin1 + character \a ch is greater than or equal to that of \a c. +*/ + +/*! + \fn int operator<( QChar c1, QChar c2 ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c1 is less than that + of \a c2. +*/ + +/*! + \fn int operator<( QChar c, char ch ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c is less than that + of the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator<( char ch, QChar c ) + \relates QChar + + Returns TRUE if the numeric Unicode value of the ASCII/Latin1 + character \a ch is less than that of \a c. +*/ + +/*! + \fn int operator>( QChar c1, QChar c2 ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c1 is greater than + that of \a c2. +*/ + +/*! + \fn int operator>( QChar c, char ch ) + \relates QChar + + Returns TRUE if the numeric Unicode value of \a c is greater than + that of the ASCII/Latin1 character \a ch. +*/ + +/*! + \fn int operator>( char ch, QChar c ) + \relates QChar + + Returns TRUE if the numeric Unicode value of the ASCII/Latin1 + character \a ch is greater than that of \a c. +*/ + +#ifndef QT_NO_UNICODETABLES + +// small class used internally in QString::Compose() +class QLigature +{ +public: + QLigature( QChar c ); + + Q_UINT16 first() { cur = ligatures; return cur ? *cur : 0; } + Q_UINT16 next() { return cur && *cur ? *(cur++) : 0; } + Q_UINT16 current() { return cur ? *cur : 0; } + + int match(QString & str, unsigned int index); + QChar head(); + QChar::Decomposition tag(); + +private: + Q_UINT16 *ligatures; + Q_UINT16 *cur; +}; + +QLigature::QLigature( QChar c ) +{ + const Q_UINT16 *r = ligature_info[c.row()]; + if( !r ) + ligatures = 0; + else + { + const Q_UINT16 pos = r[c.cell()]; + ligatures = (Q_UINT16 *)&(ligature_map[pos]); + } + cur = ligatures; +} + +QChar QLigature::head() +{ + if(current()) + return QChar(decomposition_map[current()+1]); + + return QChar::null; +} + +QChar::Decomposition QLigature::tag() +{ + if(current()) + return (QChar::Decomposition) decomposition_map[current()]; + + return QChar::Canonical; +} + +int QLigature::match(QString & str, unsigned int index) +{ + unsigned int i=index; + + if(!current()) return 0; + + Q_UINT16 lig = current() + 2; + Q_UINT16 ch; + + while ((i < str.length()) && (ch = decomposition_map[lig])) { + if (str[(int)i] != QChar(ch)) + return 0; + i++; lig++; + } + + if (!decomposition_map[lig]) + { + return i-index; + } + return 0; +} + +#endif + +// this function is just used in QString::compose() +static inline bool format(QChar::Decomposition tag, QString & str, + int index, int len) +{ + unsigned int l = index + len; + unsigned int r = index; + + bool left = FALSE, right = FALSE; + + left = ((l < str.length()) && + ((str[(int)l].joining() == QChar::Dual) || + (str[(int)l].joining() == QChar::Right))); + if (r > 0) { + r--; + //printf("joining(right) = %d\n", str[(int)r].joining()); + right = (str[(int)r].joining() == QChar::Dual); + } + + + switch (tag) { + case QChar::Medial: + return (left & right); + case QChar::Initial: + return (left && !right); + case QChar::Final: + return (right);// && !left); + case QChar::Isolated: + default: + return (!right && !left); + } +} // format() + +/* + QString::compose() and visual() were developed by Gordon Tisher + <tisher@uniserve.ca>, with input from Lars Knoll <knoll@mpi-hd.mpg.de>, + who developed the unicode data tables. +*/ +/*! + Note that this function is not supported in Qt 2.0, and is merely + for experimental and illustrative purposes. It is mainly of interest + to those experimenting with Arabic and other composition-rich texts. + + Applies possible ligatures to a QString, useful when composition-rich + text requires rendering with glyph-poor fonts, but also + makes compositions such as QChar(0x0041) ('A') and QChar(0x0308) + (Unicode accent diaresis) giving QChar(0x00c4) (German A Umlaut). +*/ +void QString::compose() +{ +#ifndef QT_NO_UNICODETABLES + unsigned int index=0, len; + unsigned int cindex = 0; + + QChar code, head; + + QArray<QChar> dia; + + QString composed = *this; + + while (index < length()) { + code = at(index); + //printf("\n\nligature for 0x%x:\n", code.unicode()); + QLigature ligature(code); + ligature.first(); + while(ligature.current()) { + if ((len = ligature.match(*this, index)) != 0) { + head = ligature.head(); + unsigned short code = head.unicode(); + // we exclude Arabic presentation forms A and a few + // other ligatures, which are undefined in most fonts + if(!(code > 0xfb50 && code < 0xfe80) && + !(code > 0xfb00 && code < 0xfb2a)) { + // joining info is only needed for arabic + if (format(ligature.tag(), *this, index, len)) { + //printf("using ligature 0x%x, len=%d\n",code,len); + // replace letter + composed.replace(cindex, len, QChar(head)); + index += len-1; + // we continue searching in case we have a final + // form because medial ones are preferred. + if ( len != 1 || ligature.tag() !=QChar::Final ) + break; + } + } + } + ligature.next(); + } + cindex++; + index++; + } + *this = composed; +#endif +} + +static QChar LRM ((ushort)0x200e); +static QChar RLM ((ushort)0x200f); +static QChar LRE ((ushort)0x202a); +static QChar RLE ((ushort)0x202b); +static QChar RLO ((ushort)0x202e); +static QChar LRO ((ushort)0x202d); +static QChar PDF ((ushort)0x202c); + +#if 0 +static inline bool is_arabic(unsigned short x) { + return (((x >= 0x0600) && (x <= 0x07bf)) || + ((x >= 0xfb50) && (x <= 0xfdff)) || + ((x >= 0xfe70) && (x <= 0xfeff))); +} +#endif + +static inline bool is_neutral(unsigned short dir) { + return ((dir == QChar::DirB) || + (dir == QChar::DirS) || + (dir == QChar::DirWS) || + (dir == QChar::DirON) || + (dir == QChar::DirNSM)); +} + +/*! + This function returns the basic directionality of the string (QChar::DirR for + right to left and QChar::DirL for left to right). Useful to find the right + alignment. + */ +QChar::Direction QString::basicDirection() +{ +#ifndef QT_NO_UNICODETABLES + // find base direction + unsigned int pos = 0; + while ((pos < length()) && + (at(pos) != RLE) && + (at(pos) != LRE) && + (at(pos) != RLO) && + (at(pos) != LRO) && + (at(pos).direction() > 1) && + (at(pos).direction() != QChar::DirAL)) // not R and not L + pos++; + + if ((at(pos).direction() == QChar::DirR) || + (at(pos).direction() == QChar::DirAL) || + (at(pos) == RLE) || + (at(pos) == RLO)) + return QChar::DirR; +#endif + + return QChar::DirL; +} + +#ifndef QT_NO_UNICODETABLES +// reverses part of the QChar array to get visual ordering +// called from QString::visual() +// +static unsigned int reverse( QString &chars, unsigned char *level, + unsigned int a, unsigned int b) +{ + unsigned int c = a; + unsigned char lev = level[c]; + + while ((c < b) && (level[c] >= lev)) { + if (level[c] > lev) + c = reverse(chars, level, c, b); + c++; + } + + if (lev > 0) { + QChar temp; + unsigned int d = a, e = c-1; + while (d < e) { + temp = chars[(int)d]; + chars[(int)d] = chars[(int)e]; + chars[(int)e] = temp; + + d++; e--; + } + } + + return c; +} + +// small class used for the ordering algorithm in QString::visual() +class QBidiState { +public: + unsigned char level; + signed char override; + + QBidiState(unsigned char l, signed char o) : level(l), override(o) {}; +}; + +// matrix for resolving neutral types + +#define NEG1 (QChar::Direction)(-1) + +static QChar::Direction resolv[5][5] = +{ + { NEG1, QChar::DirR, QChar::DirL, QChar::DirEN, QChar::DirAN }, + { QChar::DirR, QChar::DirR, NEG1, QChar::DirR, QChar::DirR }, + { QChar::DirL, NEG1, QChar::DirL, QChar::DirL, NEG1 }, + { QChar::DirEN, QChar::DirR, QChar::DirL, QChar::DirEN, QChar::DirR }, + { QChar::DirAN, QChar::DirR, NEG1, NEG1, QChar::DirAN } +}; + +#endif + +/*! + This function returns the QString ordered visually. Useful for + painting the string or when transforming to a visually ordered + encoding. +*/ +QString QString::visual(int index, int len) +{ +#ifndef QT_NO_UNICODETABLES + // #### This needs much more optimizing - it is called for + // #### every text operation. + + unsigned char *level; + QChar::Direction *dir; + unsigned char base = 0; + + unsigned int l = length(); + + // check bounds + if (len == -1) + len = length()-index; + if ((uint)index > l) + return QString::null; + + // find base direction + unsigned int pos = 0; + while ((pos < length()) && + (at(pos) != RLE) && + (at(pos) != LRE) && + (at(pos) != RLO) && + (at(pos) != LRO) && + (at(pos).direction() > 1) && + (at(pos).direction() != QChar::DirAL) + ) // not R and not L + pos++; + + if ((pos < length()) && + ((at(pos).direction() == QChar::DirR) || + (at(pos).direction() == QChar::DirAL) || + (at(pos) == RLE) || + (at(pos) == RLO))) + base = 1; + + // is there any BiDi char at all? + if ( base == 0 && pos == l ) { + return mid(index, len); + } + + + level = new uchar[l]; + dir = new QChar::Direction[l]; + + // explicit override pass + //unsigned int code_count = 0; + + QStack<QBidiState> stack; + stack.setAutoDelete(TRUE); + + unsigned char clevel = base; + signed char override = -1; + + for (pos = 0; pos < l; pos++) { + + if (at(pos) == RLE) { + //code_count++; + stack.push(new QBidiState(clevel, override)); + if (clevel < 254) + clevel += 1 + clevel % 2; + override = -1; + } + else if (at(pos) == LRE) { + //code_count++; + stack.push(new QBidiState(clevel, override)); + if (clevel < 254) + clevel += 2 - clevel % 2; + override = -1; + } + else if (at(pos) == RLO) { + //code_count++; + stack.push(new QBidiState(clevel, override)); + if (clevel < 254) + clevel += 1 + clevel % 2; + override = QChar::DirR; + } + else if (at(pos) == LRO) { + //code_count++; + stack.push(new QBidiState(clevel, override)); + if (clevel < 254) + clevel += 2 - clevel % 2; + override = QChar::DirL; + } + else if (at(pos) == PDF) { + //code_count++; + if (!stack.isEmpty()) { + override = stack.top()->override; + clevel = stack.top()->level; + stack.remove(); + } + } + + // TODO: catch block separators (newlines, paras, etc.) + + level[pos] = clevel; + if (override != -1) + dir[pos] = (QChar::Direction) override; + else + dir[pos] = at(pos).direction(); + } + + // weak type pass + for (pos = 0; pos < l; pos++) { + + int i; + + switch (at(pos).direction()) { + case QChar::DirEN: + i = pos-1; + while ((i >= 0) && + !(at(i).direction() == QChar::DirAN) && + !(at(i).direction() == QChar::DirAL) && + !(at(i).direction() == QChar::DirB)) + i--; + + if ((i >= 0) && + ((at(i).direction() == QChar::DirAN) || + (at(i).direction() == QChar::DirAL))) + dir[pos] = QChar::DirAN; + + break; + case QChar::DirES: + case QChar::DirCS: + if ((pos > 0) && (pos < l-1) && + (dir[pos-1] == dir[pos+1])) + dir[pos] = dir[pos-1]; + else + dir[pos] = QChar::DirON; + + break; + case QChar::DirET: + if (((pos > 0) && (dir[pos-1] == QChar::DirEN)) || + ((pos < l-1) && (dir[pos+1] == QChar::DirEN))) + dir[pos] = QChar::DirEN; + else + dir[pos] = QChar::DirON; + + break; + case QChar::DirAL: + dir[pos] = QChar::DirR; + break; + default: + break; + } + } + + // neutral type pass + for (pos = 0; pos < l; pos++) { + QChar::Direction left,right; // declaring l here shadowed previous l + + if (is_neutral(dir[pos])) { + if (pos > 0) + left = dir[pos-1]; + else + left = (base == 0 ? QChar::DirL : QChar::DirR); + + int i = pos; + + while ((i < (int)l-1) && is_neutral(dir[i+1])) + i++; + + if (i < (int)l-1) + right = dir[i+1]; + else + right = (base == 0 ? QChar::DirL : QChar::DirR); + + for (int j=pos; j <= i; j++) { + int a = 1, b = 1; + while ((a < 5) && (left != resolv[0][a])) + a++; + while ((b < 5) && (right != resolv[0][b])) + b++; + if ((a == 5) || (b == 5)) + dir[j] = (base == 0 ? QChar::DirL : QChar::DirR); + else + dir[j] = resolv[a][b]; + + if (dir[j] == (QChar::Direction)(-1)) + dir[j] = (base == 0 ? QChar::DirL : QChar::DirR); + } + } + } + + // implicit level pass + QChar::Direction prec = (base == 0 ? QChar::DirL : QChar::DirR); + + for (pos = 0; pos < l; pos++) { + if (level[pos] % 2) { + switch (dir[pos]) { + case QChar::DirL: + case QChar::DirAN: + case QChar::DirEN: + level[pos] += 1; + break; + default: + break; + } + } else { + switch (dir[pos]) { + case QChar::DirL: + // do nothing + break; + case QChar::DirR: + level[pos] += 1; + break; + case QChar::DirEN: + if (prec == QChar::DirL) + continue; + // fall through + case QChar::DirAN: + level[pos] += 2; + break; + default: + break; + } + } + + prec = dir[pos]; + } + + // now do the work! + QString ret(*this); + reverse(ret, level, index, index+len); + + delete [] level; + delete [] dir; + + return ret; +#else + return mid(index,len); +#endif +} + + + +// These macros are used for efficient allocation of QChar strings. +// IMPORTANT! If you change these, make sure you also change the +// "delete unicode" statement in ~QStringData() in qstring.h correspondingly! + +#define QT_ALLOC_QCHAR_VEC( N ) (QChar*) new char[ sizeof(QChar)*( N ) ] +#define QT_DELETE_QCHAR_VEC( P ) delete[] ((char*)( P )) + + +/*! + This utility function converts the 8-bit string + \a ba to Unicode, returning the result. + + The caller is responsible for deleting the return value with delete[]. +*/ + +QChar* QString::asciiToUnicode( const QByteArray& ba, uint* len ) +{ + if ( ba.isNull() ) { + *len = 0; + return 0; + } + int l = 0; + while ( l < (int)ba.size() && ba[l] ) + l++; + char* str = ba.data(); + QChar *uc = new QChar[ l ]; // Can't use macro, since function is public + QChar *result = uc; + if ( len ) + *len = l; + while (l--) + *uc++ = *str++; + return result; +} + +static QChar* internalAsciiToUnicode( const QByteArray& ba, uint* len ) +{ + if ( ba.isNull() ) { + *len = 0; + return 0; + } + int l = 0; + while ( l < (int)ba.size() && ba[l] ) + l++; + char* str = ba.data(); + QChar *uc = QT_ALLOC_QCHAR_VEC( l ); + QChar *result = uc; + if ( len ) + *len = l; + while (l--) + *uc++ = *str++; + return result; +} + +/*! + This utility function converts the NUL-terminated 8-bit string + \a str to Unicode, returning the result and setting \a len to + the length of the Unicode string. + + The caller is responsible for deleting the return value with delete[]. +*/ + +QChar* QString::asciiToUnicode( const char *str, uint* len, uint maxlen ) +{ + QChar* result = 0; + uint l = 0; + if ( str ) { + if ( maxlen != (uint)-1 ) { + while ( l < maxlen && str[l] ) + l++; + } else { + // Faster? + l = qstrlen(str); + } + QChar *uc = new QChar[ l ]; // Can't use macro since function is public + result = uc; + uint i = l; + while ( i-- ) + *uc++ = *str++; + } + if ( len ) + *len = l; + return result; +} + +static QChar* internalAsciiToUnicode( const char *str, uint* len, + uint maxlen = (uint)-1 ) +{ + QChar* result = 0; + uint l = 0; + if ( str ) { + if ( maxlen != (uint)-1 ) { + while ( l < maxlen && str[l] ) + l++; + } else { + // Faster? + l = qstrlen(str); + } + QChar *uc = QT_ALLOC_QCHAR_VEC( l ); + result = uc; + uint i = l; + while ( i-- ) + *uc++ = *str++; + } + if ( len ) + *len = l; + return result; +} + +/*! + This utility function converts \a l 16-bit characters from + \a uc to ASCII, returning a NUL-terminated string. + + The caller is responsible for deleting the string with delete[]. +*/ +char* QString::unicodeToAscii(const QChar *uc, uint l) +{ + if (!uc) { + return 0; + } + char *a = new char[l+1]; + char *result = a; + while (l--) + *a++ = *uc++; + *a = '\0'; + return result; +} + +/***************************************************************************** + QString member functions + *****************************************************************************/ + +/*! + \class QString qstring.h + + \brief The QString class provides an abstraction of Unicode text and + the classic C null-terminated char array (<var>char*</var>). + + \ingroup tools + \ingroup shared + + QString uses \link shclass.html implicit sharing\endlink, and so it + is very efficient and easy to use. + + In all QString methods that take <var>const char*</var> parameters, + the <var>const char*</var> is interpreted as a classic C-style + 0-terminated ASCII string. It is legal for the <var>const + char*</var> parameter to be 0. The results are undefined if the + <var>const char*</var> string is not 0-terminated. Functions that + copy classic C strings into a QString will not copy the terminating + 0-character. The QChar array of the QString (as returned by + unicode()) is not terminated by a null. + + A QString that has not been assigned to anything is \a null, i.e. both + the length and data pointer is 0. A QString that references the empty + string ("", a single '\0' char) is \a empty. Both null and empty + QStrings are legal parameters to the methods. Assigning <var>const char + * 0</var> to QString gives a null QString. + + Note that if you find that you are mixing usage of QCString, QString, + and QByteArray, this causes lots of unnecessary copying and might + indicate that the true nature of the data you are dealing with is + uncertain. If the data is NUL-terminated 8-bit data, use QCString; + if it is unterminated (ie. contains NULs) 8-bit data, use QByteArray; + if it is text, use QString. + + \sa QChar \link shclass.html Shared classes\endlink +*/ + +Q_EXPORT QStringData *QString::shared_null = 0; +QT_STATIC_CONST_IMPL QString QString::null; +QT_STATIC_CONST_IMPL QChar QChar::null; +QT_STATIC_CONST_IMPL QChar QChar::replacement((ushort)0xfffd); +QT_STATIC_CONST_IMPL QChar QChar::byteOrderMark((ushort)0xfeff); +QT_STATIC_CONST_IMPL QChar QChar::byteOrderSwapped((ushort)0xfffe); +QT_STATIC_CONST_IMPL QChar QChar::nbsp((ushort)0x00a0); + +QStringData* QString::makeSharedNull() +{ + return shared_null=new QStringData; +} + +// Uncomment this to get some useful statistics. +// #define Q2HELPER(x) x + +#ifdef Q2HELPER +static int stat_construct_charstar=0; +static int stat_construct_charstar_size=0; +static int stat_construct_null=0; +static int stat_construct_int=0; +static int stat_construct_int_size=0; +static int stat_construct_ba=0; +static int stat_get_ascii=0; +static int stat_get_ascii_size=0; +static int stat_copy_on_write=0; +static int stat_copy_on_write_size=0; +static int stat_fast_copy=0; +Q_EXPORT void qt_qstring_stats() +{ + qDebug("construct_charstar = %d (%d chars)", stat_construct_charstar, stat_construct_charstar_size); + qDebug("construct_null = %d", stat_construct_null); + qDebug("construct_int = %d (%d chars)", stat_construct_int, stat_construct_int_size); + qDebug("construct_ba = %d", stat_construct_ba); + qDebug("get_ascii = %d (%d chars)", stat_get_ascii, stat_get_ascii_size); + qDebug("copy_on_write = %d (%d chars)", stat_copy_on_write, stat_copy_on_write_size); + qDebug("fast_copy = %d", stat_fast_copy); +} +#else +#define Q2HELPER(x) +#endif + +/*! + \fn QString::QString() + + Constructs a null string. + \sa isNull() +*/ + +/*! + Constructs a string containing the one character \a ch. +*/ +QString::QString( QChar ch ) +{ + d = new QStringData( QT_ALLOC_QCHAR_VEC( 1 ), 1, 1 ); + d->unicode[0] = ch; +} + +/*! + Constructs an implicitly-shared copy of \a s. +*/ +QString::QString( const QString &s ) : + d(s.d) +{ + Q2HELPER(stat_fast_copy++) + d->ref(); +} + +/*! + Private function. + + Constructs a string with preallocated space for \a size characters. + + The string is empty. + + \sa isNull() +*/ + +QString::QString( int size, bool /*dummy*/ ) +{ + if ( size ) { + Q2HELPER(stat_construct_int++) + int l = size; + Q2HELPER(stat_construct_int_size+=l) + QChar* uc = QT_ALLOC_QCHAR_VEC( l ); + d = new QStringData( uc, 0, l ); + } else { + Q2HELPER(stat_construct_null++) + d = shared_null ? shared_null : (shared_null=new QStringData); + d->ref(); + } +} + +/*! + Constructs a string that is a deep copy of \a ba interpreted as + a classic C string. +*/ + +QString::QString( const QByteArray& ba ) +{ + Q2HELPER(stat_construct_ba++) + uint l; + QChar *uc = internalAsciiToUnicode(ba,&l); + d = new QStringData(uc,l,l); +} + +QString::QString( const QCString& ba ) +{ + Q2HELPER(stat_construct_ba++) + uint l; + QChar *uc = internalAsciiToUnicode(ba,&l); + d = new QStringData(uc,l,l); +} + +/*! + Constructs a string that is a deep copy of the + first \a length QChar in the array \a unicode. + + If \a unicode and \a length are 0, a null string is created. + + If only \a unicode is 0, the string is empty, but has + \a length characters of space preallocated - QString expands + automatically anyway, but this may speed some cases up a little. + + \sa isNull() +*/ + +QString::QString( const QChar* unicode, uint length ) +{ + if ( !unicode && !length ) { + d = shared_null ? shared_null : makeSharedNull(); + d->ref(); + } else { + QChar* uc = QT_ALLOC_QCHAR_VEC( length ); + if ( unicode ) + memcpy(uc, unicode, length*sizeof(QChar)); + d = new QStringData(uc,unicode ? length : 0,length); + } +} + +/*! + Constructs a string that is a deep copy of \a str, interpreted as a + classic C string. + + If \a str is 0 a null string is created. + + This is a cast constructor, but it is perfectly safe: converting a Latin1 + const char* to QString preserves all the information. + You can disable this constructor by + defining QT_NO_CAST_ASCII when you compile your applications. + You can also make QString objects by using setLatin1()/fromLatin1(), or + fromLocal8Bit(), fromUtf8(), or whatever encoding is appropriate for + the 8-bit data you have. + + \sa isNull() +*/ + +QString::QString( const char *str ) +{ + Q2HELPER(stat_construct_charstar++) + uint l; + QChar *uc = internalAsciiToUnicode(str,&l); + Q2HELPER(stat_construct_charstar_size+=l) + d = new QStringData(uc,l,l); +} + + +/*! \fn QString::~QString() + +Destroys the string and frees the "real" string, if this was the last +copy of that string. +*/ + + +/*! + Deallocates any space reserved solely by this QString. +*/ + +void QString::real_detach() +{ + setLength( length() ); +} + +void QString::deref() +{ + if ( d->deref() ) { + if ( d == shared_null ) + shared_null = 0; + delete d; + d = 0; // helps debugging + } +} + +void QStringData::deleteSelf() +{ + delete this; +} + +/*! + \fn QString& QString::operator=( QChar c ) + Sets the string to contain just the single character \a c. +*/ + +/*! + \fn QString& QString::operator=( char c ) + Sets the string to contain just the single character \a c. +*/ + +/*! + Assigns a shallow copy of \a s to this string and returns a + reference to this string. +*/ +QString &QString::operator=( const QString &s ) +{ + Q2HELPER(stat_fast_copy++) + s.d->ref(); + deref(); + d = s.d; + return *this; +} + +/*! + Assigns a deep copy of \a cs, interpreted as a classic C string, to + this string and returns a reference to this string. +*/ +QString &QString::operator=( const QCString& cs ) +{ + return setLatin1(cs); +} + + +/*! + Assigns a deep copy of \a str, interpreted as a classic C string, + to this string and returns a reference to this string. + + If \a str is 0 a null string is created. + + \sa isNull() +*/ +QString &QString::operator=( const char *str ) +{ + return setLatin1(str); +} + + +/*! + \fn bool QString::isNull() const + + Returns TRUE if the string is null. + A null string is also an empty string. + + Example: + \code + QString a; // a.unicode() == 0, a.length() == 0 + QString b = ""; // b.unicode() == "", b.length() == 0 + a.isNull(); // TRUE, because a.unicode() == 0 + a.isEmpty(); // TRUE, because a.length() == 0 + b.isNull(); // FALSE, because b.unicode() != 0 + b.isEmpty(); // TRUE, because b.length() == 0 + \endcode + + \sa isEmpty(), length() +*/ + +/*! + \fn bool QString::isEmpty() const + + Returns TRUE if the string is empty, i.e. if length() == 0. + An empty string is not always a null string. + + See example in isNull(). + + \sa isNull(), length() +*/ + +/*! + \fn uint QString::length() const + + Returns the length of the string. + + Null strings and empty strings have zero length. + + \sa isNull(), isEmpty() +*/ + +/*! + Truncates the string at position \a newLen if newLen is less than the + current length . Otherwise, nothing happens. + + Example: + \code + QString s = "truncate this string"; + s.truncate( 5 ); // s == "trunc" + \endcode + + In Qt 1.x, it was possible to "truncate" a string to a longer + length. This is no longer possible. + +*/ + +void QString::truncate( uint newLen ) +{ + if ( newLen < d->len ) + setLength( newLen ); +} + +/*### Make this public in 3.0 + Ensures that at least \a newLen characters are allocated, and + sets the length to \a newLen. This function always detaches the + string from other references to the same data. Any new space + allocated is \e not defined. + + If \a newLen is 0, this string becomes empty, unless this string is + null, in which case it remains null. + + \sa truncate(), isNull(), isEmpty() +*/ + +void QString::setLength( uint newLen ) +{ + if ( d->count != 1 || newLen > d->maxl || // detach, grow, or + ( newLen*4 < d->maxl && d->maxl > 4 ) ) { // shrink + Q2HELPER(stat_copy_on_write++) + Q2HELPER(stat_copy_on_write_size+=d->len) + uint newMax = 4; + while ( newMax < newLen ) + newMax *= 2; + QChar* nd = QT_ALLOC_QCHAR_VEC( newMax ); + uint len = QMIN( d->len, newLen ); + if ( d->unicode ) + memcpy( nd, d->unicode, sizeof(QChar)*len ); + deref(); + d = new QStringData( nd, newLen, newMax ); + } else { + d->len = newLen; + d->dirtyascii = 1; + } +} + +/*! Returns a string equal to this one, but with the lowest-numbered + occurrence of \c %i (for a positive integer i) replaced by \a a. + + \code + label.setText( tr("Rename %1 to %2?").arg(oldName).arg(newName) ); + \endcode + + \a fieldwidth is the minimum amount of space \a a is padded to. A + positive value produces right-aligned text, while a negative value + produces left aligned text. + + \warning Using arg() for constructing "real" sentences + programmatically is likely to lead to translation problems. + Inserting objects like numbers or file names is fairly safe. + + \warning Relying on spaces to create alignment is prone to lead to + translation problems. + + If there is no \c %i pattern, a warning message (qWarning()) is + printed and the text as appended at the end of the string. This is + error recovery and should not occur in correct code. + + \sa QObject::tr() +*/ +QString QString::arg(const QString& a, int fieldwidth) const +{ + int pos, len; + QString r = *this; + + if ( !findArg( pos, len ) ) { + qWarning( "QString::arg(): Argument missing: %s, %s", + (const char *)this, (const char *)a ); + // Make sure the text at least appears SOMEWHERE + r += ' '; + pos = r.length(); + len = 0; + } + + r.replace( pos, len, a ); + if ( fieldwidth < 0 ) { + QString s; + while ( (uint)-fieldwidth > a.length() ) { + s += ' '; + fieldwidth++; + } + r.insert( pos + a.length(), s ); + } else if ( fieldwidth ) { + QString s; + while ( (uint)fieldwidth > a.length() ) { + s += ' '; + fieldwidth--; + } + r.insert( pos, s ); + } + + return r; +} + + +/*! \overload + + \a a is expressed in to \a base notation, which is decimal by + default and must be in the range 2-36 inclusive. +*/ +QString QString::arg(long a, int fieldwidth, int base) const +{ + return arg( QString::number( a, base ), fieldwidth ); +} + +/*! \overload + + \a a is expressed in to \a base notation, which is decimal by + default and must be in the range 2-36 inclusive. +*/ +QString QString::arg(ulong a, int fieldwidth, int base) const +{ + return arg( QString::number( a, base ), fieldwidth ); +} + +/*! + \overload QString QString::arg(int a, int fieldwidth, int base) const + + \a a is expressed in to \a base notation, which is decimal by + default and must be in the range 2-36 inclusive. + +*/ + +/*! + \overload QString QString::arg(uint a, int fieldwidth, int base) const + + \a a is expressed in to \a base notation, which is decimal by + default and must be in the range 2-36 inclusive. +*/ + +/*! + \overload QString QString::arg(short a, int fieldwidth, int base) const + + \a a is expressed in to \a base notation, which is decimal by + default and must be in the range 2-36 inclusive. +*/ + +/*! + \overload QString QString::arg(ushort a, int fieldwidth, int base) const + + \a a is expressed in to \a base notation, which is decimal by + default and must be in the range 2-36 inclusive. +*/ + + +/*! \overload + + \a a is assumed to be in the Latin1 character set. +*/ +QString QString::arg(char a, int fieldwidth) const +{ + QString c; + c += a; + return arg( c, fieldwidth ); +} + +/*! \overload +*/ +QString QString::arg(QChar a, int fieldwidth) const +{ + QString c; + c += a; + return arg( c, fieldwidth ); +} + +/*! \overload + + \a is formatted according to the \a fmt format specified, which is + 'g' by default and can be any of 'f', 'F', 'e', 'E', 'g' or 'G', all + of which have the same meaning as for sprintf(). \a prec determines + the precision, just as for number() and sprintf(). +*/ +QString QString::arg(double a, int fieldwidth, char fmt, int prec) const +{ + return arg( QString::number( a, fmt, prec ), fieldwidth ); +} + + +/*! + Just 1-digit arguments. +*/ +bool QString::findArg(int& pos, int& len) const +{ + char lowest=0; + for (uint i=0; i<length(); i++) { + if ( at(i) == '%' && i+1<length() ) { + char dig = at(i+1); + if ( dig >= '0' && dig <= '9' ) { + if ( !lowest || dig < lowest ) { + lowest = dig; + pos = i; + len = 2; + } + } + } + } + return lowest != 0; +} + +/*! + Safely builds a formatted string from a format string and an + arbitrary list of arguments. The format string supports all + the escape sequences of printf() in the standard C library. + + The %s escape sequence expects a utf8() encoded string. + The format string \e cformat is expected to be in latin1. If you need a unicode + format string, use QString::arg() instead. For typesafe + string building, with full Unicode support, you can use QTextOStream + like this: + + \code + QString str; + QString s = ...; + int x = ...; + QTextOStream(&str) << s << " : " << x; + \endcode + + For \link QObject::tr() translations,\endlink especially if the + strings contains more than one escape sequence, you should consider + using the arg() function instead. This allows the order of the + replacements to be controlled by the translator, and has Unicode + support. + + \sa arg() +*/ + +QString &QString::sprintf( const char* cformat, ... ) +{ + va_list ap; + va_start( ap, cformat ); + + if ( !cformat || !*cformat ) { + // Qt 1.x compat + *this = QString::fromLatin1( "" ); + return *this; + } + QString format = QString::fromLatin1( cformat ); + + static QRegExp *escape = 0; + if (!escape) + escape = new QRegExp( "%#?0?-? ?\\+?'?[0-9*]*\\.?[0-9*]*h?l?L?q?Z?" ); + + QString result; + uint last = 0; + + int len = 0; + int pos; + while ( 1 ) { + pos = escape->match( format, last, &len ); + // Non-escaped text + if ( pos > (int)last ) + result += format.mid(last,pos-last); + if ( pos < 0 ) { + // The rest + if ( last < format.length() ) + result += format.mid(last); + break; + } + last = pos + len + 1; + + // Escape + QString f = format.mid( pos, len ); + uint width, decimals; + int params = 0; + int wpos = f.find('*'); + if ( wpos >= 0 ) { + params++; + width = va_arg( ap, int ); + if ( f.find('*', wpos + 1) >= 0 ) { + decimals = va_arg( ap, int ); + params++; + } else { + decimals = 0; + } + } else { + decimals = width = 0; + } + QString replacement; + if ( format[pos+len] == 's' || + format[pos+len] == 'S' || + format[pos+len] == 'c' ) + { + bool rightjust = ( f.find('-') < 0 ); + // Yes, %-5s really means left adjust in sprintf + + if ( wpos < 0 ) { + QRegExp num( QString::fromLatin1("[0-9]+") ); + QRegExp dot( QString::fromLatin1("\\.") ); + int nlen; + int p = num.match( f, 0, &nlen ); + int q = dot.match( f, 0 ); + if ( q < 0 || (p < q && p >= 0) ) + width = f.mid( p, nlen ).toInt(); + if ( q >= 0 ) { + p = num.match( f, q ); + // "decimals" is used to specify string truncation + if ( p >= 0 ) + decimals = f.mid( p, nlen ).toInt(); + } + } + + if ( format[pos+len] == 's' ) { +#ifndef QT_NO_TEXTCODEC + QString s = QString::fromUtf8(va_arg(ap, char*)); +#else + QString s = QString::fromLatin1(va_arg(ap, char*)); +#endif + if ( decimals <= 0 ) + replacement = s; + else + replacement = s.left(decimals); + } else { + int ch = va_arg(ap, int); + replacement = QChar((ushort)ch); + } + if ( replacement.length() < width ) { + replacement = rightjust + ? replacement.rightJustify(width) + : replacement.leftJustify(width); + } + } else if ( format[pos+len] == '%' ) { + replacement = '%'; + } else if ( format[pos+len] == 'n' ) { + int* n = va_arg(ap, int*); + *n = result.length(); + } else { + char in[64], out[330] = ""; + strncpy(in,f.latin1(),63); + char fch = format[pos+len].latin1(); + in[f.length()] = fch; + switch ( fch ) { + case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { + int value = va_arg(ap, int); + switch (params) { + case 0: ::sprintf( out, in, value ); break; + case 1: ::sprintf( out, in, width, value ); break; + case 2: ::sprintf( out, in, width, decimals, value ); break; + } + } break; + case 'e': case 'E': case 'f': case 'g': case 'G': { + double value = va_arg(ap, double); + switch (params) { + case 0: ::sprintf( out, in, value ); break; + case 1: ::sprintf( out, in, width, value ); break; + case 2: ::sprintf( out, in, width, decimals, value ); break; + } + } break; + case 'p': { + void* value = va_arg(ap, void*); + switch (params) { + case 0: ::sprintf( out, in, value ); break; + case 1: ::sprintf( out, in, width, value ); break; + case 2: ::sprintf( out, in, width, decimals, value ); break; + } + } break; + } + replacement = QString::fromLatin1(out); + } + result += replacement; + } + *this = result; + + va_end( ap ); + return *this; +} + +/*! + Fills the string with \a len characters of value \a c. + + If \a len is negative, the current string length is used. +*/ + +void QString::fill( QChar c, int len ) +{ + if ( len < 0 ) + len = length(); + if ( len == 0 ) { + *this = ""; + } else { + deref(); + QChar * nd = QT_ALLOC_QCHAR_VEC( len ); + d = new QStringData(nd,len,len); + while (len--) *nd++ = c; + } +} + + +/*! + \fn QString QString::copy() const + + \obsolete + + Returns a deep copy of this string. + + Doing this is redundant in Qt 2.x, since QString is implicitly + shared, and so will automatically be deeply copied as necessary. +*/ + +/*! + Finds the first occurrence of the character \a c, starting at + position \a index. If \a index is -1, the search starts at the + last character; if -2, at the next to last character; etc. + + The search is case sensitive if \a cs is TRUE, or case insensitive + if \a cs is FALSE. + + Returns the position of \a c, or -1 if \a c could not be found. +*/ + +int QString::find( QChar c, int index, bool cs ) const +{ + if ( index < 0 ) + index += length(); + if ( (uint)index >= length() ) // index outside string + return -1; + register const QChar *uc; + uc = unicode()+index; + int n = length()-index; + if ( cs ) { + while ( n-- && *uc != c ) + uc++; + } else { + c = c.lower(); + while ( n-- && uc->lower() != c ) + uc++; + } + if ( uint(uc - unicode()) >= length() ) + return -1; + return (int)(uc - unicode()); +} + +/*! + Finds the first occurrence of the string \a str, starting at position + \a index. If \a index is -1, the search starts at the last character; + if -2, at the next to last character; etc. + + The search is case sensitive if \a cs is TRUE, or case insensitive if + \a cs is FALSE. + + Returns the position of \a str, or -1 if \a str could not be found. +*/ + +int QString::find( const QString& str, int index, bool cs ) const +{ + /* + We use some weird hashing for efficiency's sake. Instead of + comparing strings, we compare the hash value of str with that of + a part of this QString. Only if that matches, we call ucstrncmp + or ucstrnicmp. + + The hash value of a string is the sum of the cells of its + QChars. + */ + if ( index < 0 ) + index += length(); + int lstr = str.length(); + int lthis = length() - index; + if ( (uint)lthis > length() ) + return -1; + int delta = lthis - lstr; + if ( delta < 0 ) + return -1; + + const QChar *uthis = unicode() + index; + const QChar *ustr = str.unicode(); + uint hthis = 0; + uint hstr = 0; + int i; + if ( cs ) { + for ( i = 0; i < lstr; i++ ) { + hthis += uthis[i].cell(); + hstr += ustr[i].cell(); + } + i = 0; + while ( TRUE ) { + if ( hthis == hstr && ucstrncmp(uthis + i, ustr, lstr) == 0 ) + return index + i; + if ( i == delta ) + return -1; + hthis += uthis[i + lstr].cell(); + hthis -= uthis[i].cell(); + i++; + } + } else { + for ( i = 0; i < lstr; i++ ) { + hthis += uthis[i].lower().cell(); + hstr += ustr[i].lower().cell(); + } + i = 0; + while ( TRUE ) { + if ( hthis == hstr && ucstrnicmp(uthis + i, ustr, lstr) == 0 ) + return index + i; + if ( i == delta ) + return -1; + hthis += uthis[i + lstr].lower().cell(); + hthis -= uthis[i].lower().cell(); + i++; + } + } +#if defined(Q_SPURIOUS_NON_VOID_WARNING) + return -1; +#endif +} + +/*! + \fn int QString::findRev( const char* str, int index ) const + + Equivalent to findRev(QString(str), index). +*/ + +/*! + \fn int QString::find( const char* str, int index ) const + + Equivalent to find(QString(str), index). +*/ + +/*! + Finds the first occurrence of the character \a c, starting at + position \a index and searching backwards. If \a index is -1, + the search starts at the last character; if -2, at the next to + last character; etc. + + The search is case sensitive if \a cs is TRUE, or case insensitive if \a + cs is FALSE. + + Returns the position of \a c, or -1 if \a c could not be found. +*/ + +int QString::findRev( QChar c, int index, bool cs ) const +{ + QString t( c ); + return findRev( t, index, cs ); +} + +/*! + Finds the first occurrence of the string \a str, starting at + position \a index and searching backwards. If \a index is -1, + the search starts at the last character; -2, at the next to last + character; etc. + + The search is case sensitive if \a cs is TRUE, or case insensitive if \e + cs is FALSE. + + Returns the position of \a str, or -1 if \a str could not be found. +*/ + +int QString::findRev( const QString& str, int index, bool cs ) const +{ + /* + See QString::find() for explanations. + */ + int lthis = length(); + if ( index < 0 ) + index += lthis; + + int lstr = str.length(); + int delta = lthis - lstr; + if ( index < 0 || index > lthis || delta < 0 ) + return -1; + if ( index > delta ) + index = delta; + + const QChar *uthis = unicode(); + const QChar *ustr = str.unicode(); + uint hthis = 0; + uint hstr = 0; + int i; + if ( cs ) { + for ( i = 0; i < lstr; i++ ) { + hthis += uthis[index + i].cell(); + hstr += ustr[i].cell(); + } + i = index; + while ( TRUE ) { + if ( hthis == hstr && ucstrncmp(uthis + i, ustr, lstr) == 0 ) + return i; + if ( i == 0 ) + return -1; + i--; + hthis -= uthis[i + lstr].cell(); + hthis += uthis[i].cell(); + } + } else { + for ( i = 0; i < lstr; i++ ) { + hthis += uthis[index + i].lower().cell(); + hstr += ustr[i].lower().cell(); + } + i = index; + while ( TRUE ) { + if ( hthis == hstr && ucstrnicmp(uthis + i, ustr, lstr) == 0 ) + return i; + if ( i == 0 ) + return -1; + i--; + hthis -= uthis[i + lstr].lower().cell(); + hthis += uthis[i].lower().cell(); + } + } +#if defined(Q_SPURIOUS_NON_VOID_WARNING) + return -1; +#endif +} + + +/*! + Returns the number of times the character \a c occurs in the string. + + The match is case sensitive if \a cs is TRUE, or case insensitive if \a cs + is FALSE. +*/ + +int QString::contains( QChar c, bool cs ) const +{ + int count = 0; + const QChar *uc = unicode(); + if ( !uc ) + return 0; + int n = length(); + if ( cs ) { // case sensitive + while ( n-- ) + if ( *uc++ == c ) + count++; + } else { // case insensitive + c = c.lower(); + while ( n-- ) { + if ( uc->lower() == c ) + count++; + uc++; + } + } + return count; +} + +/*! + \overload +*/ +int QString::contains( const char* str, bool cs ) const +{ + return contains(QString(str),cs); +} + +/*! + \overload int QString::contains (char c, bool cs) const +*/ + +/*! + \overload int QString::find (char c, int index, bool cs) const + +*/ + +/*! + \overload int QString::findRev (char c, int index, bool cs) const + +*/ + +/*! + Returns the number of times \a str occurs in the string. + + The match is case sensitive if \a cs is TRUE, or case insensitive if \e + cs is FALSE. + + This function counts overlapping substrings, for example, "banana" + contains two occurrences of "ana". + + \sa findRev() +*/ + +int QString::contains( const QString &str, bool cs ) const +{ + int count = 0; + const QChar *uc = unicode(); + if ( !uc ) + return 0; + int len = str.length(); + int n = length(); + while ( n-- ) { // counts overlapping strings + // ### Doesn't account for length of this - searches over "end" + if ( cs ) { + if ( ucstrncmp( uc, str.unicode(), len ) == 0 ) + count++; + } else { + if ( ucstrnicmp(uc, str.unicode(), len) == 0 ) + count++; + } + uc++; + } + return count; +} + +/*! + Returns a substring that contains the \a len leftmost characters + of the string. + + The whole string is returned if \a len exceeds the length of the + string. + + + Example: + \code + QString s = "Pineapple"; + QString t = s.left( 4 ); // t == "Pine" + \endcode + + \sa right(), mid(), isEmpty() +*/ + +QString QString::left( uint len ) const +{ + if ( isEmpty() ) { + return QString(); + } else if ( len == 0 ) { // ## just for 1.x compat: + return QString::fromLatin1(""); + } else if ( len > length() ) { + return *this; + } else { + QString s( len, TRUE ); + memcpy( s.d->unicode, d->unicode, len*sizeof(QChar) ); + s.d->len = len; + return s; + } +} + +/*! + Returns a substring that contains the \a len rightmost characters + of the string. + + The whole string is returned if \a len exceeds the length of the + string. + + Example: + \code + QString s = "Pineapple"; + QString t = s.right( 5 ); // t == "apple" + \endcode + + \sa left(), mid(), isEmpty() +*/ + +QString QString::right( uint len ) const +{ + if ( isEmpty() ) { + return QString(); + } else if ( len == 0 ) { // ## just for 1.x compat: + return QString::fromLatin1(""); + } else { + uint l = length(); + if ( len > l ) + len = l; + QString s( len, TRUE ); + memcpy( s.d->unicode, d->unicode+(l-len), len*sizeof(QChar) ); + s.d->len = len; + return s; + } +} + +/*! + Returns a substring that contains the \a len characters of this + string, starting at position \a index. + + Returns a null string if the string is empty or \a index is out + of range. Returns the whole string from \a index if \a index+len exceeds + the length of the string. + + Example: + \code + QString s = "Five pineapples"; + QString t = s.mid( 5, 4 ); // t == "pine" + \endcode + + \sa left(), right() +*/ + +QString QString::mid( uint index, uint len ) const +{ + uint slen = length(); + if ( isEmpty() || index >= slen ) { + return QString(); + } else if ( len == 0 ) { // ## just for 1.x compat: + return QString::fromLatin1(""); + } else { + if ( len > slen-index ) + len = slen - index; + if ( index == 0 && len == length() ) + return *this; + register const QChar *p = unicode()+index; + QString s( len, TRUE ); + memcpy( s.d->unicode, p, len*sizeof(QChar) ); + s.d->len = len; + return s; + } +} + +/*! + Returns a string of length \a width that contains this + string and padded by the \a fill character. + + If the length of the string exceeds \a width and \a truncate is FALSE, + then the returned string is a copy of the string. + If the length of the string exceeds \a width and \a truncate is TRUE, + then the returned string is a left(\a width). + + Example: + \code + QString s("apple"); + QString t = s.leftJustify(8, '.'); // t == "apple..." + \endcode + + \sa rightJustify() +*/ + +QString QString::leftJustify( uint width, QChar fill, bool truncate ) const +{ + QString result; + int len = length(); + int padlen = width - len; + if ( padlen > 0 ) { + result.setLength(len+padlen); + if ( len ) + memcpy( result.d->unicode, unicode(), sizeof(QChar)*len ); + QChar* uc = result.d->unicode + len; + while (padlen--) + *uc++ = fill; + } else { + if ( truncate ) + result = left( width ); + else + result = *this; + } + return result; +} + +/*! + Returns a string of length \a width that contains pad + characters followed by the string. + + If the length of the string exceeds \a width and \a truncate is FALSE, + then the returned string is a copy of the string. + If the length of the string exceeds \a width and \a truncate is TRUE, + then the returned string is a left(\a width). + + Example: + \code + QString s("pie"); + QString t = s.rightJustify(8, '.'); // t == ".....pie" + \endcode + + \sa leftJustify() +*/ + +QString QString::rightJustify( uint width, QChar fill, bool truncate ) const +{ + QString result; + int len = length(); + int padlen = width - len; + if ( padlen > 0 ) { + result.setLength( len+padlen ); + QChar* uc = result.d->unicode; + while (padlen--) + *uc++ = fill; + if ( len ) + memcpy( uc, unicode(), sizeof(QChar)*len ); + } else { + if ( truncate ) + result = left( width ); + else + result = *this; + } + return result; +} + +/*! + Returns a new string that is the string converted to lower case. + + Example: + \code + QString s("TeX"); + QString t = s.lower(); // t == "tex" + \endcode + + \sa upper() +*/ + +QString QString::lower() const +{ + QString s(*this); + int l=length(); + if ( l ) { + s.real_detach(); // could do this only when we find a change + register QChar *p=s.d->unicode; + if ( p ) { + while ( l-- ) { + *p = p->lower(); + p++; + } + } + } + return s; +} + +/*! + Returns a new string that is the string converted to upper case. + + Example: + \code + QString s("TeX"); + QString t = s.upper(); // t == "TEX" + \endcode + + \sa lower() +*/ + +QString QString::upper() const +{ + QString s(*this); + int l=length(); + if ( l ) { + s.real_detach(); // could do this only when we find a change + register QChar *p=s.d->unicode; + if ( p ) { + while ( l-- ) { + *p = p->upper(); + p++; + } + } + } + return s; +} + + +/*! + Returns a new string that has white space removed from the start and the end. + + White space means any character for which QChar::isSpace() returns + TRUE. This includes ASCII characters 9 (TAB), 10 (LF), 11 (VT), 12 + (FF), 13 (CR), and 32 (Space). + + Example: + \code + QString s = " space "; + QString t = s.stripWhiteSpace(); // t == "space" + \endcode + + \sa simplifyWhiteSpace() +*/ + +QString QString::stripWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + if ( !at(0).isSpace() && !at(length()-1).isSpace() ) + return *this; + + register const QChar *s = unicode(); + QString result = fromLatin1(""); + + int start = 0; + int end = length() - 1; + while ( start<=end && s[start].isSpace() ) // skip white space from start + start++; + if ( start > end ) { // only white space + return result; + } + while ( end && s[end].isSpace() ) // skip white space from end + end--; + int l = end - start + 1; + result.setLength( l ); + if ( l ) + memcpy( result.d->unicode, &s[start], sizeof(QChar)*l ); + return result; +} + + +/*! + Returns a new string that has white space removed from the start and the end, + plus any sequence of internal white space replaced with a single space + (ASCII 32). + + White space means any character for which QChar::isSpace() returns + TRUE. This includes ASCII characters 9 (TAB), 10 (LF), 11 (VT), 12 + (FF), 13 (CR), and 32 (Space). + + \code + QString s = " lots\t of\nwhite space "; + QString t = s.simplifyWhiteSpace(); // t == "lots of white space" + \endcode + + \sa stripWhiteSpace() +*/ + +QString QString::simplifyWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + QString result; + result.setLength( length() ); + const QChar *from = unicode(); + const QChar *fromend = from+length(); + int outc=0; + QChar *to = result.d->unicode; + while ( TRUE ) { + while ( from!=fromend && from->isSpace() ) + from++; + while ( from!=fromend && !from->isSpace() ) + to[outc++] = *from++; + if ( from!=fromend ) + to[outc++] = ' '; + else + break; + } + if ( outc > 0 && to[outc-1] == ' ' ) + outc--; + result.truncate( outc ); + return result; +} + + +/*! + Insert \a s into the string before position \a index. + + If \a index is beyond the end of the string, the string is extended with + spaces (ASCII 32) to length \a index and \a s is then appended. + + \code + QString s = "I like fish"; + s.insert( 2, "don't "); // s == "I don't like fish" + s = "x"; + s.insert( 3, "yz" ); // s == "x yz" + \endcode +*/ + +QString &QString::insert( uint index, const QString &s ) +{ + // the sub function takes care of &s == this case. + return insert( index, s.unicode(), s.length() ); +} + +/*! + Insert \a len units of QChar data from \a s into the string before + position \a index. +*/ + +QString &QString::insert( uint index, const QChar* s, uint len ) +{ + if ( len == 0 ) + return *this; + uint olen = length(); + int nlen = olen + len; + + int df = s - d->unicode; // ### pointer subtraction, cast down to int + if ( df >= 0 && (uint)df < d->maxl ) { + // Part of me - take a copy. + QChar *tmp = QT_ALLOC_QCHAR_VEC( len ); + memcpy(tmp,s,len*sizeof(QChar)); + insert(index,tmp,len); + QT_DELETE_QCHAR_VEC( tmp ); + return *this; + } + + if ( index >= olen ) { // insert after end of string + setLength( len+index ); + int n = index-olen; + QChar* uc = d->unicode+olen; + while (n--) + *uc++ = ' '; + memcpy( d->unicode+index, s, sizeof(QChar)*len ); + } else { // normal insert + setLength( nlen ); + memmove( d->unicode+index+len, unicode()+index, + sizeof(QChar)*(olen-index) ); + memcpy( d->unicode+index, s, sizeof(QChar)*len ); + } + return *this; +} + +/*! + Insert \a c into the string at (before) position \a index and returns + a reference to the string. + + If \a index is beyond the end of the string, the string is extended with + spaces (ASCII 32) to length \a index and \a c is then appended. + + Example: + \code + QString s = "Ys"; + s.insert( 1, 'e' ); // s == "Yes" + s.insert( 3, '!'); // s == "Yes!" + \endcode + + \sa remove(), replace() +*/ + +QString &QString::insert( uint index, QChar c ) // insert char +{ + QString s( c ); + return insert( index, s ); +} + +/*! + \overload QString& QString::insert( uint index, char c ) +*/ + +/*! + \fn QString &QString::prepend( const QString &s ) + + Prepend \a s to the string. Equivalent to insert(0,s). + + \sa insert() +*/ + +/*! + \fn QString& QString::prepend( char ch ) + Prepends \a ch to the string and returns a reference to the result. + + \sa insert() + */ + +/*! + \fn QString& QString::prepend( QChar ch ) + Prepends \a ch to the string and returns a reference to the result. + + \sa insert() + */ + + +/*! + Removes \a len characters starting at position \a index from the + string and returns a reference to the string. + + If \a index is too big, nothing happens. If \a index is valid, but + \a len is too large, the rest of the string is removed. + + \code + QString s = "Montreal"; + s.remove( 1, 4 ); + // s == "Meal" + \endcode + + \sa insert(), replace() +*/ + +QString &QString::remove( uint index, uint len ) +{ + uint olen = length(); + if ( index + len >= olen ) { // range problems + if ( index < olen ) { // index ok + setLength( index ); + } + } else if ( len != 0 ) { + real_detach(); + memmove( d->unicode+index, d->unicode+index+len, + sizeof(QChar)*(olen-index-len) ); + setLength( olen-len ); + } + return *this; +} + +/*! + Replaces \a len characters starting at position \a index from the + string with \a s, and returns a reference to the string. + + If \a index is too big, nothing is deleted and \a s is inserted at the + end of the string. If \a index is valid, but \a len is too large, \e + str replaces the rest of the string. + + \code + QString s = "Say yes!"; + s.replace( 4, 3, "NO" ); // s == "Say NO!" + \endcode + + \sa insert(), remove() +*/ + +QString &QString::replace( uint index, uint len, const QString &s ) +{ + return replace( index, len, s.unicode(), s.length() ); +} + + +/*! + Replaces \a len characters starting at position \a index by + \a slen units ot QChar data from \a s, and returns a reference to the string. + + \sa insert(), remove() +*/ + +QString &QString::replace( uint index, uint len, const QChar* s, uint slen ) +{ + if ( len == slen && index + len <= length() ) { + // Optimized common case: replace without size change + real_detach(); + memcpy( d->unicode+index, s, len*sizeof(QChar) ); + } else { + int df = s - d->unicode; // ### pointer subtraction, cast down to int + if ( df >= 0 && (uint)df < d->maxl ) { + // Part of me - take a copy. + QChar *tmp = QT_ALLOC_QCHAR_VEC( slen ); + memcpy(tmp,s,slen*sizeof(QChar)); + replace(index,len,tmp,slen); + QT_DELETE_QCHAR_VEC( tmp ); + return *this; + } + + remove( index, len ); + insert( index, s, slen ); + } + return *this; +} + + + +/*! + Finds the first occurrence of the regular expression \a rx, starting at + position \a index. If \a index is -1, the search starts at the last + character; if -2, at the next to last character; etc. + + Returns the position of the next match, or -1 if \a rx was not found. + + \sa findRev() replace() contains() +*/ + +int QString::find( const QRegExp &rx, int index ) const +{ + if ( index < 0 ) + index += length(); + return rx.match( *this, index ); +} + +/*! + Finds the first occurrence of the regular expression \a rx, starting at + position \a index and searching backwards. If \a index is -1, the + search starts at the last character; if -2, at the next to last + character; etc. + + Returns the position of the next match (backwards), or -1 if \a rx was not + found. + + \sa find() +*/ + +int QString::findRev( const QRegExp &rx, int index ) const +{ + if ( index < 0 ) // neg index ==> start from end + index += length(); + if ( (uint)index > length() ) // bad index + return -1; + while( index >= 0 ) { + if ( rx.match( *this, index ) == index ) + return index; + index--; + } + return -1; +} + +/*! + Counts the number of overlapping occurrences of \a rx in the string. + + Example: + \code + QString s = "banana and panama"; + QRegExp r = QRegExp("a[nm]a", TRUE, FALSE); + s.contains( r ); // 4 matches + \endcode + + \sa find() findRev() +*/ + +int QString::contains( const QRegExp &rx ) const +{ + if ( isEmpty() ) + return rx.match( *this ) < 0 ? 0 : 1; + int count = 0; + int index = -1; + int len = length(); + while ( index < len-1 ) { // count overlapping matches + index = rx.match( *this, index+1 ); + if ( index < 0 ) + break; + count++; + } + return count; +} + + +/*! + Replaces every occurrence of \a rx in the string with \a str. + Returns a reference to the string. + + Examples: + \code + QString s = "banana"; + s.replace( QRegExp("a.*a"), "" ); // becomes "b" + + QString s = "banana"; + s.replace( QRegExp("^[bn]a"), " " ); // becomes " nana" + + QString s = "banana"; + s.replace( QRegExp("^[bn]a"), "" ); // NOTE! becomes "" + \endcode + + \sa find() findRev() +*/ + +QString &QString::replace( const QRegExp &rx, const QString &str ) +{ + if ( isEmpty() ) + return *this; + int index = 0; + int slen = str.length(); + int len; + while ( index < (int)length() ) { + index = rx.match( *this, index, &len, FALSE ); + if ( index >= 0 ) { + replace( index, len, str ); + index += slen; + if ( !len ) + break; // Avoid infinite loop on 0-length matches, e.g. [a-z]* + } + else + break; + } + return *this; +} + +static bool +ok_in_base( QChar c, int base ) +{ + if ( base <= 10 ) + return c.isDigit() && c.digitValue() < base; + else + return c.isDigit() || (c >= 'a' && c < char('a'+base-10)) + || (c >= 'A' && c < char('A'+base-10)); +} + +/*! + Returns the string converted to a <code>long</code> value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, or if + it has trailing garbage. +*/ + +long QString::toLong( bool *ok, int base ) const +{ + const QChar *p = unicode(); + long val=0; + int l = length(); + const long max_mult = INT_MAX / base; + bool is_ok = FALSE; + int neg = 0; + if ( !p ) + goto bye; + while ( l && p->isSpace() ) // skip leading space + l--,p++; + if ( l && *p == '-' ) { + l--; + p++; + neg = 1; + } else if ( *p == '+' ) { + l--; + p++; + } + + // NOTE: toULong() code is similar + if ( !l || !ok_in_base(*p,base) ) + goto bye; + while ( l && ok_in_base(*p,base) ) { + l--; + int dv; + if ( p->isDigit() ) { + dv = p->digitValue(); + } else { + if ( *p >= 'a' && *p <= 'z' ) + dv = *p - 'a' + 10; + else + dv = *p - 'A' + 10; + } + if ( val > max_mult || (val == max_mult && dv > (INT_MAX%base)+neg) ) + goto bye; + val = base*val + dv; + p++; + } + if ( neg ) + val = -val; + while ( l && p->isSpace() ) // skip trailing space + l--,p++; + if ( !l ) + is_ok = TRUE; +bye: + if ( ok ) + *ok = is_ok; + return is_ok ? val : 0; +} + +/*! + Returns the string converted to an <code>unsigned long</code> + value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, + or if it has trailing garbage. +*/ + +ulong QString::toULong( bool *ok, int base ) const +{ + const QChar *p = unicode(); + ulong val=0; + int l = length(); + const ulong max_mult = 429496729; // UINT_MAX/10, rounded down + bool is_ok = FALSE; + if ( !p ) + goto bye; + while ( l && p->isSpace() ) // skip leading space + l--,p++; + if ( *p == '+' ) + l--,p++; + + // NOTE: toLong() code is similar + if ( !l || !ok_in_base(*p,base) ) + goto bye; + while ( l && ok_in_base(*p,base) ) { + l--; + uint dv; + if ( p->isDigit() ) { + dv = p->digitValue(); + } else { + if ( *p >= 'a' && *p <= 'z' ) + dv = *p - 'a' + 10; + else + dv = *p - 'A' + 10; + } + if ( val > max_mult || (val == max_mult && dv > (UINT_MAX%base)) ) + goto bye; + val = base*val + dv; + p++; + } + + while ( l && p->isSpace() ) // skip trailing space + l--,p++; + if ( !l ) + is_ok = TRUE; +bye: + if ( ok ) + *ok = is_ok; + return is_ok ? val : 0; +} + +/*! + Returns the string converted to a <code>short</code> value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, or if + it has trailing garbage. +*/ + +short QString::toShort( bool *ok, int base ) const +{ + long v = toLong( ok, base ); + if ( ok && *ok && (v < -32768 || v > 32767) ) { + *ok = FALSE; + v = 0; + } + return (short)v; +} + +/*! + Returns the string converted to an <code>unsigned short</code> value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, or if + it has trailing garbage. +*/ + +ushort QString::toUShort( bool *ok, int base ) const +{ + ulong v = toULong( ok, base ); + if ( ok && *ok && (v > 65535) ) { + *ok = FALSE; + v = 0; + } + return (ushort)v; +} + + +/*! + Returns the string converted to a <code>int</code> value. + + \code + QString str("FF"); + bool ok; + int hex = str.toInt( &ok, 16 ); // will return 255, and ok set to TRUE + int dec = str.toInt( &ok, 10 ); // will return 0, and ok set to FALSE + \endcode + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, + or if it has trailing garbage. +*/ + +int QString::toInt( bool *ok, int base ) const +{ + return (int)toLong( ok, base ); +} + +/*! + Returns the string converted to an <code>unsigned int</code> value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, + or if it has trailing garbage. +*/ + +uint QString::toUInt( bool *ok, int base ) const +{ + return (uint)toULong( ok, base ); +} + +/*! + Returns the string converted to a <code>double</code> value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no conceivable + errors, and FALSE if the string is not a number at all, or if it has + trailing garbage. +*/ + +double QString::toDouble( bool *ok ) const +{ + char *end; + + QCString a = latin1(); + // Just latin1() is not sufficient, since U0131 would look like '1'. + for (uint i=0; i<d->len; i++) + if ( d->unicode[i].row() ) + a[(int)i]='z'; + + double val = strtod( a.data() ? a.data() : "", &end ); + if ( ok ) + *ok = ( a && *a && ( end == 0 || *end == '\0' ) ); + return val; +} + +/*! + Returns the string converted to a <code>float</code> value. + + If \a ok is non-null, \a *ok is set to TRUE if there are no + conceivable errors, and FALSE if the string is not a number at all, + or if it has trailing garbage. +*/ + +float QString::toFloat( bool *ok ) const +{ + return (float)toDouble( ok ); +} + + +/*! + Sets the string to the printed value of \a n and returns a + reference to the string. + + The value is converted to \a base notation (default is decimal). + The base must be a value from 2 to 36. +*/ + +QString &QString::setNum( long n, int base ) +{ +#if defined(CHECK_RANGE) + if ( base < 2 || base > 36 ) { + qWarning( "QString::setNum: Invalid base %d", base ); + base = 10; + } +#endif + char charbuf[65*sizeof(QChar)]; + QChar *buf = (QChar*)charbuf; + QChar *p = &buf[64]; + int len = 0; + bool neg; + if ( n < 0 ) { + neg = TRUE; + if ( n == INT_MIN ) { + // Cannot always negate this special case + QString s1, s2; + s1.setNum(n/base); + s2.setNum((-(n+base))%base); + *this = s1 + s2; + return *this; + } + n = -n; + } else { + neg = FALSE; + } + do { + *--p = "0123456789abcdefghijklmnopqrstuvwxyz"[((int)(n%base))]; + n /= base; + len++; + } while ( n ); + if ( neg ) { + *--p = '-'; + len++; + } + return setUnicode( p, len ); +} + +/*! + Sets the string to the printed unsigned value of \a n and + returns a reference to the string. + + The value is converted to \a base notation (default is decimal). + The base must be a value from 2 to 36. +*/ + +QString &QString::setNum( ulong n, int base ) +{ +#if defined(CHECK_RANGE) + if ( base < 2 || base > 36 ) { + qWarning( "QString::setNum: Invalid base %d", base ); + base = 10; + } +#endif + char charbuf[65*sizeof(QChar)]; + QChar *buf = (QChar*)charbuf; + QChar *p = &buf[64]; + int len = 0; + do { + *--p = "0123456789abcdefghijklmnopqrstuvwxyz"[((int)(n%base))]; + n /= base; + len++; + } while ( n ); + return setUnicode(p,len); +} + +/*! + \fn QString &QString::setNum( int n, int base ) + Sets the string to the printed value of \a n and returns a reference + to the string. +*/ + +/*! + \fn QString &QString::setNum( uint n, int base ) + Sets the string to the printed unsigned value of \a n and returns a + reference to the string. +*/ + +/*! + \fn QString &QString::setNum( short n, int base ) + Sets the string to the printed value of \a n and returns a reference + to the string. +*/ + +/*! + \fn QString &QString::setNum( ushort n, int base ) + Sets the string to the printed unsigned value of \a n and returns a + reference to the string. +*/ + +/*! Sets the string to the printed value of \a n, formatted in the \a f + format with \a prec precision, and returns a reference to the + string. + + \a f can be 'f', 'F', 'e', 'E', 'g' or 'G', all of which have the + same meaning as for sprintf(). +*/ + +QString &QString::setNum( double n, char f, int prec ) +{ +#if defined(CHECK_RANGE) + if ( !(f=='f' || f=='F' || f=='e' || f=='E' || f=='g' || f=='G') ) { + qWarning( "QString::setNum: Invalid format char '%c'", f ); + f = 'f'; + } +#endif + char format[20]; + char buf[120]; // enough for 99 precision? + char *fs = format; // generate format string + *fs++ = '%'; // "%.<prec>l<f>" + if ( prec >= 0 ) { + if ( prec > 99 ) // buf big enough for precision? + prec = 99; + *fs++ = '.'; + if ( prec >= 10 ) { + *fs++ = prec / 10 + '0'; + *fs++ = prec % 10 + '0'; + } else { + *fs++ = prec + '0'; + } + } + *fs++ = 'l'; + *fs++ = f; + *fs = '\0'; + ::sprintf( buf, format, n ); + return setLatin1(buf); +} + +/*! + \overload QString &QString::setNum( float n, char f, int prec ) +*/ + + +/*! + A convenience factory function that returns a string representation + of the number \a n. + + \sa setNum() + */ +QString QString::number( long n, int base ) +{ + QString s; + s.setNum( n, base ); + return s; +} + +/*! + A convenience factory function that returns a string representation + of the number \a n. + + \sa setNum() + */ +QString QString::number( ulong n, int base ) +{ + QString s; + s.setNum( n, base ); + return s; +} + +/*! + A convenience factory function that returns a string representation + of the number \a n. + + \sa setNum() + */ +QString QString::number( int n, int base ) +{ + QString s; + s.setNum( n, base ); + return s; +} + +/*! + A convenience factory function that returns a string representation + of the number \a n. + + \sa setNum() + */ +QString QString::number( uint n, int base ) +{ + QString s; + s.setNum( n, base ); + return s; +} + +/*! + This static function returns the printed value of \a n, formatted in the + \a f format with \a prec precision. + + \a f can be 'f', 'F', 'e', 'E', 'g' or 'G', all of which have the + same meaning as for sprintf(). + + \sa setNum() + */ +QString QString::number( double n, char f, int prec ) +{ + QString s; + s.setNum( n, f, prec ); + return s; +} + + +/*! \obsolete + + Sets the character at position \a index to \a c and expands the + string if necessary, filling with spaces. + + This method is redundant in Qt 2.x, because operator[] will expand + the string as necessary. +*/ + +void QString::setExpand( uint index, QChar c ) +{ + int spaces = index - d->len; + at(index) = c; + while (spaces-->0) + d->unicode[--index]=' '; +} + + +/*! + \fn const char* QString::data() const + + \obsolete + + Returns a pointer to a 0-terminated classic C string. + + In Qt 1.x, this returned a char* allowing direct manipulation of the + string as a sequence of bytes. In Qt 2.x where QString is a Unicode + string, char* conversion constructs a temporary string, and hence + direct character operations are meaningless. +*/ + +/*! + \fn bool QString::operator!() const + Returns TRUE if it is a null string, otherwise FALSE. Thus + you can write: + +\code + QString name = getName(); + if ( !name ) + name = "Rodney"; +\endcode + + Note that if you say: + +\code + QString name = getName(); + if ( name ) + doSomethingWith(name); +\endcode + + Then this will call <tt>operator const char*()</tt>, which will do what + you want, but rather inefficiently - you may wish to define the macro + QT_NO_ASCII_CAST when writing code which you wish to strictly remain + Unicode-clean. + + When you want the above semantics, use <tt>!isNull()</tt> + or even <tt>!!</tt>: + +\code + QString name = getName(); + if ( !!name ) + doSomethingWith(name); +\endcode +*/ + + +/*! + \fn QString& QString::append( const QString& str ) + Appends \a str to the string and returns a reference to the result. + Equivalent to operator+=(). + */ + +/*! + \fn QString& QString::append( char ch ) + Appends \a ch to the string and returns a reference to the result. + Equivalent to operator+=(). + */ + +/*! + \fn QString& QString::append( QChar ch ) + Appends \a ch to the string and returns a reference to the result. + Equivalent to operator+=(). + */ + +/*! + Appends \a str to the string and returns a reference to the string. +*/ +QString& QString::operator+=( const QString &str ) +{ + uint len1 = length(); + uint len2 = str.length(); + if ( len2 ) { + setLength(len1+len2); + memcpy( d->unicode+len1, str.unicode(), sizeof(QChar)*len2 ); + } else if ( isNull() && !str.isNull() ) { // ## just for 1.x compat: + *this = fromLatin1(""); + } + return *this; +} + +/*! + Appends \a c to the string and returns a reference to the string. +*/ + +QString &QString::operator+=( QChar c ) +{ + setLength(length()+1); + d->unicode[length()-1] = c; + return *this; +} + +/*! + Appends \a c to the string and returns a reference to the string. +*/ + +QString &QString::operator+=( char c ) +{ + setLength(length()+1); + d->unicode[length()-1] = c; + return *this; +} + + + +/*! \fn char QChar::latin1() const + + Returns a latin-1 copy of this character, if this character is in + the latin-1 character set. If not, this function returns 0. +*/ + + +/*! + Returns a Latin-1 representation of the string. Note that the returned + value is undefined if the string contains non-Latin-1 characters. If you + want to convert strings into formats other than Unicode, see the + QTextCodec classes. + + This function is mainly useful for boot-strapping legacy code to + use Unicode. + + The result remains valid so long as one unmodified + copy of the source string exists. + + \sa utf8(), local8Bit() +*/ +const char* QString::latin1() const +{ + if ( d->ascii ) { + if ( d->dirtyascii ) + delete [] d->ascii; + else + return d->ascii; + } + Q2HELPER(stat_get_ascii++) + Q2HELPER(stat_get_ascii_size+=d->len) + d->ascii = unicodeToAscii( d->unicode, d->len ); + d->dirtyascii = 0; + return d->ascii; +} + +/*! \obsolete + + This functions simply calls latin1() and returns the result. +*/ +const char* QString::ascii() const +{ + return latin1(); +} + +#ifndef QT_NO_TEXTCODEC +/*! + Returns the string encoded in UTF8 format. + + See QTextCodec for more diverse coding/decoding of Unicode strings. + + \sa QString::fromUtf8(), local8Bit(), latin1() +*/ +QCString QString::utf8() const +{ + static QTextCodec* codec = QTextCodec::codecForMib(106); + return codec + ? codec->fromUnicode(*this) + : QCString(latin1()); +} + +/*! + Returns the unicode string decoded from the + first \a len bytes of \a utf8. If \a len is -1 (the default), the + length of \a utf8 is used. If trailing partial characters are in + \a utf8, they are ignored. + + See QTextCodec for more diverse coding/decoding of Unicode strings. +*/ +QString QString::fromUtf8(const char* utf8, int len) +{ + static QTextCodec* codec = QTextCodec::codecForMib(106); + if ( len < 0 ) len = qstrlen(utf8); + return codec + ? codec->toUnicode(utf8, len) + : QString::fromLatin1(utf8, len); +} +#endif // QT_NO_TEXTCODEC +/*! + Creates a QString from Latin1 text. This is the same as the + QString(const char*) constructor, but you can make that constructor + invisible if you compile with the define QT_NO_CAST_ASCII, in which + case you can explicitly create a QString from Latin-1 text using + this function. +*/ +QString QString::fromLatin1(const char* chars, int len) +{ + uint l; + QChar *uc; + if ( len < 0 ) { + uc = internalAsciiToUnicode(chars,&l); + } else { + uc = internalAsciiToUnicode(chars,&l,len); + } + return QString(new QStringData(uc,l,l), TRUE); +} + +/*! + \fn const QChar* QString::unicode() const + + Returns the Unicode representation of the string. The result + remains valid until the string is modified. +*/ + +/*! + Returns the string encoded in a locale-specific format. On X11, this + is the QTextCodec::codecForLocale(). On Windows, it is a system-defined + encoding. + + See QTextCodec for more diverse coding/decoding of Unicode strings. + + \sa QString::fromLocal8Bit(), latin1(), utf8() +*/ + + +QCString QString::local8Bit() const +{ +#ifdef QT_NO_TEXTCODEC + return latin1(); +#else +#ifdef _WS_X11_ + static QTextCodec* codec = QTextCodec::codecForLocale(); + return codec + ? codec->fromUnicode(*this) + : QCString(latin1()); +#endif +#ifdef _WS_MAC_ + static QTextCodec* codec = QTextCodec::codecForLocale(); + return codec + ? codec->fromUnicode(*this) + : QCString(latin1()); +#endif +#ifdef _WS_WIN_ + return qt_winQString2MB( *this ); +#endif +#ifdef _WS_QWS_ + return utf8(); // ##### if there is ANY 8 bit format supported? +#endif +#endif +} + +/*! + Returns the unicode string decoded from the + first \a len bytes of \a local8Bit. If \a len is -1 (the default), the + length of \a local8Bit is used. If trailing partial characters are in + \a local8Bit, they are ignored. + + \a local8Bit is assumed to be encoded in a locale-specific format. + + See QTextCodec for more diverse coding/decoding of Unicode strings. +*/ +QString QString::fromLocal8Bit(const char* local8Bit, int len) +{ +#ifdef QT_NO_TEXTCODEC + return fromLatin1( local8Bit, len ); +#else + + if ( !local8Bit ) + return QString::null; +#ifdef _WS_X11_ + static QTextCodec* codec = QTextCodec::codecForLocale(); + if ( len < 0 ) len = qstrlen(local8Bit); + return codec + ? codec->toUnicode(local8Bit, len) + : QString::fromLatin1(local8Bit,len); +#endif +#ifdef _WS_MAC_ + static QTextCodec* codec = QTextCodec::codecForLocale(); + if ( len < 0 ) len = qstrlen(local8Bit); + return codec + ? codec->toUnicode(local8Bit, len) + : QString::fromLatin1(local8Bit,len); +#endif +// Should this be OS_WIN32? +#ifdef _WS_WIN_ + if ( len >= 0 ) { + QCString s(local8Bit,len+1); + return qt_winMB2QString(s); + } + return qt_winMB2QString( local8Bit ); +#endif +#ifdef _WS_QWS_ + return fromUtf8(local8Bit,len); +#endif +#endif // QT_NO_TEXTCODEC +} + +/*! + \fn QString::operator const char *() const + + Returns latin1(). Be sure to see the warnings documented there. + Note that for new code which you wish to be strictly Unicode-clean, + you can define the macro QT_NO_ASCII_CAST when compiling your code + to hide this function so that automatic casts are not done. This + has the added advantage that you catch the programming error + described under operator!(). +*/ + +/*! + \fn QChar QString::at( uint ) const + + Returns the character at \a i, or 0 if \a i is beyond the length + of the string. + + Note: If this QString is not const or const&, the non-const at() + will be used instead, which will expand the string if \a i is beyond + the length of the string. +*/ + +/*! + \fn QChar QString::constref(uint i) const + Equivalent to at(i), this returns the QChar at \a i by value. + + \sa ref() +*/ + +/*! + \fn QChar& QString::ref(uint i) + Returns the QChar at \a i by reference. + + \sa constref() +*/ + +/*! + \fn QChar QString::operator[](int) const + + Returns the character at \a i, or QChar::null if \a i is beyond the + length of the string. + + Note: If this QString is not const or const&, the non-const operator[] + will be used instead, which will expand the string if \a i is beyond + the length of the string. +*/ + +/*! + \fn QCharRef QString::operator[](int) + + Returns an object that references the character at \a i. + This reference + can then be assigned to, or otherwise used immediately, but + becomes invalid once further modifications are made to the string. + The QCharRef internal class can be used much like a constant QChar, but + if you assign to it, you change the original string (which enlarges + and detaches itself). You will get compilation errors if you try to + use the result as anything but a QChar. +*/ + +/*! + \fn QCharRef QString::at( uint i ) + Returns a reference to the character at \a i, expanding + the string with QChar::null if necessary. The resulting reference + can then be assigned to, or otherwise used immediately, but + becomes invalid once further modifications are made to the string. +*/ + +/*! + Internal chunk of code to handle the + uncommon cases of at() above. +*/ +void QString::subat( uint i ) +{ + uint olen = d->len; + if ( i >= olen ) { + setLength( i+1 ); // i is index; i+1 is needed length + for ( uint j=olen; j<=i; j++ ) + d->unicode[j] = QChar::null; + } else { + // Just be sure to detach + real_detach(); + } +} + + +/*! + Resizes the string to \a len unicode characters and copies \a unicode + into the string. If \a unicode is null, nothing is copied, but the + string is resized to \a len anyway. If \a len is zero, the string + becomes a \link isNull() null\endlink string. + + \sa setLatin1(), isNull() +*/ + +QString& QString::setUnicode( const QChar *unicode, uint len ) +{ + if ( len == 0 ) { // set to null string + if ( d != shared_null ) { // beware of nullstring being set to nullstring + deref(); + d = shared_null ? shared_null : makeSharedNull(); + d->ref(); + } + } else if ( d->count != 1 || len > d->maxl || + ( len*4 < d->maxl && d->maxl > 4 ) ) { // detach, grown or shrink + Q2HELPER(stat_copy_on_write++) + Q2HELPER(stat_copy_on_write_size+=d->len) + uint newMax = 4; + while ( newMax < len ) + newMax *= 2; + QChar* nd = QT_ALLOC_QCHAR_VEC( newMax ); + if ( unicode ) + memcpy( nd, unicode, sizeof(QChar)*len ); + deref(); + d = new QStringData( nd, len, newMax ); + } else { + d->len = len; + d->dirtyascii = 1; + if ( unicode ) + memcpy( d->unicode, unicode, sizeof(QChar)*len ); + } + return *this; +} + +/*! + Resizes the string to \a len unicode characters and copies + \a unicode_as_ushorts into the string (on some X11 client + platforms this will involve a byte-swapping pass). + + If \a unicode is null, nothing is copied, but the + string is resized to \a len anyway. If \a len is zero, the string + becomes a \link isNull() null\endlink string. + + \sa setLatin1(), isNull() +*/ +QString& QString::setUnicodeCodes( const ushort* unicode_as_ushorts, uint len ) +{ + setUnicode((const QChar*)unicode_as_ushorts, len); + QChar t(0x1234); + if ( unicode_as_ushorts && *((ushort*)&t) == 0x3412 ) { + // Need to byteswap + char* b = (char*)d->unicode; + while ( len-- ) { + char c = b[0]; + b[0] = b[1]; + b[1] = c; + b += sizeof(QChar); + } + } + return *this; +} + + +/*! + Sets this string to \a str, interpreted as a classic Latin 1 C string. + If the \a len argument is negative (default), it is set to strlen(str). + + If \a str is 0 a null string is created. If \a str is "" an empty + string is created. + + \sa isNull(), isEmpty() +*/ + +QString &QString::setLatin1( const char *str, int len ) +{ + if ( str == 0 ) + return setUnicode(0,0); + if ( len < 0 ) + len = qstrlen(str); + if ( len == 0 ) { // won't make a null string + deref(); + uint l; + QChar *uc = internalAsciiToUnicode(str,&l); + d = new QStringData(uc,l,l); + } else { + setUnicode( 0, len ); // resize but not copy + QChar *p = d->unicode; + while ( len-- ) + *p++ = *str++; + } + return *this; +} + + +/*! + \fn int QString::compare (const QString & s1, const QString & s2) + + Compare \a s1 to \a s2 returning an integer less than, equal to, or + greater than zero if s1 is, respectively, lexically less than, equal to, + or greater than s2. +*/ + +/*! + Compares this string to \a s, returning an integer less than, equal to, or + greater than zero if it is, respectively, lexically less than, equal to, + or greater than \a s. +*/ +int QString::compare( const QString& s ) const +{ + return ucstrcmp(*this,s); +} + +bool operator==( const QString &s1, const QString &s2 ) +{ + return (s1.length() == s2.length()) && s1.isNull() == s2.isNull() && + (memcmp((char*)s1.unicode(),(char*)s2.unicode(), + s1.length()*sizeof(QChar)) ==0); +} + +bool operator!=( const QString &s1, const QString &s2 ) +{ return !(s1==s2); } + +bool operator<( const QString &s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) < 0; } + +bool operator<=( const QString &s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) <= 0; } + +bool operator>( const QString &s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) > 0; } + +bool operator>=( const QString &s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) >= 0; } + + +bool operator==( const QString &s1, const char *s2 ) +{ return s1==QString(s2); } + +bool operator==( const char *s1, const QString &s2 ) +{ return QString(s1)==s2; } + +bool operator!=( const QString &s1, const char *s2 ) +{ return !(s1==s2); } + +bool operator!=( const char *s1, const QString &s2 ) +{ return !(s1==s2); } + +bool operator<( const QString &s1, const char *s2 ) +{ return ucstrcmp(s1,s2) < 0; } + +bool operator<( const char *s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) < 0; } + +bool operator<=( const QString &s1, const char *s2 ) +{ return ucstrcmp(s1,s2) <= 0; } + +bool operator<=( const char *s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) <= 0; } + +bool operator>( const QString &s1, const char *s2 ) +{ return ucstrcmp(s1,s2) > 0; } + +bool operator>( const char *s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) > 0; } + +bool operator>=( const QString &s1, const char *s2 ) +{ return ucstrcmp(s1,s2) >= 0; } + +bool operator>=( const char *s1, const QString &s2 ) +{ return ucstrcmp(s1,s2) >= 0; } + + +/***************************************************************************** + Documentation for QString related functions + *****************************************************************************/ + +/*! + \fn bool operator==( const QString &s1, const QString &s2 ) + \relates QString + Returns TRUE if the two strings are equal, or FALSE if they are different. + A null string is different from an empty, non-null string. + + Equivalent to <code>qstrcmp(s1,s2) == 0</code>. +*/ + +/*! + \fn bool operator==( const QString &s1, const char *s2 ) + \relates QString + Returns TRUE if the two strings are equal, or FALSE if they are different. + + Equivalent to <code>qstrcmp(s1,s2) == 0</code>. +*/ + +/*! + \fn bool operator==( const char *s1, const QString &s2 ) + \relates QString + Returns TRUE if the two strings are equal, or FALSE if they are different. + + Equivalent to <code>qstrcmp(s1,s2) == 0</code>. +*/ + +/*! + \fn bool operator!=( const QString &s1, const QString &s2 ) + \relates QString + Returns TRUE if the two strings are different, or FALSE if they are equal. + + Equivalent to <code>qstrcmp(s1,s2) != 0</code>. +*/ + +/*! + \fn bool operator!=( const QString &s1, const char *s2 ) + \relates QString + Returns TRUE if the two strings are different, or FALSE if they are equal. + + Equivalent to <code>qstrcmp(s1,s2) != 0</code>. +*/ + +/*! + \fn bool operator!=( const char *s1, const QString &s2 ) + \relates QString + Returns TRUE if the two strings are different, or FALSE if they are equal. + + Equivalent to <code>qstrcmp(s1,s2) != 0</code>. +*/ + +/*! + \fn bool operator<( const QString &s1, const char *s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically less than \a s2, otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \< 0</code>. +*/ + +/*! + \fn bool operator<( const char *s1, const QString &s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically less than \a s2, otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \< 0</code>. +*/ + +/*! + \fn bool operator<=( const QString &s1, const char *s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically less than or equal to \a s2, + otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \<= 0</code>. +*/ + +/*! + \fn bool operator<=( const char *s1, const QString &s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically less than or equal to \a s2, + otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \<= 0</code>. +*/ + +/*! + \fn bool operator>( const QString &s1, const char *s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically greater than \a s2, otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \> 0</code>. +*/ + +/*! + \fn bool operator>( const char *s1, const QString &s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically greater than \a s2, otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \> 0</code>. +*/ + +/*! + \fn bool operator>=( const QString &s1, const char *s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically greater than or equal to \a s2, + otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \>= 0</code>. +*/ + +/*! + \fn bool operator>=( const char *s1, const QString &s2 ) + \relates QString + Returns TRUE if \a s1 is alphabetically greater than or equal to \a s2, + otherwise FALSE. + + Equivalent to <code>qstrcmp(s1,s2) \>= 0</code>. +*/ + +/*! + \fn QString operator+( const QString &s1, const QString &s2 ) + \relates QString + Returns the concatenated string of s1 and s2. +*/ + +/*! + \fn QString operator+( const QString &s1, const char *s2 ) + \relates QString + Returns the concatenated string of s1 and s2. +*/ + +/*! + \fn QString operator+( const char *s1, const QString &s2 ) + \relates QString + Returns the concatenated string of s1 and s2. +*/ + +/*! + \fn QString operator+( const QString &s, char c ) + \relates QString + Returns the concatenated string of s and c. +*/ + +/*! + \fn QString operator+( char c, const QString &s ) + \relates QString + Returns the concatenated string of c and s. +*/ + + +/***************************************************************************** + QString stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +/*! + \relates QString + Writes a string to the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator<<( QDataStream &s, const QString &str ) +{ + if ( s.version() == 1 ) { + QCString l( str.latin1() ); + s << l; + } + else { + const char* ub = (const char*)str.unicode(); + if ( ub || s.version() < 3 ) { + if ( QChar::networkOrdered() == + (s.byteOrder()==QDataStream::BigEndian) ) { + s.writeBytes( ub, sizeof(QChar)*str.length() ); + } else { + static const uint auto_size = 1024; + char t[auto_size]; + char *b; + if ( str.length()*sizeof(QChar) > auto_size ) { + b = new char[str.length()*sizeof(QChar)]; + } else { + b = t; + } + int l = str.length(); + char *c=b; + while ( l-- ) { + *c++ = ub[1]; + *c++ = ub[0]; + ub+=sizeof(QChar); + } + s.writeBytes( b, sizeof(QChar)*str.length() ); + if ( str.length()*sizeof(QChar) > auto_size ) + delete [] b; + } + } else { + // write null marker + s << (Q_UINT32)0xffffffff; + } + } + return s; +} + +/*! + \relates QString + Reads a string from the stream. + + \sa \link datastreamformat.html Format of the QDataStream operators \endlink +*/ + +QDataStream &operator>>( QDataStream &s, QString &str ) +{ +#ifdef QT_QSTRING_UCS_4 +#if defined(_CC_GNU_) +#warning "operator>> not working properly" +#endif +#endif + if ( s.version() == 1 ) { + QCString l; + s >> l; + str = QString( l ); + } + else { + Q_UINT32 bytes; + s >> bytes; // read size of string + if ( bytes == 0xffffffff ) { // null string + str = QString::null; + } else if ( bytes > 0 ) { // not empty + str.setLength( bytes/2 ); + char* b = (char*)str.d->unicode; + s.readRawBytes( b, bytes ); + if ( QChar::networkOrdered() != + (s.byteOrder()==QDataStream::BigEndian) ) { + bytes /= 2; + while ( bytes-- ) { + char c = b[0]; + b[0] = b[1]; + b[1] = c; + b += 2; + } + } + } else { + str = ""; + } + } + return s; +} +#endif // QT_NO_DATASTREAM + +/***************************************************************************** + QConstString member functions + *****************************************************************************/ + +/*! + \class QConstString qstring.h + \brief A QString which uses constant Unicode data. + + In order to minimize copying, highly optimized applications can use + QConstString to provide a QString-compatible object from existing + Unicode data. It is then the user's responsibility to make sure + that the Unicode data must exist for the entire lifetime of the + QConstString object. +*/ + +/*! + Constructs a QConstString that uses the first \a length Unicode + characters in the array \a unicode. Any attempt to modify + copies of the string will cause it to create a copy of the + data, thus it remains forever unmodified. + + Note that \a unicode is \e not \e copied. The caller \e must be + able to guarantee that \a unicode will not be deleted or + modified. Since that is generally not the case with \c const strings + (they are references), this constructor demands a non-const pointer + even though it never modifies \a unicode. +*/ +QConstString::QConstString( QChar* unicode, uint length ) : + QString(new QStringData(unicode, length, length),TRUE) +{ +} + +/*! + Destroys the QConstString, creating a copy of the data if + other strings are still using it. +*/ +QConstString::~QConstString() +{ + if ( d->count > 1 ) { + QChar* cp = QT_ALLOC_QCHAR_VEC( d->len ); + memcpy( cp, d->unicode, d->len*sizeof(QChar) ); + d->unicode = cp; + } else { + d->unicode = 0; + } + + // The original d->unicode is now unlinked. +} + +/*! + \fn const QString& QConstString::string() const + + Returns a constant string referencing the data passed during + construction. +*/ + +/*! + Returns whether the strings starts with \a s, or not. + */ +bool QString::startsWith( const QString& s ) const +{ + for ( int i =0; i < (int) s.length(); i++ ) { + if ( i >= (int) length() || d->unicode[i] != s[i] ) + return FALSE; + } + return TRUE; +} + + + +#if defined(_OS_WIN32_) + +#include <windows.h> + +/*! + Returns a static Windows TCHAR* from a QString, possibly adding NUL. + + The lifetime of the return value is until the next call to this function. +*/ +const void* qt_winTchar(const QString& str_in, bool addnul) +{ + // So that the return value lives long enough. + static QString str; + str = str_in; + +#ifdef UNICODE + static uint buflen = 256; + static TCHAR *buf = new TCHAR[buflen]; + + const QChar* uc = str.unicode(); + +#define EXTEND if (str.length() > buflen) { delete buf; buf = new TCHAR[buflen=str.length()+1]; } + +#if defined(_WS_X11_) || defined(_OS_WIN32_BYTESWAP_) + EXTEND + for ( int i=str.length(); i--; ) + buf[i] = uc[i].row() << 8 | uc[i].cell(); + if ( addnul ) + buf[str.length()] = 0; +#else + // Same endianness of TCHAR + if ( addnul ) { + EXTEND + memcpy(buf,uc,sizeof(TCHAR)*str.length()); + buf[str.length()] = 0; + } else { + return uc; + } +#endif + return buf; +#undef EXTEND + +#else + return str.latin1(); +#endif +} + +/*! + Makes a new null terminated Windows TCHAR* from a QString. +*/ +void* qt_winTchar_new(const QString& str) +{ + TCHAR* result = new TCHAR[str.length()+1]; + memcpy(result, qt_winTchar(str,FALSE), sizeof(TCHAR)*str.length()); + result[str.length()] = 0; + return result; +} + +/*! + Makes a QString from a Windows TCHAR*. +*/ +QString qt_winQString(void* tc) +{ +#ifdef UNICODE + + int len=0; + while ( ((TCHAR*)tc)[len] ) + len++; +#if defined(_WS_X11_) || defined(_OS_WIN32_BYTESWAP_) + QString r; + for ( int i=0; i<len; i++ ) + r += QChar(((TCHAR*)tc)[i]&0xff,((TCHAR*)tc)[i]>>8); + return r; +#else + // Same endianness of TCHAR + return QString((QChar*)tc,len); +#endif +#undef EXTEND +#else + return (TCHAR*)tc; +#endif +} + +QCString qt_winQString2MB( const QString& s, int uclen ) +{ + if ( uclen < 0 ) + uclen = s.length(); + if ( uclen == 0 ) + return QCString(); + BOOL used_def; + int bufSize=4096; + QCString mb(bufSize); + int len; + while ( !(len=WideCharToMultiByte(CP_ACP, 0, (const WCHAR*)s.unicode(), uclen, + mb.data(), bufSize-1, 0, &used_def)) ) + { + int r = GetLastError(); + if ( r == ERROR_INSUFFICIENT_BUFFER ) { + bufSize=1+WideCharToMultiByte( CP_ACP, 0, + (const WCHAR*)s.unicode(), uclen, + 0, 0, 0, &used_def); + mb.resize(bufSize); + // and try again... + } else { + // Fail. + qWarning("WideCharToMultiByte cannot convert multibyte text (error %d): %s (UTF8)", + r, s.utf8().data()); + break; + } + } + mb[len]='\0'; + return mb; +} + +// WATCH OUT: mblen must include the NUL (or just use -1) +QString qt_winMB2QString( const char* mb, int mblen ) +{ + if ( !mb || !mblen ) + return QString::null; + const int wclen_auto = 4096; + WCHAR wc_auto[wclen_auto]; + int wclen = wclen_auto; + WCHAR *wc = wc_auto; + int len; + while ( !(len=MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, + mb, mblen, wc, wclen )) ) + { + int r = GetLastError(); + if ( r == ERROR_INSUFFICIENT_BUFFER ) { + if ( wc != wc_auto ) { + qWarning("Size changed in MultiByteToWideChar"); + break; + } else { + wclen = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, + mb, mblen, 0, 0 ); + wc = new WCHAR[wclen]; + // and try again... + } + } else { + // Fail. + qWarning("MultiByteToWideChar cannot convert multibyte text"); + break; + } + } + if ( len <= 0 ) + return QString::null; + QString s( (QChar*)wc, len-1 ); // len-1: we don't want terminator + if ( wc != wc_auto ) + delete [] wc; + return s; +} + + +#endif // _OS_WIN32_ diff --git a/trunk/qtools/qstring.h b/trunk/qtools/qstring.h new file mode 100644 index 0000000..c64d756 --- /dev/null +++ b/trunk/qtools/qstring.h @@ -0,0 +1,825 @@ +/**************************************************************************** +** +** +** Definition of the QString class, and related Unicode +** functions. +** +** Created : 920609 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSTRING_H +#define QSTRING_H + +#ifndef QT_H +#include "qcstring.h" +#endif // QT_H + + +/***************************************************************************** + QString class + *****************************************************************************/ + +class QRegExp; +class QString; +class QCharRef; + +class Q_EXPORT Q_PACKED QChar { +public: + QChar(); + QChar( char c ); + QChar( uchar c ); + QChar( uchar c, uchar r ); + QChar( const QChar& c ); + QChar( ushort rc ); + QChar( short rc ); + QChar( uint rc ); + QChar( int rc ); + + QT_STATIC_CONST QChar null; // 0000 + QT_STATIC_CONST QChar replacement; // FFFD + QT_STATIC_CONST QChar byteOrderMark; // FEFF + QT_STATIC_CONST QChar byteOrderSwapped; // FFFE + QT_STATIC_CONST QChar nbsp; // 00A0 + + // Unicode information + + enum Category + { + NoCategory, + + Mark_NonSpacing, // Mn + Mark_SpacingCombining, // Mc + Mark_Enclosing, // Me + + Number_DecimalDigit, // Nd + Number_Letter, // Nl + Number_Other, // No + + Separator_Space, // Zs + Separator_Line, // Zl + Separator_Paragraph, // Zp + + Other_Control, // Cc + Other_Format, // Cf + Other_Surrogate, // Cs + Other_PrivateUse, // Co + Other_NotAssigned, // Cn + + Letter_Uppercase, // Lu + Letter_Lowercase, // Ll + Letter_Titlecase, // Lt + Letter_Modifier, // Lm + Letter_Other, // Lo + + Punctuation_Connector, // Pc + Punctuation_Dask, // Pd + Punctuation_Open, // Ps + Punctuation_Close, // Pe + Punctuation_InitialQuote, // Pi + Punctuation_FinalQuote, // Pf + Punctuation_Other, // Po + + Symbol_Math, // Sm + Symbol_Currency, // Sc + Symbol_Modifier, // Sk + Symbol_Other // So + }; + + enum Direction + { + DirL, DirR, DirEN, DirES, DirET, DirAN, DirCS, DirB, DirS, DirWS, DirON, + DirLRE, DirLRO, DirAL, DirRLE, DirRLO, DirPDF, DirNSM, DirBN + }; + + enum Decomposition + { + Single, Canonical, Font, NoBreak, Initial, Medial, + Final, Isolated, Circle, Super, Sub, Vertical, + Wide, Narrow, Small, Square, Compat, Fraction + }; + + enum Joining + { + OtherJoining, Dual, Right, Center + }; + + // ****** WHEN ADDING FUNCTIONS, CONSIDER ADDING TO QCharRef TOO + + int digitValue() const; + QChar lower() const; + QChar upper() const; + + Category category() const; + Direction direction() const; + Joining joining() const; + bool mirrored() const; + QChar mirroredChar() const; + QString decomposition() const; + Decomposition decompositionTag() const; + + char latin1() const { return rw ? 0 : cl; } + ushort unicode() const { return (rw << 8) | cl; } +#ifndef QT_NO_CAST_ASCII + // like all ifdef'd code this is undocumented + operator char() const { return latin1(); } +#endif + + bool isNull() const { return unicode()==0; } + bool isPrint() const; + bool isPunct() const; + bool isSpace() const; + bool isMark() const; + bool isLetter() const; + bool isNumber() const; + bool isLetterOrNumber() const; + bool isDigit() const; + + uchar& cell() { return cl; } + uchar& row() { return rw; } + uchar cell() const { return cl; } + uchar row() const { return rw; } + + static bool networkOrdered() { return (int)net_ordered == 1; } + + friend inline int operator==( char ch, QChar c ); + friend inline int operator==( QChar c, char ch ); + friend inline int operator==( QChar c1, QChar c2 ); + friend inline int operator!=( QChar c1, QChar c2 ); + friend inline int operator!=( char ch, QChar c ); + friend inline int operator!=( QChar c, char ch ); + friend inline int operator<=( QChar c, char ch ); + friend inline int operator<=( char ch, QChar c ); + friend inline int operator<=( QChar c1, QChar c2 ); + +private: +#if defined(_WS_X11_) || defined(_OS_WIN32_BYTESWAP_) || defined( _WS_QWS_ ) + // XChar2b on X11, ushort on _OS_WIN32_BYTESWAP_ + //### QWS must be defined on a platform by platform basis + uchar rw; + uchar cl; +#if defined(QT_QSTRING_UCS_4) + ushort grp; +#endif + enum { net_ordered = 1 }; +#else + // ushort on _OS_WIN32_ + uchar cl; + uchar rw; +#if defined(QT_QSTRING_UCS_4) + ushort grp; +#endif + enum { net_ordered = 0 }; +#endif +}; + +inline QChar::QChar() +{ + rw = 0; cl = 0; +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( char c ) +{ + rw = 0; cl = (uchar)c; +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( uchar c ) +{ + rw = 0; cl = c; +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( uchar c, uchar r ) +{ + rw = r; cl = c; +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( const QChar& c ) +{ + rw = c.rw; cl = c.cl; +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( ushort rc ) +{ + rw = (uchar)((rc>>8)&0xff); cl = (uchar)(rc&0xff); +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( short rc ) +{ + rw = (uchar)((rc>>8)&0xff); cl = (uchar)(rc&0xff); +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( uint rc ) +{ + rw = (uchar)((rc>>8)&0xff); cl = (uchar)(rc&0xff); +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} +inline QChar::QChar( int rc ) +{ + rw = (uchar)((rc>>8)&0xff); cl = (uchar)(rc&0xff); +#ifdef QT_QSTRING_UCS_4 + grp = 0; +#endif +} + + +inline int operator==( char ch, QChar c ) +{ + return ch == c.cl && !c.rw; +} + +inline int operator==( QChar c, char ch ) +{ + return ch == c.cl && !c.rw; +} + +inline int operator==( QChar c1, QChar c2 ) +{ + return c1.cl == c2.cl + && c1.rw == c2.rw; +} + +inline int operator!=( QChar c1, QChar c2 ) +{ + return c1.cl != c2.cl + || c1.rw != c2.rw; +} + +inline int operator!=( char ch, QChar c ) +{ + return ch != c.cl || c.rw; +} + +inline int operator!=( QChar c, char ch ) +{ + return ch != c.cl || c.rw; +} + +inline int operator<=( QChar c, char ch ) +{ + return !(ch < c.cl || c.rw); +} + +inline int operator<=( char ch, QChar c ) +{ + return ch <= c.cl || c.rw; +} + +inline int operator<=( QChar c1, QChar c2 ) +{ + return c1.rw > c2.rw + ? FALSE + : c1.rw < c2.rw + ? TRUE + : c1.cl <= c2.cl; +} + +inline int operator>=( QChar c, char ch ) { return ch <= c; } +inline int operator>=( char ch, QChar c ) { return c <= ch; } +inline int operator>=( QChar c1, QChar c2 ) { return c2 <= c1; } +inline int operator<( QChar c, char ch ) { return !(ch<=c); } +inline int operator<( char ch, QChar c ) { return !(c<=ch); } +inline int operator<( QChar c1, QChar c2 ) { return !(c2<=c1); } +inline int operator>( QChar c, char ch ) { return !(ch>=c); } +inline int operator>( char ch, QChar c ) { return !(c>=ch); } +inline int operator>( QChar c1, QChar c2 ) { return !(c2>=c1); } + +// internal +struct Q_EXPORT QStringData : public QShared { + QStringData() : + unicode(0), ascii(0), len(0), maxl(0), dirtyascii(0) { ref(); } + QStringData(QChar *u, uint l, uint m) : + unicode(u), ascii(0), len(l), maxl(m), dirtyascii(0) { } + + ~QStringData() { if ( unicode ) delete[] ((char*)unicode); + if ( ascii ) delete[] ascii; } + + void deleteSelf(); + QChar *unicode; + char *ascii; + uint len; + uint maxl:30; + uint dirtyascii:1; +}; + + +class Q_EXPORT QString +{ +public: + QString(); // make null string + QString( QChar ); // one-char string + QString( const QString & ); // impl-shared copy + QString( const QByteArray& ); // deep copy + QString( const QCString& ); // deep copy + QString( const QChar* unicode, uint length ); // deep copy +#ifndef QT_NO_CAST_ASCII + QString( const char *str ); // deep copy +#endif + ~QString(); + + QString &operator=( const QString & ); // impl-shared copy +#ifndef QT_NO_CAST_ASCII + QString &operator=( const char * ); // deep copy +#endif + QString &operator=( const QCString& ); // deep copy + QString &operator=( QChar c ); + QString &operator=( char c ); + + QT_STATIC_CONST QString null; + + bool isNull() const; + bool isEmpty() const; + uint length() const; + void truncate( uint pos ); + +#if QT_VERSION >= 300 +#error "fill() Should return *this, or QChar constructor should take count=1" +#endif + void fill( QChar c, int len = -1 ); + + QString copy() const; + + QString arg(long a, int fieldwidth=0, int base=10) const; + QString arg(ulong a, int fieldwidth=0, int base=10) const; + QString arg(int a, int fieldwidth=0, int base=10) const; + QString arg(uint a, int fieldwidth=0, int base=10) const; + QString arg(short a, int fieldwidth=0, int base=10) const; + QString arg(ushort a, int fieldwidth=0, int base=10) const; + QString arg(char a, int fieldwidth=0) const; + QString arg(QChar a, int fieldwidth=0) const; + QString arg(const QString& a, int fieldwidth=0) const; + QString arg(double a, int fieldwidth=0, char fmt='g', int prec=-1) const; + + QString &sprintf( const char* format, ... ) +#if defined(_CC_GNU_) && !defined(__INSURE__) + __attribute__ ((format (printf, 2, 3))) +#endif + ; + + int find( QChar c, int index=0, bool cs=TRUE ) const; + int find( char c, int index=0, bool cs=TRUE ) const; + int find( const QString &str, int index=0, bool cs=TRUE ) const; + int find( const QRegExp &, int index=0 ) const; +#ifndef QT_NO_CAST_ASCII + int find( const char* str, int index=0 ) const; +#endif + int findRev( QChar c, int index=-1, bool cs=TRUE) const; + int findRev( char c, int index=-1, bool cs=TRUE) const; + int findRev( const QString &str, int index=-1, bool cs=TRUE) const; + int findRev( const QRegExp &, int index=-1 ) const; +#ifndef QT_NO_CAST_ASCII + int findRev( const char* str, int index=-1 ) const; +#endif + int contains( QChar c, bool cs=TRUE ) const; + int contains( char c, bool cs=TRUE ) const + { return contains(QChar(c), cs); } +#ifndef QT_NO_CAST_ASCII + int contains( const char* str, bool cs=TRUE ) const; +#endif + int contains( const QString &str, bool cs=TRUE ) const; + int contains( const QRegExp & ) const; + + QString left( uint len ) const; + QString right( uint len ) const; + QString mid( uint index, uint len=0xffffffff) const; + + QString leftJustify( uint width, QChar fill=' ', bool trunc=FALSE)const; + QString rightJustify( uint width, QChar fill=' ',bool trunc=FALSE)const; + + QString lower() const; + QString upper() const; + + QString stripWhiteSpace() const; + QString simplifyWhiteSpace() const; + + QString &insert( uint index, const QString & ); + QString &insert( uint index, const QChar*, uint len ); + QString &insert( uint index, QChar ); + QString &insert( uint index, char c ) { return insert(index,QChar(c)); } + QString &append( char ); + QString &append( QChar ); + QString &append( const QString & ); + QString &prepend( char ); + QString &prepend( QChar ); + QString &prepend( const QString & ); + QString &remove( uint index, uint len ); + QString &replace( uint index, uint len, const QString & ); + QString &replace( uint index, uint len, const QChar*, uint clen ); + QString &replace( const QRegExp &, const QString & ); + + short toShort( bool *ok=0, int base=10 ) const; + ushort toUShort( bool *ok=0, int base=10 ) const; + int toInt( bool *ok=0, int base=10 ) const; + uint toUInt( bool *ok=0, int base=10 ) const; + long toLong( bool *ok=0, int base=10 ) const; + ulong toULong( bool *ok=0, int base=10 ) const; + float toFloat( bool *ok=0 ) const; + double toDouble( bool *ok=0 ) const; + + QString &setNum( short, int base=10 ); + QString &setNum( ushort, int base=10 ); + QString &setNum( int, int base=10 ); + QString &setNum( uint, int base=10 ); + QString &setNum( long, int base=10 ); + QString &setNum( ulong, int base=10 ); + QString &setNum( float, char f='g', int prec=6 ); + QString &setNum( double, char f='g', int prec=6 ); + + static QString number( long, int base=10 ); + static QString number( ulong, int base=10); + static QString number( int, int base=10 ); + static QString number( uint, int base=10); + static QString number( double, char f='g', int prec=6 ); + + void setExpand( uint index, QChar c ); + + QString &operator+=( const QString &str ); + QString &operator+=( QChar c ); + QString &operator+=( char c ); + + // Your compiler is smart enough to use the const one if it can. + QChar at( uint i ) const + { return i<d->len ? d->unicode[i] : QChar::null; } + QChar operator[]( int i ) const { return at((uint)i); } + QCharRef at( uint i ); + QCharRef operator[]( int i ); + + QChar constref(uint i) const + { return at(i); } + QChar& ref(uint i) + { // Optimized for easy-inlining by simple compilers. + if (d->count!=1 || i>=d->len) + subat(i); + d->dirtyascii=1; + return d->unicode[i]; + } + + const QChar* unicode() const { return d->unicode; } + const char* ascii() const; + const char* latin1() const; + static QString fromLatin1(const char*, int len=-1); +#ifndef QT_NO_TEXTCODEC + QCString utf8() const; + static QString fromUtf8(const char*, int len=-1); +#endif + QCString local8Bit() const; + static QString fromLocal8Bit(const char*, int len=-1); + bool operator!() const; +#ifndef QT_NO_ASCII_CAST + operator const char *() const { return latin1(); } +#endif + + QString &setUnicode( const QChar* unicode, uint len ); + QString &setUnicodeCodes( const ushort* unicode_as_ushorts, uint len ); + QString &setLatin1( const char*, int len=-1 ); + + int compare( const QString& s ) const; + static int compare( const QString& s1, const QString& s2 ) + { return s1.compare(s2); } + +#ifndef QT_NO_DATASTREAM + friend Q_EXPORT QDataStream &operator>>( QDataStream &, QString & ); +#endif + // new functions for BiDi + void compose(); + QChar::Direction basicDirection(); + QString visual(int index = 0, int len = -1); + +#ifndef QT_NO_COMPAT + const char* data() const { return latin1(); } +#endif + + bool startsWith( const QString& ) const; + +private: + QString( int size, bool dummy ); // allocate size incl. \0 + + void deref(); + void real_detach(); + void setLength( uint pos ); + void subat( uint ); + bool findArg(int& pos, int& len) const; + + static QChar* asciiToUnicode( const char*, uint * len, uint maxlen=(uint)-1 ); + static QChar* asciiToUnicode( const QByteArray&, uint * len ); + static char* unicodeToAscii( const QChar*, uint len ); + + QStringData *d; + static QStringData* shared_null; + static QStringData* makeSharedNull(); + + friend class QConstString; + QString(QStringData* dd, bool /*dummy*/) : d(dd) { } +}; + +class Q_EXPORT QCharRef { + friend class QString; + QString& s; + uint p; + QCharRef(QString* str, uint pos) : s(*str), p(pos) { } + +public: + // Most QChar operations repeated here... + + // all this is not documented: We just say "like QChar" and let it be. +#if 1 + ushort unicode() const { return s.constref(p).unicode(); } + char latin1() const { return s.constref(p).latin1(); } + + // An operator= for each QChar cast constructor... + QCharRef operator=(char c ) { s.ref(p)=c; return *this; } + QCharRef operator=(uchar c ) { s.ref(p)=c; return *this; } + QCharRef operator=(QChar c ) { s.ref(p)=c; return *this; } + QCharRef operator=(const QCharRef& c ) { s.ref(p)=c.unicode(); return *this; } + QCharRef operator=(ushort rc ) { s.ref(p)=rc; return *this; } + QCharRef operator=(short rc ) { s.ref(p)=rc; return *this; } + QCharRef operator=(uint rc ) { s.ref(p)=rc; return *this; } + QCharRef operator=(int rc ) { s.ref(p)=rc; return *this; } + + operator QChar () const { return s.constref(p); } + + // each function... + bool isNull() const { return unicode()==0; } + bool isPrint() const { return s.constref(p).isPrint(); } + bool isPunct() const { return s.constref(p).isPunct(); } + bool isSpace() const { return s.constref(p).isSpace(); } + bool isMark() const { return s.constref(p).isMark(); } + bool isLetter() const { return s.constref(p).isLetter(); } + bool isNumber() const { return s.constref(p).isNumber(); } + bool isLetterOrNumber() { return s.constref(p).isLetterOrNumber(); } + bool isDigit() const { return s.constref(p).isDigit(); } + + int digitValue() const { return s.constref(p).digitValue(); } + QChar lower() { return s.constref(p).lower(); } + QChar upper() { return s.constref(p).upper(); } + + QChar::Category category() const { return s.constref(p).category(); } + QChar::Direction direction() const { return s.constref(p).direction(); } + QChar::Joining joining() const { return s.constref(p).joining(); } + bool mirrored() const { return s.constref(p).mirrored(); } + QChar mirroredChar() const { return s.constref(p).mirroredChar(); } + QString decomposition() const { return s.constref(p).decomposition(); } + QChar::Decomposition decompositionTag() const { return s.constref(p).decompositionTag(); } + + // Not the non-const ones of these. + uchar cell() const { return s.constref(p).cell(); } + uchar row() const { return s.constref(p).row(); } +#endif +}; + +inline QCharRef QString::at( uint i ) { return QCharRef(this,i); } +inline QCharRef QString::operator[]( int i ) { return at((uint)i); } + + +class Q_EXPORT QConstString : private QString { +public: + QConstString( QChar* unicode, uint length ); + ~QConstString(); + const QString& string() const { return *this; } +}; + + +/***************************************************************************** + QString stream functions + *****************************************************************************/ +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator<<( QDataStream &, const QString & ); +Q_EXPORT QDataStream &operator>>( QDataStream &, QString & ); +#endif + +/***************************************************************************** + QString inline functions + *****************************************************************************/ + +// These two move code into makeSharedNull() and deletesData() +// to improve cache-coherence (and reduce code bloat), while +// keeping the common cases fast. +// +// No safe way to pre-init shared_null on ALL compilers/linkers. +inline QString::QString() : + d(shared_null ? shared_null : makeSharedNull()) +{ + d->ref(); +} +// +inline QString::~QString() +{ + if ( d->deref() ) { + if ( d == shared_null ) + shared_null = 0; + d->deleteSelf(); + } +} + +inline QString &QString::operator=( QChar c ) +{ return *this = QString(c); } + +inline QString &QString::operator=( char c ) +{ return *this = QString(QChar(c)); } + +inline bool QString::isNull() const +{ return unicode() == 0; } + +inline bool QString::operator!() const +{ return isNull(); } + +inline uint QString::length() const +{ return d->len; } + +inline bool QString::isEmpty() const +{ return length() == 0; } + +inline QString QString::copy() const +{ return QString( *this ); } + +inline QString &QString::prepend( const QString & s ) +{ return insert(0,s); } + +inline QString &QString::prepend( QChar c ) +{ return insert(0,c); } + +inline QString &QString::prepend( char c ) +{ return insert(0,c); } + +inline QString &QString::append( const QString & s ) +{ return operator+=(s); } + +inline QString &QString::append( QChar c ) +{ return operator+=(c); } + +inline QString &QString::append( char c ) +{ return operator+=(c); } + +inline QString &QString::setNum( short n, int base ) +{ return setNum((long)n, base); } + +inline QString &QString::setNum( ushort n, int base ) +{ return setNum((ulong)n, base); } + +inline QString &QString::setNum( int n, int base ) +{ return setNum((long)n, base); } + +inline QString &QString::setNum( uint n, int base ) +{ return setNum((ulong)n, base); } + +inline QString &QString::setNum( float n, char f, int prec ) +{ return setNum((double)n,f,prec); } + +inline QString QString::arg(int a, int fieldwidth, int base) const +{ return arg((long)a, fieldwidth, base); } + +inline QString QString::arg(uint a, int fieldwidth, int base) const +{ return arg((ulong)a, fieldwidth, base); } + +inline QString QString::arg(short a, int fieldwidth, int base) const +{ return arg((long)a, fieldwidth, base); } + +inline QString QString::arg(ushort a, int fieldwidth, int base) const +{ return arg((ulong)a, fieldwidth, base); } + +inline int QString::find( char c, int index, bool cs ) const +{ return find(QChar(c), index, cs); } + +inline int QString::findRev( char c, int index, bool cs) const +{ return findRev( QChar(c), index, cs ); } + + +#ifndef QT_NO_CAST_ASCII +inline int QString::find( const char* str, int index ) const +{ return find(QString::fromLatin1(str), index); } + +inline int QString::findRev( const char* str, int index ) const +{ return findRev(QString::fromLatin1(str), index); } +#endif + + +/***************************************************************************** + QString non-member operators + *****************************************************************************/ + +Q_EXPORT bool operator!=( const QString &s1, const QString &s2 ); +Q_EXPORT bool operator<( const QString &s1, const QString &s2 ); +Q_EXPORT bool operator<=( const QString &s1, const QString &s2 ); +Q_EXPORT bool operator==( const QString &s1, const QString &s2 ); +Q_EXPORT bool operator>( const QString &s1, const QString &s2 ); +Q_EXPORT bool operator>=( const QString &s1, const QString &s2 ); +#ifndef QT_NO_CAST_ASCII +Q_EXPORT bool operator!=( const QString &s1, const char *s2 ); +Q_EXPORT bool operator<( const QString &s1, const char *s2 ); +Q_EXPORT bool operator<=( const QString &s1, const char *s2 ); +Q_EXPORT bool operator==( const QString &s1, const char *s2 ); +Q_EXPORT bool operator>( const QString &s1, const char *s2 ); +Q_EXPORT bool operator>=( const QString &s1, const char *s2 ); +Q_EXPORT bool operator!=( const char *s1, const QString &s2 ); +Q_EXPORT bool operator<( const char *s1, const QString &s2 ); +Q_EXPORT bool operator<=( const char *s1, const QString &s2 ); +Q_EXPORT bool operator==( const char *s1, const QString &s2 ); +//Q_EXPORT bool operator>( const char *s1, const QString &s2 ); // MSVC++ +Q_EXPORT bool operator>=( const char *s1, const QString &s2 ); +#endif + +Q_EXPORT inline QString operator+( const QString &s1, const QString &s2 ) +{ + QString tmp( s1 ); + tmp += s2; + return tmp; +} + +#ifndef QT_NO_CAST_ASCII +Q_EXPORT inline QString operator+( const QString &s1, const char *s2 ) +{ + QString tmp( s1 ); + tmp += QString::fromLatin1(s2); + return tmp; +} + +Q_EXPORT inline QString operator+( const char *s1, const QString &s2 ) +{ + QString tmp = QString::fromLatin1( s1 ); + tmp += s2; + return tmp; +} +#endif + +Q_EXPORT inline QString operator+( const QString &s1, QChar c2 ) +{ + QString tmp( s1 ); + tmp += c2; + return tmp; +} + +Q_EXPORT inline QString operator+( const QString &s1, char c2 ) +{ + QString tmp( s1 ); + tmp += c2; + return tmp; +} + +Q_EXPORT inline QString operator+( QChar c1, const QString &s2 ) +{ + QString tmp; + tmp += c1; + tmp += s2; + return tmp; +} + +Q_EXPORT inline QString operator+( char c1, const QString &s2 ) +{ + QString tmp; + tmp += c1; + tmp += s2; + return tmp; +} + +#if defined(_OS_WIN32_) +extern Q_EXPORT QString qt_winQString(void*); +extern Q_EXPORT const void* qt_winTchar(const QString& str, bool addnul); +extern Q_EXPORT void* qt_winTchar_new(const QString& str); +extern Q_EXPORT QCString qt_winQString2MB( const QString& s, int len=-1 ); +extern Q_EXPORT QString qt_winMB2QString( const char* mb, int len=-1 ); +#endif + +#endif // QSTRING_H diff --git a/trunk/qtools/qstringlist.cpp b/trunk/qtools/qstringlist.cpp new file mode 100644 index 0000000..ff4f33e --- /dev/null +++ b/trunk/qtools/qstringlist.cpp @@ -0,0 +1,302 @@ +/**************************************************************************** +** +** +** Implementation of QStringList +** +** Created : 990406 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qstringlist.h" + +#ifndef QT_NO_STRINGLIST +#include "qstrlist.h" +#include "qdatastream.h" +#include "qtl.h" + +// NOT REVISED +/*! + \class QStringList qstringlist.h + \brief A list of strings. + + \ingroup qtl + \ingroup tools + \ingroup shared + + QStringList is basically a QValueList of QString objects. As opposed + to QStrList, that stores pointers to characters, QStringList deals + with real QString objects. It is the class of choice whenever you + work with unicode strings. + + Like QString itself, QStringList objects are implicit shared. + Passing them around as value-parameters is both fast and safe. + + Example: + \code + QStringList list; + + // three different ways of appending values: + list.append( "Torben"); + list += "Warwick"; + list << "Matthias" << "Arnt" << "Paul"; + + // sort the list, Arnt's now first + list.sort(); + + // print it out + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) { + printf( "%s \n", (*it).latin1() ); + } + \endcode + + Convenience methods such as sort(), split(), join() and grep() make + working with QStringList easy. +*/ + +/*! + \fn QStringList::QStringList() + Creates an empty list. +*/ + +/*! \fn QStringList::QStringList( const QStringList& l ) + Creates a copy of the list. This function is very fast since + QStringList is implicit shared. However, for the programmer this + is the same as a deep copy. If this list or the original one or some + other list referencing the same shared data is modified, then the + modifying list makes a copy first. +*/ + +/*! + \fn QStringList::QStringList (const QString & i) + Constructs a string list consisting of the single string \a i. + To make longer lists easily, use: + \code + QString s1,s2,s3; + ... + QStringList mylist = QStringList() << s1 << s2 << s3; + \endcode +*/ + +/*! + \fn QStringList::QStringList (const char* i) + Constructs a string list consisting of the single latin-1 string \a i. +*/ + +/*! \fn QStringList::QStringList( const QValueList<QString>& l ) + + Constructs a new string list that is a copy of \a l. +*/ + +/*! + Sorts the list of strings in ascending order. + + Sorting is very fast. It uses the Qt Template Library's + efficient HeapSort implementation that operates in O(n*log n). +*/ +void QStringList::sort() +{ + qHeapSort(*this); +} + +/*! + Splits the string \a str using \a sep as separator. Returns the + list of strings. If \a allowEmptyEntries is TRUE, also empty + entries are inserted into the list, else not. So if you have + a string 'abc..d.e.', a list which contains 'abc', 'd', and 'e' + would be returned if \a allowEmptyEntries is FALSE, but + a list containing 'abc', '', 'd', 'e' and '' would be returned if + \a allowEmptyEntries is TRUE. + If \a str doesn't contain \a sep, a stringlist + with one item, which is the same as \a str, is returned. + + \sa join() +*/ + +QStringList QStringList::split( const QChar &sep, const QString &str, bool allowEmptyEntries ) +{ + return split( QString( sep ), str, allowEmptyEntries ); +} + +/*! + Splits the string \a str using \a sep as separator. Returns the + list of strings. If \a allowEmptyEntries is TRUE, also empty + entries are inserted into the list, else not. So if you have + a string 'abc..d.e.', a list which contains 'abc', 'd', and 'e' + would be returned if \a allowEmptyEntries is FALSE, but + a list containing 'abc', '', 'd', 'e' and '' would be returned if + \a allowEmptyEntries is TRUE. + If \a str doesn't contain \a sep, a stringlist + with one item, which is the same as \a str, is returned. + + \sa join() +*/ + +QStringList QStringList::split( const QString &sep, const QString &str, bool allowEmptyEntries ) +{ + QStringList lst; + + int j = 0; + int i = str.find( sep, j ); + + while ( i != -1 ) { + if ( str.mid( j, i - j ).length() > 0 ) + lst << str.mid( j, i - j ); + else if ( allowEmptyEntries ) + lst << QString::null; + j = i + sep.length(); + i = str.find( sep, j ); + } + + int l = str.length() - 1; + if ( str.mid( j, l - j + 1 ).length() > 0 ) + lst << str.mid( j, l - j + 1 ); + else if ( allowEmptyEntries ) + lst << QString::null; + + return lst; +} + +/*! + Splits the string \a str using the regular expression \a sep as separator. Returns the + list of strings. If \a allowEmptyEntries is TRUE, also empty + entries are inserted into the list, else not. So if you have + a string 'abc..d.e.', a list which contains 'abc', 'd', and 'e' + would be returned if \a allowEmptyEntries is FALSE, but + a list containing 'abc', '', 'd', 'e' and '' would be returned if + \a allowEmptyEntries is TRUE. + If \a str doesn't contain \a sep, a stringlist + with one item, which is the same as \a str, is returned. + + \sa join() +*/ + +QStringList QStringList::split( const QRegExp &sep, const QString &str, bool allowEmptyEntries ) +{ + QStringList lst; + + int j = 0; + int len = 0; + int i = sep.match( str, j, &len ); + + while ( i != -1 ) { + if ( str.mid( j, i - j ).length() > 0 ) + lst << str.mid( j, i - j ); + else if ( allowEmptyEntries ) + lst << QString::null; + j = i + len; + i = sep.match( str, j, &len ); + } + + int l = str.length() - 1; + if ( str.mid( j, l - j + 1 ).length() > 0 ) + lst << str.mid( j, l - j + 1 ); + else if ( allowEmptyEntries ) + lst << QString::null; + + return lst; +} + +/*! + Returns a list of all strings containing the substring \a str. + + If \a cs is TRUE, the grep is done case sensitively, else not. +*/ + +QStringList QStringList::grep( const QString &str, bool cs ) const +{ + QStringList res; + for ( QStringList::ConstIterator it = begin(); it != end(); ++it ) + if ( (*it).contains( str, cs ) ) + res << *it; + + return res; +} + +/*! + Returns a list of all strings containing a substring that matches + the regular expression \a expr. +*/ + +QStringList QStringList::grep( const QRegExp &expr ) const +{ + QStringList res; + for ( QStringList::ConstIterator it = begin(); it != end(); ++it ) + if ( (*it).contains( expr ) ) + res << *it; + + return res; +} + +/*! + Joins the stringlist into a single string with each element + separated by \a sep. + + \sa split() +*/ +QString QStringList::join( const QString &sep ) const +{ + QString res; + bool alredy = FALSE; + for ( QStringList::ConstIterator it = begin(); it != end(); ++it ) { + if ( alredy ) + res += sep; + alredy = TRUE; + res += *it; + } + + return res; +} + +#ifndef QT_NO_DATASTREAM +Q_EXPORT QDataStream &operator>>( QDataStream & s, QStringList& l ) +{ + return s >> (QValueList<QString>&)l; +} + +Q_EXPORT QDataStream &operator<<( QDataStream & s, const QStringList& l ) +{ + return s << (const QValueList<QString>&)l; +} +#endif + +/*! + Converts from a QStrList (ASCII) to a QStringList (Unicode). +*/ +QStringList QStringList::fromStrList(const QStrList& ascii) +{ + QStringList res; + const char * s; + for ( QStrListIterator it(ascii); (s=it.current()); ++it ) + res << s; + return res; +} + +#endif //QT_NO_STRINGLIST diff --git a/trunk/qtools/qstringlist.h b/trunk/qtools/qstringlist.h new file mode 100644 index 0000000..03342c5 --- /dev/null +++ b/trunk/qtools/qstringlist.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** +** Definition of QStringList class +** +** Created : 990406 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSTRINGLIST_H +#define QSTRINGLIST_H + +#ifndef QT_H +#include "qvaluelist.h" +#include "qstring.h" +#include "qregexp.h" +#endif // QT_H + +#ifndef QT_NO_STRINGLIST + +class QStrList; + +class Q_EXPORT QStringList : public QValueList<QString> +{ +public: + QStringList() { } + QStringList( const QStringList& l ) : QValueList<QString>(l) { } + QStringList( const QValueList<QString>& l ) : QValueList<QString>(l) { } + QStringList( const QString& i ) { append(i); } +#ifndef QT_NO_CAST_ASCII + QStringList( const char* i ) { append(i); } +#endif + + static QStringList fromStrList(const QStrList&); + + void sort(); + + static QStringList split( const QString &sep, const QString &str, bool allowEmptyEntries = FALSE ); + static QStringList split( const QChar &sep, const QString &str, bool allowEmptyEntries = FALSE ); + static QStringList split( const QRegExp &sep, const QString &str, bool allowEmptyEntries = FALSE ); + QString join( const QString &sep ) const; + + QStringList grep( const QString &str, bool cs = TRUE ) const; + QStringList grep( const QRegExp &expr ) const; +}; + +#ifndef QT_NO_DATASTREAM +class QDataStream; +extern Q_EXPORT QDataStream &operator>>( QDataStream &, QStringList& ); +extern Q_EXPORT QDataStream &operator<<( QDataStream &, const QStringList& ); +#endif +#endif // QT_NO_STRINGLIST +#endif // QSTRINGLIST_H diff --git a/trunk/qtools/qstrlist.doc b/trunk/qtools/qstrlist.doc new file mode 100644 index 0000000..751c6c2 --- /dev/null +++ b/trunk/qtools/qstrlist.doc @@ -0,0 +1,5 @@ +/**************************************************************************** +** +*****************************************************************************/ + +//typedef QListIterator<char> QStrListIterator; diff --git a/trunk/qtools/qstrlist.h b/trunk/qtools/qstrlist.h new file mode 100644 index 0000000..c6a1864 --- /dev/null +++ b/trunk/qtools/qstrlist.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** +** Definition of QStrList, QStrIList and QStrListIterator classes +** +** Created : 920730 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSTRLIST_H +#define QSTRLIST_H + +#ifndef QT_H +#include "qstring.h" +#include "qlist.h" +#include "qdatastream.h" +#endif // QT_H + + +#if defined(Q_TEMPLATEDLL) +template class Q_EXPORT QList<char>; +template class Q_EXPORT QListIterator<char>; +#endif + +typedef QList<char> QStrListBase; +typedef QListIterator<char> QStrListIterator; + + +class Q_EXPORT QStrList : public QStrListBase +{ +public: + QStrList( bool deepCopies=TRUE ) { dc = deepCopies; del_item = deepCopies; } + QStrList( const QStrList & ); + ~QStrList() { clear(); } + QStrList& operator=( const QStrList & ); + +private: + QCollection::Item newItem( QCollection::Item d ) { return dc ? qstrdup( (const char*)d ) : d; } + void deleteItem( QCollection::Item d ) { if ( del_item ) delete[] (char*)d; } + int compareItems( QCollection::Item s1, QCollection::Item s2 ) { return qstrcmp((const char*)s1, + (const char*)s2); } +#ifndef QT_NO_DATASTREAM + QDataStream &read( QDataStream &s, QCollection::Item &d ) + { s >> (char *&)d; return s; } + QDataStream &write( QDataStream &s, QCollection::Item d ) const + { return s << (const char *)d; } +#endif + bool dc; +}; + + +class Q_EXPORT QStrIList : public QStrList // case insensitive string list +{ +public: + QStrIList( bool deepCopies=TRUE ) : QStrList( deepCopies ) {} + ~QStrIList() { clear(); } +private: + int compareItems( QCollection::Item s1, QCollection::Item s2 ) + { return qstricmp((const char*)s1, + (const char*)s2); } +}; + + +inline QStrList & QStrList::operator=( const QStrList &strList ) +{ + clear(); + dc = strList.dc; + del_item = dc; + QStrListBase::operator=(strList); + return *this; +} + +inline QStrList::QStrList( const QStrList &strList ) + : QStrListBase( strList ) +{ + dc = FALSE; + operator=(strList); +} + + +#endif // QSTRLIST_H diff --git a/trunk/qtools/qstrvec.h b/trunk/qtools/qstrvec.h new file mode 100644 index 0000000..15d3abb --- /dev/null +++ b/trunk/qtools/qstrvec.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** +** Definition of QStrVec and QStrIVec classes +** +** Created : 931203 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QSTRVEC_H +#define QSTRVEC_H + +#ifndef QT_H +#include "qstring.h" +#include "qvector.h" +#include "qdatastream.h" +#endif // QT_H + + +#if defined(Q_TEMPLATEDLL) +template class Q_EXPORT QVector<char> +#endif + +typedef QVector<char> QStrVecBase; + + +class Q_EXPORT QStrVec : public QStrVecBase +{ +public: + QStrVec() { dc = TRUE; } + QStrVec( uint size, bool deepc = TRUE ) : QStrVecBase(size) {dc=deepc;} + ~QStrVec() { clear(); } +private: + Item newItem( Item d ) { return dc ? qstrdup( (const char*)d ) : d; } + void deleteItem( Item d ) { if ( dc ) delete[] (char*)d; } + int compareItems( Item s1, Item s2 ) + { return qstrcmp((const char*)s1, + (const char*)s2); } +#ifndef QT_NO_DATASTREAM + QDataStream &read( QDataStream &s, Item &d ) + { s >> (char *&)d; return s; } + QDataStream &write( QDataStream &s, Item d ) const + { return s << (const char*)d; } +#endif + bool dc; +}; + + +class Q_EXPORT QStrIVec : public QStrVec // case insensitive string vec +{ +public: + QStrIVec() {} + QStrIVec( uint size, bool dc = TRUE ) : QStrVec( size, dc ) {} + ~QStrIVec() { clear(); } +private: + int compareItems( Item s1, Item s2 ) + { return qstricmp((const char*)s1, + (const char*)s2); } +}; + + +#endif // QSTRVEC_H diff --git a/trunk/qtools/qtextcodec.cpp b/trunk/qtools/qtextcodec.cpp new file mode 100644 index 0000000..fbbc1f9 --- /dev/null +++ b/trunk/qtools/qtextcodec.cpp @@ -0,0 +1,2071 @@ +/**************************************************************************** +** +** +** Implementation of QTextCodec class +** +** Created : 981015 +** +** Copyright (C)1998-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qtextcodec.h" +#ifndef QT_NO_TEXTCODEC + +#include "qlist.h" +#ifndef QT_NO_CODECS +#include "qutfcodec.h" +#include "qgbkcodec.h" +#include "qeucjpcodec.h" +#include "qjiscodec.h" +#include "qsjiscodec.h" +#include "qeuckrcodec.h" +#include "qbig5codec.h" +#include "qrtlcodec.h" +#include "qtsciicodec.h" +#endif + +#include "qfile.h" +#include "qstrlist.h" +#include "qstring.h" + +#include <stdlib.h> +#include <ctype.h> +#include <locale.h> + + +static QList<QTextCodec> * all = 0; +static bool destroying_is_ok; // starts out as 0 + +/*! Deletes all the created codecs. + + \warning Do not call this function. + + QApplication calls this just before exiting, to delete any + QTextCodec objects that may be lying around. Since various other + classes hold pointers to QTextCodec objects, it is not safe to call + this function earlier. + + If you are using the utility classes (like QString) but not using + QApplication, calling this function at the very end of your + application can be helpful to chasing down memory leaks, as + QTextCodec objects will not show up. +*/ + +void QTextCodec::deleteAllCodecs() +{ + if ( !all ) + return; + + destroying_is_ok = TRUE; + QList<QTextCodec> * ball = all; + all = 0; + ball->clear(); + delete ball; + destroying_is_ok = FALSE; +} + + +static void setupBuiltinCodecs(); + + +static void realSetup() +{ +#if defined(CHECK_STATE) + if ( destroying_is_ok ) + qWarning( "creating new codec during codec cleanup" ); +#endif + all = new QList<QTextCodec>; + all->setAutoDelete( TRUE ); + setupBuiltinCodecs(); +} + + +static inline void setup() +{ + if ( !all ) + realSetup(); +} + + +class QTextStatelessEncoder: public QTextEncoder { + const QTextCodec* codec; +public: + QTextStatelessEncoder(const QTextCodec*); + QCString fromUnicode(const QString& uc, int& lenInOut); +}; + + +class QTextStatelessDecoder : public QTextDecoder { + const QTextCodec* codec; +public: + QTextStatelessDecoder(const QTextCodec*); + QString toUnicode(const char* chars, int len); +}; + +QTextStatelessEncoder::QTextStatelessEncoder(const QTextCodec* c) : + codec(c) +{ +} + + +QCString QTextStatelessEncoder::fromUnicode(const QString& uc, int& lenInOut) +{ + return codec->fromUnicode(uc,lenInOut); +} + + +QTextStatelessDecoder::QTextStatelessDecoder(const QTextCodec* c) : + codec(c) +{ +} + + +QString QTextStatelessDecoder::toUnicode(const char* chars, int len) +{ + return codec->toUnicode(chars,len); +} + + + +// NOT REVISED +/*! + \class QTextCodec qtextcodec.h + \brief Provides conversion between text encodings. + + By making objects of subclasses of QTextCodec, support for + new text encodings can be added to Qt. + + The abstract virtual functions describe the encoder to the + system and the coder is used as required in the different + text file formats supported QTextStream and, under X11 for the + locale-specific character input and output (under Windows NT + codecs are not needed for GUI I/O since the system works + with Unicode already, and Windows 95/98 has built-in convertors + for the 8-bit local encoding). + + More recently created QTextCodec objects take precedence + over earlier ones. + + To add support for another 8-bit encoding to Qt, make a subclass + or QTextCodec and implement at least the following methods: + <dl> + <dt>\c const char* name() const + <dd>Return the official name for the encoding. + <dt>\c int mibEnum() const + <dd>Return the MIB enum for the encoding if it is listed in the + <a href=ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets> + IANA character-sets encoding file</a>. + </dl> + If the encoding is multi-byte then it will have "state"; that is, + the interpretation of some bytes will be dependent on some preceding + bytes. For such an encoding, you will need to implement + <dl> + <dt> \c QTextDecoder* makeDecoder() const + <dd>Return a QTextDecoder that remembers incomplete multibyte + sequence prefixes or other required state. + </dl> + If the encoding does \e not require state, you should implement: + <dl> + <dt> \c QString toUnicode(const char* chars, int len) const + <dd>Converts \e len characters from \e chars to Unicode. + </dl> + The base QTextCodec class has default implementations of the above + two functions, <i>but they are mutually recursive</i>, so you must + re-implement at least one of them, or both for improved efficiency. + + For conversion from Unicode to 8-bit encodings, it is rarely necessary + to maintain state. However, two functions similar to the two above + are used for encoding: + <dl> + <dt> \c QTextEncoder* makeEncoder() const + <dd>Return a QTextDecoder. + <dt> \c QCString fromUnicode(const QString& uc, int& lenInOut ) const; + <dd>Converts \e lenInOut characters (of type QChar) from the start + of the string \a uc, returning a QCString result, and also returning + the \link QCString::length() length\endlink + of the result in lenInOut. + </dl> + Again, these are mutually recursive so only one needs to be implemented, + or both if better efficiency is possible. + + Finally, you must implement: + <dl> + <dt> \c int heuristicContentMatch(const char* chars, int len) const + <dd>Gives a value indicating how likely it is that \e len characters + from \e chars are in the encoding. + </dl> + A good model for this function is the + QWindowsLocalCodec::heuristicContentMatch function found in the Qt sources. + + A QTextCodec subclass might have improved performance if you also + re-implement: + <dl> + <dt> \c bool canEncode( QChar ) const + <dd>Test if a Unicode character can be encoded. + <dt> \c bool canEncode( const QString& ) const + <dd>Test if a string of Unicode characters can be encoded. + <dt> \c int heuristicNameMatch(const char* hint) const + <dd>Test if a possibly non-standard name is referring to the codec. + </dl> +*/ + + +/*! + Constructs a QTextCodec, making it of highest precedence. + The QTextCodec should always be constructed on the heap + (with new), and once constructed it becomes the responsibility + of Qt to delete it (which is done at QApplication destruction). +*/ +QTextCodec::QTextCodec() +{ + setup(); + all->insert(0,this); +} + + +/*! + Destructs the QTextCodec. Note that you should not delete + codecs yourself - once created they become the responsibility + of Qt to delete. +*/ +QTextCodec::~QTextCodec() +{ + if ( !destroying_is_ok ) + qWarning("QTextCodec::~QTextCodec() called by application"); + if ( all ) + all->remove( this ); +} + + +/*! + Returns a value indicating how likely this decoder is + for decoding some format that has the given name. + + A good match returns a positive number around + the length of the string. A bad match is negative. + + The default implementation calls simpleHeuristicNameMatch() + with the name of the codec. +*/ +int QTextCodec::heuristicNameMatch(const char* hint) const +{ + return simpleHeuristicNameMatch(name(),hint); +} + + +// returns a string cotnaining the letters and numbers from input, +// with a space separating run of a character class. e.g. "iso8859-1" +// becomes "iso 8859 1" +static QString lettersAndNumbers( const char * input ) +{ + QString result; + QChar c; + + while( input && *input ) { + c = *input; + if ( c.isLetter() || c.isNumber() ) + result += c.lower(); + if ( input[1] ) { + // add space at character class transition, except + // transition from upper-case to lower-case letter + QChar n( input[1] ); + if ( c.isLetter() && n.isLetter() ) { + if ( c == c.lower() && n == n.upper() ) + result += ' '; + } else if ( c.category() != n.category() ) { + result += ' '; + } + } + input++; + } + return result.simplifyWhiteSpace(); +} + +/*! + A simple utility function for heuristicNameMatch() - it + does some very minor character-skipping + so that almost-exact matches score high. +*/ +int QTextCodec::simpleHeuristicNameMatch(const char* name, const char* hint) +{ + // if they're the same, return a perfect score. + if ( name && hint && qstrcmp( name, hint ) == 0 ) + return qstrlen( hint ); + + // if the letters and numbers are the same, we have an "almost" + // perfect match. + QString h( lettersAndNumbers( hint ) ); + QString n( lettersAndNumbers( name ) ); + if ( h == n ) + return qstrlen( hint )-1; + + if ( h.stripWhiteSpace() == n.stripWhiteSpace() ) + return qstrlen( hint )-2; + + // could do some more here, but I don't think it's worth it + + return 0; +} + + +/*! + Returns the QTextCodec \a i places from the more recently + inserted, or NULL if there is no such QTextCodec. Thus, + codecForIndex(0) returns the most recently created QTextCodec. +*/ +QTextCodec* QTextCodec::codecForIndex(int i) +{ + setup(); + return (uint)i >= all->count() ? 0 : all->at(i); +} + + +/*! + Returns the QTextCodec which matches the + \link QTextCodec::mibEnum() MIBenum\endlink \a mib. +*/ +QTextCodec* QTextCodec::codecForMib(int mib) +{ + setup(); + QListIterator<QTextCodec> i(*all); + QTextCodec* result; + for ( ; (result=i); ++i ) { + if ( result->mibEnum()==mib ) + break; + } + return result; +} + + + + + +#ifdef _OS_WIN32_ +class QWindowsLocalCodec: public QTextCodec +{ +public: + QWindowsLocalCodec(); + ~QWindowsLocalCodec(); + + QString toUnicode(const char* chars, int len) const; + QCString fromUnicode(const QString& uc, int& lenInOut ) const; + + const char* name() const; + int mibEnum() const; + + int heuristicContentMatch(const char* chars, int len) const; +}; + +QWindowsLocalCodec::QWindowsLocalCodec() +{ +} + +QWindowsLocalCodec::~QWindowsLocalCodec() +{ +} + + +QString QWindowsLocalCodec::toUnicode(const char* chars, int len) const +{ + if ( len == 1 && chars ) { // Optimization; avoids allocation + char c[2]; + c[0] = *chars; + c[1] = 0; + return qt_winMB2QString( c, 2 ); + } + if ( len < 0 ) + return qt_winMB2QString( chars ); + QCString s(chars,len+1); + return qt_winMB2QString(s); +} + +QCString QWindowsLocalCodec::fromUnicode(const QString& uc, int& lenInOut ) const +{ + QCString r = qt_winQString2MB( uc, lenInOut ); + lenInOut = r.length(); + return r; +} + + +const char* QWindowsLocalCodec::name() const +{ + return "System"; +} + +int QWindowsLocalCodec::mibEnum() const +{ + return 0; +} + + +int QWindowsLocalCodec::heuristicContentMatch(const char* chars, int len) const +{ + // ### Not a bad default implementation? + QString t = toUnicode(chars,len); + int l = t.length(); + QCString mb = fromUnicode(t,l); + int i=0; + while ( i < len ) + if ( chars[i] == mb[i] ) + i++; + return i; +} + +#else + +/* locale names mostly copied from XFree86 */ +static const char * const iso8859_2locales[] = { + "croatian", "cs", "cs_CS", "cs_CZ","cz", "cz_CZ", "czech", "hr", + "hr_HR", "hu", "hu_HU", "hungarian", "pl", "pl_PL", "polish", "ro", + "ro_RO", "rumanian", "serbocroatian", "sh", "sh_SP", "sh_YU", "sk", + "sk_SK", "sl", "sl_CS", "sl_SI", "slovak", "slovene", "sr_SP", 0 }; + +static const char * const iso8859_3locales[] = { + "eo", 0 }; + +static const char * const iso8859_4locales[] = { + "ee", "ee_EE", "lt", "lt_LT", "lv", "lv_LV", 0 }; + +static const char * const iso8859_5locales[] = { + "bg", "bg_BG", "bulgarian", "mk", "mk_MK", + "sp", "sp_YU", 0 }; + +static const char * const iso8859_6locales[] = { + "ar_AA", "ar_SA", "arabic", 0 }; + +static const char * const iso8859_7locales[] = { + "el", "el_GR", "greek", 0 }; + +static const char * const iso8859_8locales[] = { + "hebrew", "he", "he_IL", "iw", "iw_IL", 0 }; + +static const char * const iso8859_9locales[] = { + "tr", "tr_TR", "turkish", 0 }; + +static const char * const iso8859_15locales[] = { + "fr", "fi", "french", "finnish", "et", "et_EE", 0 }; + +static const char * const koi8_ulocales[] = { + "uk", "uk_UA", "ru_UA", "ukrainian", 0 }; + +static const char * const tis_620locales[] = { + "th", "th_TH", "thai", 0 }; + + +static bool try_locale_list( const char * const locale[], const char * lang ) +{ + int i; + for( i=0; locale[i] && qstrcmp(locale[i], lang); i++ ) + { } + return locale[i] != 0; +} + +// For the probably_koi8_locales we have to look. the standard says +// these are 8859-5, but almsot all Russion users uses KOI8-R and +// incorrectly set $LANG to ru_RU. We'll check tolower() to see what +// tolower() thinks ru_RU means. + +// If you read the history, it seems that many Russians blame ISO and +// Peristroika for the confusion. +// +// The real bug is that some programs break if the user specifies +// ru_RU.KOI8-R. + +static const char * const probably_koi8_rlocales[] = { + "ru", "ru_SU", "ru_RU", "russian", 0 }; + +// this means ANY of these locale aliases. if they're aliases for +// different locales, the code breaks. +static QTextCodec * ru_RU_codec = 0; + +static QTextCodec * ru_RU_hack( const char * i ) { + if ( ! ru_RU_codec ) { + QCString origlocale = setlocale( LC_CTYPE, i ); + // unicode koi8r latin5 name + // 0x044E 0xC0 0xEE CYRILLIC SMALL LETTER YU + // 0x042E 0xE0 0xCE CYRILLIC CAPITAL LETTER YU + int latin5 = tolower( 0xCE ); + int koi8r = tolower( 0xE0 ); + if ( koi8r == 0xC0 && latin5 != 0xEE ) { + ru_RU_codec = QTextCodec::codecForName( "KOI8-R" ); + } else if ( koi8r != 0xC0 && latin5 == 0xEE ) { + ru_RU_codec = QTextCodec::codecForName( "ISO 8859-5" ); + } else { + // something else again... let's assume... *throws dice* + ru_RU_codec = QTextCodec::codecForName( "KOI8-R" ); + qWarning( "QTextCodec: using KOI8-R, probe failed (%02x %02x %s)", + koi8r, latin5, i ); + } + setlocale( LC_CTYPE, origlocale.data() ); + } + return ru_RU_codec; +} + +#endif + +static QTextCodec * localeMapper = 0; + +void qt_set_locale_codec( QTextCodec *codec ) +{ + localeMapper = codec; +} + +/*! Returns a pointer to the codec most suitable for this locale. */ + +QTextCodec* QTextCodec::codecForLocale() +{ + if ( localeMapper ) + return localeMapper; + + setup(); + +#ifdef _OS_WIN32_ + localeMapper = new QWindowsLocalCodec; +#else + // Very poorly defined and followed standards causes lots of code + // to try to get all the cases... + + char * lang = qstrdup( getenv("LANG") ); + + char * p = lang ? strchr( lang, '.' ) : 0; + if ( !p || *p != '.' ) { + // Some versions of setlocale return encoding, others not. + char *ctype = qstrdup( setlocale( LC_CTYPE, 0 ) ); + // Some Linux distributions have broken locales which will return + // "C" for LC_CTYPE + if ( qstrcmp( ctype, "C" ) == 0 ) { + delete [] ctype; + } else { + if ( lang ) + delete [] lang; + lang = ctype; + p = lang ? strchr( lang, '.' ) : 0; + } + } + + if( p && *p == '.' ) { + // if there is an encoding and we don't know it, we return 0 + // User knows what they are doing. Codecs will believe them. + localeMapper = codecForName( lang ); + if ( !localeMapper ) { + // Use or codec disagree. + localeMapper = codecForName( p+1 ); + } + } + if ( !localeMapper || !(p && *p == '.') ) { + // if there is none, we default to 8859-1 + // We could perhaps default to 8859-15. + if ( try_locale_list( iso8859_2locales, lang ) ) + localeMapper = codecForName( "ISO 8859-2" ); + else if ( try_locale_list( iso8859_3locales, lang ) ) + localeMapper = codecForName( "ISO 8859-3" ); + else if ( try_locale_list( iso8859_4locales, lang ) ) + localeMapper = codecForName( "ISO 8859-4" ); + else if ( try_locale_list( iso8859_5locales, lang ) ) + localeMapper = codecForName( "ISO 8859-5" ); + else if ( try_locale_list( iso8859_6locales, lang ) ) + localeMapper = codecForName( "ISO 8859-6-I" ); + else if ( try_locale_list( iso8859_7locales, lang ) ) + localeMapper = codecForName( "ISO 8859-7" ); + else if ( try_locale_list( iso8859_8locales, lang ) ) + localeMapper = codecForName( "ISO 8859-8-I" ); + else if ( try_locale_list( iso8859_9locales, lang ) ) + localeMapper = codecForName( "ISO 8859-9" ); + else if ( try_locale_list( iso8859_15locales, lang ) ) + localeMapper = codecForName( "ISO 8859-15" ); + else if ( try_locale_list( tis_620locales, lang ) ) + localeMapper = codecForName( "ISO 8859-11" ); + else if ( try_locale_list( koi8_ulocales, lang ) ) + localeMapper = codecForName( "KOI8-U" ); + else if ( try_locale_list( probably_koi8_rlocales, lang ) ) + localeMapper = ru_RU_hack( lang ); + else if (!lang || !(localeMapper = codecForName(lang) )) + localeMapper = codecForName( "ISO 8859-1" ); + } + delete[] lang; +#endif + + return localeMapper; +} + + +/*! + Searches all installed QTextCodec objects, returning the one + which best matches given name. Returns NULL if no codec has + a match closeness above \a accuracy. + + \sa heuristicNameMatch() +*/ +QTextCodec* QTextCodec::codecForName(const char* hint, int accuracy) +{ + setup(); + QListIterator<QTextCodec> i(*all); + QTextCodec* result = 0; + int best=accuracy; + for ( QTextCodec* cursor; (cursor=i); ++i ) { + int s = cursor->heuristicNameMatch(hint); + if ( s > best ) { + best = s; + result = cursor; + } + } + return result; +} + + +/*! + Searches all installed QTextCodec objects, returning the one + which most recognizes the given content. May return 0. + + Note that this is often a poor choice, since character + encodings often use most of the available character sequences, + and so only by linguistic analysis could a true match be made. + + \sa heuristicContentMatch() +*/ +QTextCodec* QTextCodec::codecForContent(const char* chars, int len) +{ + setup(); + QListIterator<QTextCodec> i(*all); + QTextCodec* result = 0; + int best=0; + for ( QTextCodec* cursor; (cursor=i); ++i ) { + int s = cursor->heuristicContentMatch(chars,len); + if ( s > best ) { + best = s; + result = cursor; + } + } + return result; +} + + +/*! + \fn const char* QTextCodec::name() const + Subclasses of QTextCodec must reimplement this function. It returns + the name of the encoding supported by the subclass. When choosing + a name for an encoding, consider these points: + <ul> + <li>On X11, heuristicNameMatch( const char * hint ) + is used to test if a the QTextCodec + can convert between Unicode and the encoding of a font + with encoding \e hint, such as "iso8859-1" for Latin-1 fonts, + "koi8-r" for Russian KOI8 fonts. + The default algorithm of heuristicNameMatch() uses name(). + <li>Some applications may use this function to present + encodings to the end user. + </ul> +*/ + +/*! + \fn int QTextCodec::mibEnum() const + + Subclasses of QTextCodec must reimplement this function. It returns the + MIBenum (see + <a href="ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets"> + the IANA character-sets encoding file</a> for more information). + It is important that each QTextCodec subclass return the correct unique + value for this function. +*/ + + +/*! + \fn int QTextCodec::heuristicContentMatch(const char* chars, int len) const + + Subclasses of QTextCodec must reimplement this function. It examines + the first \a len bytes of \a chars and returns a value indicating how + likely it is that the string is a prefix of text encoded in the + encoding of the subclass. Any negative return value indicates that the text + is detectably not in the encoding (eg. it contains undefined characters). + A return value of 0 indicates that the text should be decoded with this + codec rather than as ASCII, but there + is no particular evidence. The value should range up to \a len. Thus, + most decoders will return -1, 0, or -\a len. + + The characters are not null terminated. + + \sa codecForContent(). +*/ + + +/*! + Creates a QTextDecoder which stores enough state to decode chunks + of char* data to create chunks of Unicode data. The default implementation + creates a stateless decoder, which is sufficient for only the simplest + encodings where each byte corresponds to exactly one Unicode character. + + The caller is responsible for deleting the returned object. +*/ +QTextDecoder* QTextCodec::makeDecoder() const +{ + return new QTextStatelessDecoder(this); +} + + +/*! + Creates a QTextEncoder which stores enough state to encode chunks + of Unicode data as char* data. The default implementation + creates a stateless encoder, which is sufficient for only the simplest + encodings where each Unicode character corresponds to exactly one char. + + The caller is responsible for deleting the returned object. +*/ +QTextEncoder* QTextCodec::makeEncoder() const +{ + return new QTextStatelessEncoder(this); +} + + +/*! + Subclasses of QTextCodec must reimplement this function or + makeDecoder(). It converts the first \a len characters of \a chars + to Unicode. + + The default implementation makes a decoder with makeDecoder() and + converts the input with that. Note that the default makeDecoder() + implementation makes a decoder that simply calls + this function, hence subclasses \e must reimplement one function or + the other to avoid infinite recursion. +*/ +QString QTextCodec::toUnicode(const char* chars, int len) const +{ + QTextDecoder* i = makeDecoder(); + QString result = i->toUnicode(chars,len); + delete i; + return result; +} + + +/*! + Subclasses of QTextCodec must reimplement either this function or + makeEncoder(). It converts the first \a lenInOut characters of \a + uc from Unicode to the encoding of the subclass. If \a lenInOut + is negative or too large, the length of \a uc is used instead. + + The value returned is the property of the caller, which is + responsible for deleting it with "delete []". The length of the + resulting Unicode character sequence is returned in \a lenInOut. + + The default implementation makes an encoder with makeEncoder() and + converts the input with that. Note that the default makeEncoder() + implementation makes an encoder that simply calls + this function, hence subclasses \e must reimplement one function or + the other to avoid infinite recursion. +*/ + +QCString QTextCodec::fromUnicode(const QString& uc, int& lenInOut) const +{ + QTextEncoder* i = makeEncoder(); + QCString result = i->fromUnicode(uc, lenInOut); + delete i; + return result; +} + +/*! + \overload QCString QTextCodec::fromUnicode(const QString& uc) const +*/ +QCString QTextCodec::fromUnicode(const QString& uc) const +{ + int l = uc.length(); + return fromUnicode(uc,l); +} + +/*! + \overload QString QTextCodec::toUnicode(const QByteArray& a, int len) const +*/ +QString QTextCodec::toUnicode(const QByteArray& a, int len) const +{ + int l = a.size(); + if( l > 0 && a.data()[l - 1] == '\0' ) l--; + l = QMIN( l, len ); + return toUnicode( a.data(), l ); +} + +/*! + \overload QString QTextCodec::toUnicode(const QByteArray& a) const +*/ +QString QTextCodec::toUnicode(const QByteArray& a) const +{ + int l = a.size(); + if( l > 0 && a.data()[l - 1] == '\0' ) l--; + return toUnicode( a.data(), l ); +} + +/*! + \overload QString QTextCodec::toUnicode(const char* chars) const +*/ +QString QTextCodec::toUnicode(const char* chars) const +{ + return toUnicode(chars,qstrlen(chars)); +} + +/*! + Returns TRUE if the unicode character \a ch can be fully encoded + with this codec. The default implementation tests if the result of + toUnicode(fromUnicode(ch)) is the original \a ch. Subclasses may be + able to improve the efficiency. +*/ +bool QTextCodec::canEncode( QChar ch ) const +{ + return toUnicode(fromUnicode(ch)) == ch; +} + +/*! + Returns TRUE if the unicode string \a s can be fully encoded + with this codec. The default implementation tests if the result of + toUnicode(fromUnicode(s)) is the original \a s. Subclasses may be + able to improve the efficiency. +*/ +bool QTextCodec::canEncode( const QString& s ) const +{ + return toUnicode(fromUnicode(s)) == s; +} + + + +/*! + \class QTextEncoder qtextcodec.h + \brief State-based encoder + + A QTextEncoder converts Unicode into another format, remembering + any state that is required between calls. + + \sa QTextCodec::makeEncoder() +*/ + +/*! + Destructs the encoder. +*/ +QTextEncoder::~QTextEncoder() +{ +} +/*! + \fn QCString QTextEncoder::fromUnicode(const QString& uc, int& lenInOut) + + Converts \a lenInOut characters (not bytes) from \a uc, producing + a QCString. \a lenInOut will also be set to the + \link QCString::length() length\endlink of the result (in bytes). + + The encoder is free to record state to use when subsequent calls are + made to this function (for example, it might change modes with escape + sequences if needed during the encoding of one string, then assume that + mode applies when a subsequent call begins). +*/ + +/*! + \class QTextDecoder qtextcodec.h + \brief State-based decoder + + A QTextEncoder converts a text format into Unicode, remembering + any state that is required between calls. + + \sa QTextCodec::makeEncoder() +*/ + + +/*! + Destructs the decoder. +*/ +QTextDecoder::~QTextDecoder() +{ +} + +/*! + \fn QString QTextDecoder::toUnicode(const char* chars, int len) + + Converts the first \a len bytes at \a chars to Unicode, returning the + result. + + If not all characters are used (eg. only part of a multi-byte + encoding is at the end of the characters), the decoder remembers + enough state to continue with the next call to this function. +*/ + +#define CHAINED 0xffff + +struct QMultiByteUnicodeTable { + // If multibyte, ignore unicode and index into multibyte + // with the next character. + QMultiByteUnicodeTable() : unicode(0xfffd), multibyte(0) { } + + ~QMultiByteUnicodeTable() + { + if ( multibyte ) + delete [] multibyte; + } + + ushort unicode; + QMultiByteUnicodeTable* multibyte; +}; + +#ifndef QT_NO_CODECS +static int getByte(char* &cursor) +{ + int byte = 0; + if ( *cursor ) { + if ( cursor[1] == 'x' ) + byte = strtol(cursor+2,&cursor,16); + else if ( cursor[1] == 'd' ) + byte = strtol(cursor+2,&cursor,10); + else + byte = strtol(cursor+2,&cursor,8); + } + return byte&0xff; +} + +class QTextCodecFromIOD; + +class QTextCodecFromIODDecoder : public QTextDecoder { + const QTextCodecFromIOD* codec; + QMultiByteUnicodeTable* mb; +public: + QTextCodecFromIODDecoder(const QTextCodecFromIOD* c); + QString toUnicode(const char* chars, int len); +}; + +class QTextCodecFromIOD : public QTextCodec { + friend class QTextCodecFromIODDecoder; + + QCString n; + + // If from_unicode_page[row()][cell()] is 0 and from_unicode_page_multibyte, + // use from_unicode_page_multibyte[row()][cell()] as string. + char** from_unicode_page; + char*** from_unicode_page_multibyte; + char unkn; + + // Only one of these is used + ushort* to_unicode; + QMultiByteUnicodeTable* to_unicode_multibyte; + int max_bytes_per_char; + QStrList aliases; + + bool stateless() const { return !to_unicode_multibyte; } + +public: + QTextCodecFromIOD(QIODevice* iod) + { + from_unicode_page = 0; + to_unicode_multibyte = 0; + to_unicode = 0; + from_unicode_page_multibyte = 0; + max_bytes_per_char = 1; + + const int maxlen=100; + char line[maxlen]; + char esc='\\'; + char comm='%'; + bool incmap = FALSE; + while (iod->readLine(line,maxlen) > 0) { + if (0==qstrnicmp(line,"<code_set_name>",15)) + n = line+15; + else if (0==qstrnicmp(line,"<escape_char> ",14)) + esc = line[14]; + else if (0==qstrnicmp(line,"<comment_char> ",15)) + comm = line[15]; + else if (line[0]==comm && 0==qstrnicmp(line+1," alias ",7)) { + aliases.append(line+8); + } else if (0==qstrnicmp(line,"CHARMAP",7)) { + if (!from_unicode_page) { + from_unicode_page = new char*[256]; + for (int i=0; i<256; i++) + from_unicode_page[i]=0; + } + if (!to_unicode) { + to_unicode = new ushort[256]; + } + incmap = TRUE; + } else if (0==qstrnicmp(line,"END CHARMAP",11)) + break; + else if (incmap) { + char* cursor = line; + int byte,unicode=-1; + ushort* mb_unicode=0; + const int maxmb=8; // more -> we'll need to improve datastructures + char mb[maxmb+1]; + int nmb=0; + + while (*cursor) { + if (cursor[0]=='<' && cursor[1]=='U' && + cursor[2]>='0' && cursor[2]<='9' && + cursor[3]>='0' && cursor[3]<='9') { + + unicode = strtol(cursor+2,&cursor,16); + + } else if (*cursor==esc) { + + byte = getByte(cursor); + + if ( *cursor == esc ) { + if ( !to_unicode_multibyte ) { + to_unicode_multibyte = + new QMultiByteUnicodeTable[256]; + for (int i=0; i<256; i++) { + to_unicode_multibyte[i].unicode = + to_unicode[i]; + to_unicode_multibyte[i].multibyte = 0; + } + delete [] to_unicode; + to_unicode = 0; + } + QMultiByteUnicodeTable* mbut = + to_unicode_multibyte+byte; + mb[nmb++] = byte; + while ( nmb < maxmb && *cursor == esc ) { + // Always at least once + + mbut->unicode = CHAINED; + byte = getByte(cursor); + mb[nmb++] = byte; + if (!mbut->multibyte) { + mbut->multibyte = + new QMultiByteUnicodeTable[256]; + } + mbut = mbut->multibyte+byte; + mb_unicode = & mbut->unicode; + } + + if ( nmb > max_bytes_per_char ) + max_bytes_per_char = nmb; + } + } else { + cursor++; + } + } + + if (unicode >= 0 && unicode <= 0xffff) + { + QChar ch((ushort)unicode); + if (!from_unicode_page[ch.row()]) { + from_unicode_page[ch.row()] = new char[256]; + for (int i=0; i<256; i++) + from_unicode_page[ch.row()][i]=0; + } + if ( mb_unicode ) { + from_unicode_page[ch.row()][ch.cell()] = 0; + if (!from_unicode_page_multibyte) { + from_unicode_page_multibyte = new char**[256]; + for (int i=0; i<256; i++) + from_unicode_page_multibyte[i]=0; + } + if (!from_unicode_page_multibyte[ch.row()]) { + from_unicode_page_multibyte[ch.row()] = new char*[256]; + for (int i=0; i<256; i++) + from_unicode_page_multibyte[ch.row()][i] = 0; + } + mb[nmb++] = 0; + from_unicode_page_multibyte[ch.row()][ch.cell()] + = qstrdup(mb); + *mb_unicode = unicode; + } else { + from_unicode_page[ch.row()][ch.cell()] = (char)byte; + if ( to_unicode ) + to_unicode[byte] = unicode; + else + to_unicode_multibyte[byte].unicode = unicode; + } + } else { + } + } + } + n = n.stripWhiteSpace(); + + unkn = '?'; // ##### Might be a bad choice. + } + + ~QTextCodecFromIOD() + { + if ( from_unicode_page ) { + for (int i=0; i<256; i++) + if (from_unicode_page[i]) + delete [] from_unicode_page[i]; + } + if ( from_unicode_page_multibyte ) { + for (int i=0; i<256; i++) + if (from_unicode_page_multibyte[i]) + for (int j=0; j<256; j++) + if (from_unicode_page_multibyte[i][j]) + delete [] from_unicode_page_multibyte[i][j]; + } + if ( to_unicode ) + delete [] to_unicode; + if ( to_unicode_multibyte ) + delete [] to_unicode_multibyte; + } + + bool ok() const + { + return !!from_unicode_page; + } + + QTextDecoder* makeDecoder() const + { + if ( stateless() ) + return QTextCodec::makeDecoder(); + else + return new QTextCodecFromIODDecoder(this); + } + + const char* name() const + { + return n; + } + + int mibEnum() const + { + return 0; // #### Unknown. + } + + int heuristicContentMatch(const char*, int) const + { + return 0; + } + + int heuristicNameMatch(const char* hint) const + { + int bestr = QTextCodec::heuristicNameMatch(hint); + QStrListIterator it(aliases); + char* a; + while ((a=it.current())) { + ++it; + int r = simpleHeuristicNameMatch(a,hint); + if (r > bestr) + bestr = r; + } + return bestr; + } + + QString toUnicode(const char* chars, int len) const + { + const uchar* uchars = (const uchar*)chars; + QString result; + QMultiByteUnicodeTable* multibyte=to_unicode_multibyte; + if ( multibyte ) { + while (len--) { + QMultiByteUnicodeTable& mb = multibyte[*uchars]; + if ( mb.multibyte ) { + // Chained multi-byte + multibyte = mb.multibyte; + } else { + result += QChar(mb.unicode); + multibyte=to_unicode_multibyte; + } + uchars++; + } + } else { + while (len--) + result += QChar(to_unicode[*uchars++]); + } + return result; + } + + QCString fromUnicode(const QString& uc, int& lenInOut) const + { + if (lenInOut > (int)uc.length()) + lenInOut = uc.length(); + int rlen = lenInOut*max_bytes_per_char; + QCString rstr(rlen); + char* cursor = rstr.data(); + char* s=0; + int l = lenInOut; + int lout = 0; + for (int i=0; i<l; i++) { + QChar ch = uc[i]; + if ( ch == QChar::null ) { + // special + *cursor++ = 0; + } else if ( from_unicode_page[ch.row()] && + from_unicode_page[ch.row()][ch.cell()] ) + { + *cursor++ = from_unicode_page[ch.row()][ch.cell()]; + lout++; + } else if ( from_unicode_page_multibyte && + from_unicode_page_multibyte[ch.row()] && + (s=from_unicode_page_multibyte[ch.row()][ch.cell()]) ) + { + while (*s) { + *cursor++ = *s++; + lout++; + } + } else { + *cursor++ = unkn; + lout++; + } + } + *cursor = 0; + lenInOut = lout; + return rstr; + } +}; + +QTextCodecFromIODDecoder::QTextCodecFromIODDecoder(const QTextCodecFromIOD* c) : + codec(c) +{ + mb = codec->to_unicode_multibyte; +} + +QString QTextCodecFromIODDecoder::toUnicode(const char* chars, int len) +{ + const uchar* uchars = (const uchar*)chars; + QString result; + while (len--) { + QMultiByteUnicodeTable& t = mb[*uchars]; + if ( t.multibyte ) { + // Chained multi-byte + mb = t.multibyte; + } else { + if ( t.unicode ) + result += QChar(t.unicode); + mb=codec->to_unicode_multibyte; + } + uchars++; + } + return result; +} + +/*! + Reads a POSIX2 charmap definition from \a iod. + The parser recognizes the following lines: +<pre> + <code_set_name> <i>name</i> + <escape_char> <i>character</i> + % alias <i>alias</i> + CHARMAP + <<i>token</i>> /x<i>hexbyte</i> <U<i>unicode</i>> ... + <<i>token</i>> /d<i>decbyte</i> <U<i>unicode</i>> ... + <<i>token</i>> /<i>octbyte</i> <U<i>unicode</i>> ... + <<i>token</i>> /<i>any</i>/<i>any</i>... <U<i>unicode</i>> ... + END CHARMAP +</pre> + + The resulting QTextCodec is returned (and also added to the + global list of codecs). The name() of the result is taken + from the code_set_name. + + Note that a codec constructed in this way uses much more memory + and is slower than a hand-written QTextCodec subclass, since + tables in code are in memory shared by all applications simultaneously + using Qt. + + \sa loadCharmapFile() +*/ +QTextCodec* QTextCodec::loadCharmap(QIODevice* iod) +{ + QTextCodecFromIOD* r = new QTextCodecFromIOD(iod); + if ( !r->ok() ) { + delete r; + r = 0; + } + return r; +} + +/*! + A convenience function for loadCharmap(). +*/ +QTextCodec* QTextCodec::loadCharmapFile(QString filename) +{ + QFile f(filename); + if (f.open(IO_ReadOnly)) { + QTextCodecFromIOD* r = new QTextCodecFromIOD(&f); + if ( !r->ok() ) + delete r; + else + return r; + } + return 0; +} +#endif //QT_NO_CODECS + + +/*! + Returns a string representing the current language. +*/ + +const char* QTextCodec::locale() +{ + static QCString lang; + if ( lang.isEmpty() ) { + lang = getenv( "LANG" ); //########Windows?? + if ( lang.isEmpty() ) + lang = "C"; + } + return lang; +} + + + +#ifndef QT_NO_CODECS + +class QSimpleTextCodec: public QTextCodec +{ +public: + QSimpleTextCodec( int ); + ~QSimpleTextCodec(); + + QString toUnicode(const char* chars, int len) const; + QCString fromUnicode(const QString& uc, int& lenInOut ) const; + + const char* name() const; + int mibEnum() const; + + int heuristicContentMatch(const char* chars, int len) const; + + int heuristicNameMatch(const char* hint) const; + +private: + int forwardIndex; +}; + + +#define LAST_MIB 2259 + +static struct { + const char * cs; + int mib; + Q_UINT16 values[128]; +} unicodevalues[] = { + // from RFC 1489, ftp://ftp.isi.edu/in-notes/rfc1489.txt + { "KOI8-R", 2084, + { 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, + 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, + 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219/**/, 0x221A, 0x2248, + 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, + 0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x00A9, + 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, + 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A } }, + // /**/ - The BULLET OPERATOR is confused. Some people think + // it should be 0x2022 (BULLET). + + // from RFC 2319, ftp://ftp.isi.edu/in-notes/rfc2319.txt + { "KOI8-U", 2088, + { 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, + 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, + 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, + 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, + 0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x0404, 0x2563, 0x0406, 0x0407, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 0x256C, 0x00A9, + 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, + 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A } }, + + // next bits generated from tables on the Unicode 2.0 CD. we can + // use these tables since this is part of the transition to using + // unicode everywhere in qt. + + // $ for A in 8 9 A B C D E F ; do for B in 0 1 2 3 4 5 6 7 8 9 A B C D E F ; do echo 0x${A}${B} 0xFFFD ; done ; done > /tmp/digits ; for a in 8859-* ; do ( awk '/^0x[89ABCDEF]/{ print $1, $2 }' < $a ; cat /tmp/digits ) | sort | uniq -w4 | cut -c6- | paste '-d ' - - - - - - - - | sed -e 's/ /, /g' -e 's/$/,/' -e '$ s/,$/} },/' -e '1 s/^/{ /' > ~/tmp/$a ; done + + // then I inserted the files manually. + { "ISO 8859-2", 5, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, + 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, + 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, + 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9} }, + { "ISO 8859-3", 6, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0xFFFD, 0x0124, 0x00A7, + 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0xFFFD, 0x017B, + 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, + 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0xFFFD, 0x017C, + 0x00C0, 0x00C1, 0x00C2, 0xFFFD, 0x00C4, 0x010A, 0x0108, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0xFFFD, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, + 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0xFFFD, 0x00E4, 0x010B, 0x0109, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0xFFFD, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, + 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9} }, + { "ISO 8859-4", 7, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7, + 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF, + 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7, + 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A, + 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B, + 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9} }, + { "ISO 8859-5", 8, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F} }, + { "ISO 8859-6-I", 82, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0xFFFD, 0xFFFD, 0xFFFD, 0x00A4, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x060C, 0x00AD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0x061B, 0xFFFD, 0xFFFD, 0xFFFD, 0x061F, + 0xFFFD, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, + 0x0638, 0x0639, 0x063A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, + 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, + 0x0650, 0x0651, 0x0652, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD} }, + { "ISO 8859-7", 10, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x2018, 0x2019, 0x00A3, 0xFFFD, 0xFFFD, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0xFFFD, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0xFFFD, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xFFFD} }, + { "ISO 8859-8-I", 85, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0xFFFD, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x203E, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x2017, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD} }, + { "ISO 8859-9", 12, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF} }, + { "ISO 8859-10", 13, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7, + 0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A, + 0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7, + 0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2015, 0x016B, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138} }, + { "ISO 8859-13", 109, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019} }, + { "ISO 8859-14", 110, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7, + 0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178, + 0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56, + 0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF} }, + { "ISO 8859-15", 111, + { 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7, + 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7, + 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF} }, + + // next bits generated again from tables on the Unicode 3.0 CD. + + // $ for a in CP* ; do ( awk '/^0x[89ABCDEF]/{ print $1, $2 }' < $a ) | sort | sed -e 's/#UNDEF.*$/0xFFFD/' | cut -c6- | paste '-d ' - - - - - - - - | sed -e 's/ /, /g' -e 's/$/,/' -e '$ s/,$/} },/' -e '1 s/^/{ /' > ~/tmp/$a ; done + + { "CP 874", 0, //### what is the mib? + { 0x20AC, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x2026, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x00A0, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, + 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, + 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, + 0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, + 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD} }, + { "CP 1250", 2250, + { 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021, + 0xFFFD, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, + 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B, + 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9} }, + { "CP 1251", 2251, + { 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, + 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, + 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, + 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, + 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, + 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, + 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F} }, + { "CP 1252", 2252, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFD, 0x017D, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFD, 0x017E, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF} }, + { "CP 1253", 2253, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0xFFFD, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0xFFFD, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0xFFFD} }, + { "CP 1254", 2254, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF} }, + { "CP 1255", 2255, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AA, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, + 0x05B8, 0x05B9, 0xFFFD, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, + 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, + 0x05F4, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0xFFFD, 0xFFFD, 0x200E, 0x200F, 0xFFFD} }, + { "CP 1256", 2256, + { 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, + 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, + 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F, + 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, + 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643, + 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF, + 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, + 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2} }, + { "CP 1257", 2257, + { 0x20AC, 0xFFFD, 0x201A, 0xFFFD, 0x201E, 0x2026, 0x2020, 0x2021, + 0xFFFD, 0x2030, 0xFFFD, 0x2039, 0xFFFD, 0x00A8, 0x02C7, 0x00B8, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0xFFFD, 0x2122, 0xFFFD, 0x203A, 0xFFFD, 0x00AF, 0x02DB, 0xFFFD, + 0x00A0, 0xFFFD, 0x00A2, 0x00A3, 0x00A4, 0xFFFD, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9} }, + { "CP 1258", 2258, + { 0x20AC, 0xFFFD, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0xFFFD, 0x2039, 0x0152, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0xFFFD, 0x203A, 0x0153, 0xFFFD, 0xFFFD, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x0300, 0x00CD, 0x00CE, 0x00CF, + 0x0110, 0x00D1, 0x0309, 0x00D3, 0x00D4, 0x01A0, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x01AF, 0x0303, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0301, 0x00ED, 0x00EE, 0x00EF, + 0x0111, 0x00F1, 0x0323, 0x00F3, 0x00F4, 0x01A1, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x01B0, 0x20AB, 0x00FF} }, + + // this one is generated from the charmap file located in /usr/share/i18n/charmaps + // on most Linux distributions. The thai character set tis620 is byte by byte equivalent + // to iso8859-11, so we name it 8859-11 here, but recognise the name tis620 too. + + // $ for A in 8 9 A B C D E F ; do for B in 0 1 2 3 4 5 6 7 8 9 A B C D E F ; do echo x${A}${B} 0xFFFD ; done ; done > /tmp/digits ; ( cut -c25- < TIS-620 ; cat /tmp/digits ) | awk '/^x[89ABCDEF]/{ print $1, $2 }' | sed -e 's/<U/0x/' -e 's/>//' | sort | uniq -w4 | cut -c5- | paste '-d ' - - - - - - - - | sed -e 's/ /, /g' -e 's/$/,/' -e '$ s/,$/} },/' -e '1 s/^/{ /' > ~/tmp/tis-620 + { "ISO 8859-11", 2259, // Thai character set mib enum taken from tis620 (which is byte by byte equivalent) + { 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, + 0xFFFD, 0x0E01, 0x0E02, 0x0E03, 0x0E04, 0x0E05, 0x0E06, 0x0E07, + 0x0E08, 0x0E09, 0x0E0A, 0x0E0B, 0x0E0C, 0x0E0D, 0x0E0E, 0x0E0F, + 0x0E10, 0x0E11, 0x0E12, 0x0E13, 0x0E14, 0x0E15, 0x0E16, 0x0E17, + 0x0E18, 0x0E19, 0x0E1A, 0x0E1B, 0x0E1C, 0x0E1D, 0x0E1E, 0x0E1F, + 0x0E20, 0x0E21, 0x0E22, 0x0E23, 0x0E24, 0x0E25, 0x0E26, 0x0E27, + 0x0E28, 0x0E29, 0x0E2A, 0x0E2B, 0x0E2C, 0x0E2D, 0x0E2E, 0x0E2F, + 0x0E30, 0x0E31, 0x0E32, 0x0E33, 0x0E34, 0x0E35, 0x0E36, 0x0E37, + 0x0E38, 0x0E39, 0x0E3A, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD, 0x0E3F, + 0x0E40, 0x0E41, 0x0E42, 0x0E43, 0x0E44, 0x0E45, 0x0E46, 0x0E47, + 0x0E48, 0x0E49, 0x0E4A, 0x0E4B, 0x0E4C, 0x0E4D, 0x0E4E, 0x0E4F, + 0x0E50, 0x0E51, 0x0E52, 0x0E53, 0x0E54, 0x0E55, 0x0E56, 0x0E57, + 0x0E58, 0x0E59, 0x0E5A, 0x0E5B, 0xFFFD, 0xFFFD, 0xFFFD, 0xFFFD} }, + + // change LAST_MIB if you add more, and edit unicodevalues in + // kernel/qpsprinter.cpp too. +}; + + +static const QSimpleTextCodec * reverseOwner = 0; +static QArray<char> * reverseMap = 0; + + +QSimpleTextCodec::QSimpleTextCodec( int i ) + : QTextCodec(), forwardIndex( i ) +{ +} + + +QSimpleTextCodec::~QSimpleTextCodec() +{ + if ( reverseOwner == this ) { + delete reverseMap; + reverseMap = 0; + reverseOwner = 0; + } +} + +// what happens if strlen(chars)<len? what happens if !chars? if len<1? +QString QSimpleTextCodec::toUnicode(const char* chars, int len) const +{ + if(len <= 0) + return QString::null; + + int clen = qstrlen(chars); + len = QMIN(len, clen); // Note: NUL ends string + + QString r; + r.setUnicode(0, len); + QChar* uc = (QChar*)r.unicode(); // const_cast + const unsigned char * c = (const unsigned char *)chars; + for( int i=0; i<len; i++ ) { + if ( c[i] > 127 ) + uc[i] = unicodevalues[forwardIndex].values[c[i]-128]; + else + uc[i] = c[i]; + } + return r; +} + + +QCString QSimpleTextCodec::fromUnicode(const QString& uc, int& len ) const +{ + if ( reverseOwner != this ) { + int m = 0; + int i = 0; + while( i < 128 ) { + if ( unicodevalues[forwardIndex].values[i] > m && + unicodevalues[forwardIndex].values[i] < 0xfffd ) + m = unicodevalues[forwardIndex].values[i]; + i++; + } + m++; + if ( !reverseMap ) + reverseMap = new QArray<char>( m ); + if ( m > (int)(reverseMap->size()) ) + reverseMap->resize( m ); + for( i = 0; i < 128 && i < m; i++ ) + (*reverseMap)[i] = (char)i; + for( ;i < m; i++ ) + (*reverseMap)[i] = '?'; + for( i=128; i<256; i++ ) { + int u = unicodevalues[forwardIndex].values[i-128]; + if ( u < m ) + (*reverseMap)[u] = (char)(unsigned char)(i); + } + reverseOwner = this; + } + if ( len <0 || len > (int)uc.length() ) + len = uc.length(); + QCString r( len+1 ); + int i = len; + int u; + const QChar* ucp = uc.unicode(); + char* rp = r.data(); + char* rmp = reverseMap->data(); + int rmsize = (int) reverseMap->size(); + while( i-- ) + { + u = ucp->unicode(); + *rp++ = u < 128 ? u : (( u < rmsize ) ? (*(rmp+u)) : '?' ); + ucp++; + } + r[len] = 0; + return r; +} + + +const char* QSimpleTextCodec::name() const +{ + return unicodevalues[forwardIndex].cs; +} + + +int QSimpleTextCodec::mibEnum() const +{ + return unicodevalues[forwardIndex].mib; +} + +int QSimpleTextCodec::heuristicNameMatch(const char* hint) const +{ + if ( hint[0]=='k' ) { + // Help people with messy fonts + if ( QCString(hint) == "koi8-1" ) + return QTextCodec::heuristicNameMatch("koi8-r")-1; + if ( QCString(hint) == "koi8-ru" ) + return QTextCodec::heuristicNameMatch("koi8-r")-1; + } else if ( hint[0] == 't' && QCString(name()) == "ISO 8859-11" ) { + // 8859-11 and tis620 are byte by bute equivalent + int i = simpleHeuristicNameMatch("tis620-0", hint); + if( !i ) + i = simpleHeuristicNameMatch("tis-620", hint); + if( i ) return i; + } + return QTextCodec::heuristicNameMatch(hint); +} + +int QSimpleTextCodec::heuristicContentMatch(const char* chars, int len) const +{ + if ( len<1 || !chars ) + return -1; + int i = 0; + const uchar * c = (const unsigned char *)chars; + int r = 0; + while( i<len && c && *c ) { + if ( *c >= 128 ) { + if ( unicodevalues[forwardIndex].values[(*c)-128] == 0xfffd ) + return -1; + } + if ( (*c >= ' ' && *c < 127) || + *c == '\n' || *c == '\t' || *c == '\r' ) + r++; + i++; + c++; + } + if ( mibEnum()==4 ) + r+=1; + return r; +} + + +#endif // QT_NO_CODECS + +class QLatin1Codec: public QTextCodec +{ +public: + QLatin1Codec(); + ~QLatin1Codec(); + + QString toUnicode(const char* chars, int len) const; + QCString fromUnicode(const QString& uc, int& lenInOut ) const; + + const char* name() const; + int mibEnum() const; + + int heuristicContentMatch(const char* chars, int len) const; + + int heuristicNameMatch(const char* hint) const; + +private: + int forwardIndex; +}; + + +QLatin1Codec::QLatin1Codec() + : QTextCodec() +{ +} + + +QLatin1Codec::~QLatin1Codec() +{ +} + +// what happens if strlen(chars)<len? what happens if !chars? if len<1? +QString QLatin1Codec::toUnicode(const char* chars, int len) const +{ + if(len <= 0) + return QString::null; + + return QString::fromLatin1(chars, len); +} + + +QCString QLatin1Codec::fromUnicode(const QString& uc, int& len ) const +{ + if ( len <0 || len > (int)uc.length() ) + len = uc.length(); + QCString r( len+1 ); + int i = 0; + const QChar *ch = uc.unicode(); + while ( i < len ) { + r[i] = ch->row() ? '?' : ch->cell(); + i++; + ch++; + } + r[len] = 0; + return r; +} + + +const char* QLatin1Codec::name() const +{ + return "ISO 8859-1"; +} + + +int QLatin1Codec::mibEnum() const +{ + return 4; +} + +int QLatin1Codec::heuristicNameMatch(const char* hint) const +{ + return QTextCodec::heuristicNameMatch(hint); +} + +int QLatin1Codec::heuristicContentMatch(const char* chars, int len) const +{ + if ( len<1 || !chars ) + return -1; + int i = 0; + const uchar * c = (const unsigned char *)chars; + int r = 0; + while( i<len && c && *c ) { + if ( *c >= 0x80 && *c < 0xa0 ) + return -1; + if ( (*c >= ' ' && *c < 127) || + *c == '\n' || *c == '\t' || *c == '\r' ) + r++; + i++; + c++; + } + return r; +} + + +static void setupBuiltinCodecs() +{ + (void)new QLatin1Codec; + +#ifndef QT_NO_CODECS + int i = 0; + do { + (void)new QSimpleTextCodec( i ); + } while( unicodevalues[i++].mib != LAST_MIB ); + + (void)new QEucJpCodec; + (void)new QSjisCodec; + (void)new QJisCodec; + (void)new QEucKrCodec; + (void)new QGbkCodec; + (void)new QBig5Codec; + (void)new QUtf8Codec; + (void)new QUtf16Codec; + (void)new QHebrewCodec; + (void)new QArabicCodec; + (void)new QTsciiCodec; +#endif // QT_NO_CODECS +} + +#endif // QT_NO_TEXTCODEC diff --git a/trunk/qtools/qtextcodec.h b/trunk/qtools/qtextcodec.h new file mode 100644 index 0000000..18ece20 --- /dev/null +++ b/trunk/qtools/qtextcodec.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** +** Definition of QTextCodec class +** +** Created : 981015 +** +** Copyright (C) 1998-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QTEXTCODEC_H +#define QTEXTCODEC_H + +#ifndef QT_H +#include "qstring.h" +#endif // QT_H + +#ifndef QT_NO_TEXTCODEC + +class QTextCodec; +class QIODevice; + +class Q_EXPORT QTextEncoder { +public: + virtual ~QTextEncoder(); + virtual QCString fromUnicode(const QString& uc, int& lenInOut) = 0; +}; + +class Q_EXPORT QTextDecoder { +public: + virtual ~QTextDecoder(); + virtual QString toUnicode(const char* chars, int len) = 0; +}; + +class Q_EXPORT QTextCodec { +public: + virtual ~QTextCodec(); + +#ifndef QT_NO_CODECS + static QTextCodec* loadCharmap(QIODevice*); + static QTextCodec* loadCharmapFile(QString filename); +#endif + static QTextCodec* codecForMib(int mib); + static QTextCodec* codecForName(const char* hint, int accuracy=0); + static QTextCodec* codecForContent(const char* chars, int len); + static QTextCodec* codecForIndex(int i); + static QTextCodec* codecForLocale(); + + static void deleteAllCodecs(); + + static const char* locale(); + + virtual const char* name() const = 0; + virtual int mibEnum() const = 0; + + virtual QTextDecoder* makeDecoder() const; + virtual QTextEncoder* makeEncoder() const; + + virtual QString toUnicode(const char* chars, int len) const; + virtual QCString fromUnicode(const QString& uc, int& lenInOut) const; + + QCString fromUnicode(const QString& uc) const; + QString toUnicode(const QByteArray&, int len) const; + QString toUnicode(const QByteArray&) const; + QString toUnicode(const char* chars) const; + virtual bool canEncode( QChar ) const; + virtual bool canEncode( const QString& ) const; + + virtual int heuristicContentMatch(const char* chars, int len) const = 0; + virtual int heuristicNameMatch(const char* hint) const; + +protected: + QTextCodec(); + static int simpleHeuristicNameMatch(const char* name, const char* hint); +}; +#endif // QT_NO_TEXTCODEC +#endif // QTEXTCODEC_H diff --git a/trunk/qtools/qtextstream.cpp b/trunk/qtools/qtextstream.cpp new file mode 100644 index 0000000..6686f81 --- /dev/null +++ b/trunk/qtools/qtextstream.cpp @@ -0,0 +1,2237 @@ +/**************************************************************************** +** +** +** Implementation of QTextStream class +** +** Created : 940922 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#include "qtextstream.h" + +#ifndef QT_NO_TEXTSTREAM +#include "qtextcodec.h" +#include "qregexp.h" +#include "qbuffer.h" +#include "qfile.h" +#include <stdio.h> +#include <ctype.h> +#include <stdlib.h> + +#if defined(_OS_WIN32_) +#include <windows.h> +#endif + +// NOT REVISED +/*! + \class QTextStream qtextstream.h + + \brief The QTextStream class provides basic functions for reading and + writing text using a QIODevice. + + \ingroup io + + \define endl + \define bin + \define oct + \define dec + \define hex + \define flush + \define ws + + The text stream class has a functional interface that is very + similar to that of the standard C++ iostream class. The difference + between iostream and QTextStream is that our stream operates on a + QIODevice, which is easily subclassed, while iostream operates on + FILE * pointers, which can not be subclassed. + + Qt provides several global functions similar to the ones in iostream: + <ul> + <li> \c bin sets the QTextStream to read/write binary numbers + <li> \c oct sets the QTextStream to read/write octal numbers + <li> \c dec sets the QTextStream to read/write decimal numbers + <li> \c hex sets the QTextStream to read/write hexadecimal numbers + <li> \c endl forces a line break + <li> \c flush forces the QIODevice to flush any buffered data + <li> \c ws eats any available white space (on input) + <li> \c reset resets the QTextStream to its default mode (see reset()). + </ul> + + \warning By default, QTextStream will automatically detect whether + integers in the stream are in decimal, octal, hexadecimal or binary + format when reading from the stream. In particular, a leading '0' + signifies octal, ie. the sequence "0100" will be interpreted as + 64. + + The QTextStream class reads and writes text and it is not + appropriate for dealing with binary data (but QDataStream is). + + By default output of Unicode text (ie. QString) is done using the + local 8-bit encoding. This can be changed using the setEncoding() + method. For input, the QTextStream will auto-detect standard + Unicode "byte order marked" text files, but otherwise the local + 8-bit encoding is used. + + \sa QDataStream +*/ + +/* + \class QTSManip qtextstream.h + + \brief The QTSManip class is an internal helper class for the + QTextStream. + + It is generally a very bad idea to use this class directly in + application programs. + + \internal + + This class makes it possible to give the QTextStream function objects + with arguments, like this: + \code + QTextStream cout( stdout, IO_WriteOnly ); + cout << setprecision( 8 ); // QTSManip used here! + cout << 3.14159265358979323846; + \endcode + + The setprecision() function returns a QTSManip object. + The QTSManip object contains a pointer to a member function in + QTextStream and an integer argument. + When serializing a QTSManip into a QTextStream, the function + is executed with the argument. +*/ + +/*! \fn QTSManip::QTSManip (QTSMFI m, int a) + + Constructs a QTSManip object which will call \a m (a member function + in QTextStream which accepts a single int) with argument \a a when + QTSManip::exec() is called. Used internally in e.g. endl: + + \code + s << "some text" << endl << "more text"; + \endcode +*/ + +/*! \fn void QTSManip::exec (QTextStream& s) + + Calls the member function specified in the constructor, for object + \a s. Used internally in e.g. endl: + + \code + s << "some text" << endl << "more text"; + \endcode +*/ + + +/***************************************************************************** + QTextStream member functions + *****************************************************************************/ + +#if defined(CHECK_STATE) +#undef CHECK_STREAM_PRECOND +#define CHECK_STREAM_PRECOND if ( !dev ) { \ + qWarning( "QTextStream: No device" ); \ + return *this; } +#else +#define CHECK_STREAM_PRECOND +#endif + + +#define I_SHORT 0x0010 +#define I_INT 0x0020 +#define I_LONG 0x0030 +#define I_TYPE_MASK 0x00f0 + +#define I_BASE_2 QTS::bin +#define I_BASE_8 QTS::oct +#define I_BASE_10 QTS::dec +#define I_BASE_16 QTS::hex +#define I_BASE_MASK (QTS::bin | QTS::oct | QTS::dec | QTS::hex) + +#define I_SIGNED 0x0100 +#define I_UNSIGNED 0x0200 +#define I_SIGN_MASK 0x0f00 + + +static const QChar QEOF = QChar((ushort)0xffff); //guaranteed not to be a character. + +const int QTextStream::basefield = I_BASE_MASK; +const int QTextStream::adjustfield = ( QTextStream::left | + QTextStream::right | + QTextStream::internal ); +const int QTextStream::floatfield = ( QTextStream::scientific | + QTextStream::fixed ); + + +class QTextStreamPrivate { +public: +#ifndef QT_NO_TEXTCODEC + QTextStreamPrivate() : decoder( 0 ), sourceType( NotSet ) {} + ~QTextStreamPrivate() { delete decoder; } + QTextDecoder *decoder; //??? +#else + QTextStreamPrivate() : sourceType( NotSet ) {} + ~QTextStreamPrivate() { } +#endif + QString ungetcBuf; + + enum SourceType { NotSet, IODevice, String, ByteArray, File }; + SourceType sourceType; +}; + + +// skips whitespace and returns the first non-whitespace character +QChar QTextStream::eat_ws() +{ + QChar c; + do { c = ts_getc(); } while ( c != QEOF && ts_isspace(c) ); + return c; +} + +void QTextStream::init() +{ + // ### ungetcBuf = QEOF; + dev = 0; // no device set + fstrm = owndev = FALSE; + mapper = 0; + d = new QTextStreamPrivate; + doUnicodeHeader = TRUE; //default to autodetect + latin1 = TRUE; // ### should use local? + internalOrder = QChar::networkOrdered(); //default to network order +} + +/*! + Constructs a data stream that has no IO device. +*/ + +QTextStream::QTextStream() +{ + init(); + setEncoding( Locale ); //### + reset(); + d->sourceType = QTextStreamPrivate::NotSet; +} + +/*! + Constructs a text stream that uses the IO device \a iod. +*/ + +QTextStream::QTextStream( QIODevice *iod ) +{ + init(); + setEncoding( Locale ); //### + dev = iod; // set device + reset(); + d->sourceType = QTextStreamPrivate::IODevice; +} + +// TODO: use special-case handling of this case in QTextStream, and +// simplify this class to only deal with QChar or QString data. +class QStringBuffer : public QIODevice { +public: + QStringBuffer( QString* str ); + ~QStringBuffer(); + bool open( int m ); + void close(); + void flush(); + uint size() const; + int at() const; + bool at( int pos ); + int readBlock( char *p, uint len ); + int writeBlock( const char *p, uint len ); + int getch(); + int putch( int ch ); + int ungetch( int ch ); +protected: + QString* s; + +private: // Disabled copy constructor and operator= + QStringBuffer( const QStringBuffer & ); + QStringBuffer &operator=( const QStringBuffer & ); +}; + + +QStringBuffer::QStringBuffer( QString* str ) +{ + s = str; +} + +QStringBuffer::~QStringBuffer() +{ +} + + +bool QStringBuffer::open( int m ) +{ + if ( !s ) { +#if defined(CHECK_STATE) + qWarning( "QStringBuffer::open: No string" ); +#endif + return FALSE; + } + if ( isOpen() ) { // buffer already open +#if defined(CHECK_STATE) + qWarning( "QStringBuffer::open: Buffer already open" ); +#endif + return FALSE; + } + setMode( m ); + if ( m & IO_Truncate ) { // truncate buffer + s->truncate( 0 ); + } + if ( m & IO_Append ) { // append to end of buffer + ioIndex = s->length()*sizeof(QChar); + } else { + ioIndex = 0; + } + setState( IO_Open ); + setStatus( 0 ); + return TRUE; +} + +void QStringBuffer::close() +{ + if ( isOpen() ) { + setFlags( IO_Direct ); + ioIndex = 0; + } +} + +void QStringBuffer::flush() +{ +} + +uint QStringBuffer::size() const +{ + return s ? s->length()*sizeof(QChar) : 0; +} + +int QStringBuffer::at() const +{ + return ioIndex; +} + +bool QStringBuffer::at( int pos ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { + qWarning( "QStringBuffer::at: Buffer is not open" ); + return FALSE; + } +#endif + if ( (uint)pos >= s->length()*2 ) { +#if defined(CHECK_RANGE) + qWarning( "QStringBuffer::at: Index %d out of range", pos ); +#endif + return FALSE; + } + ioIndex = pos; + return TRUE; +} + + +int QStringBuffer::readBlock( char *p, uint len ) +{ +#if defined(CHECK_STATE) + CHECK_PTR( p ); + if ( !isOpen() ) { // buffer not open + qWarning( "QStringBuffer::readBlock: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QStringBuffer::readBlock: Read operation not permitted" ); + return -1; + } +#endif + if ( (uint)ioIndex + len > s->length()*sizeof(QChar) ) { + // overflow + if ( (uint)ioIndex >= s->length()*sizeof(QChar) ) { + setStatus( IO_ReadError ); + return -1; + } else { + len = s->length()*2 - (uint)ioIndex; + } + } + memcpy( p, ((const char*)(s->unicode()))+ioIndex, len ); + ioIndex += len; + return len; +} + +int QStringBuffer::writeBlock( const char *p, uint len ) +{ +#if defined(CHECK_NULL) + if ( p == 0 && len != 0 ) + qWarning( "QStringBuffer::writeBlock: Null pointer error" ); +#endif +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QStringBuffer::writeBlock: Buffer not open" ); + return -1; + } + if ( !isWritable() ) { // writing not permitted + qWarning( "QStringBuffer::writeBlock: Write operation not permitted" ); + return -1; + } + if ( ioIndex&1 ) { + qWarning( "QStringBuffer::writeBlock: non-even index - non Unicode" ); + return -1; + } + if ( len&1 ) { + qWarning( "QStringBuffer::writeBlock: non-even length - non Unicode" ); + return -1; + } +#endif + s->replace(ioIndex/2, len/2, (QChar*)p, len/2); + ioIndex += len; + return len; +} + +int QStringBuffer::getch() +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QStringBuffer::getch: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QStringBuffer::getch: Read operation not permitted" ); + return -1; + } +#endif + if ( (uint)ioIndex >= s->length()*2 ) { // overflow + setStatus( IO_ReadError ); + return -1; + } + return *((char*)s->unicode() + ioIndex++); +} + +int QStringBuffer::putch( int ch ) +{ + char c = ch; + if ( writeBlock(&c,1) < 0 ) + return -1; + else + return ch; +} + +int QStringBuffer::ungetch( int ch ) +{ +#if defined(CHECK_STATE) + if ( !isOpen() ) { // buffer not open + qWarning( "QStringBuffer::ungetch: Buffer not open" ); + return -1; + } + if ( !isReadable() ) { // reading not permitted + qWarning( "QStringBuffer::ungetch: Read operation not permitted" ); + return -1; + } +#endif + if ( ch != -1 ) { // something to do with eof + if ( ioIndex ) + ioIndex--; + else + ch = -1; + } + return ch; +} + + +/*! + Constructs a text stream that operates on a Unicode QString through an + internal device. + + If you set an encoding or codec with setEncoding() or setCodec(), this + setting is ignored for text streams that operate on QString. + + Example: + \code + QString str; + QTextStream ts( &str, IO_WriteOnly ); + ts << "pi = " << 3.14; // str == "pi = 3.14" + \endcode + + Writing data to the text stream will modify the contents of the string. + The string will be expanded when data is written beyond the end of the + string. Note that the string will not be truncated: + \code + QString str = "pi = 3.14"; + QTextStream ts( &str, IO_WriteOnly ); + ts << "2+2 = " << 2+2; // str == "2+2 = 414" + \endcode + + Note that since QString is Unicode, you should not use readRawBytes() + or writeRawBytes() on such a stream. +*/ + +QTextStream::QTextStream( QString* str, int filemode ) +{ + // TODO: optimize for this case as it becomes more common + // (see QStringBuffer above) + init(); + dev = new QStringBuffer( str ); + ((QStringBuffer *)dev)->open( filemode ); + owndev = TRUE; + setEncoding(RawUnicode); + reset(); + d->sourceType = QTextStreamPrivate::String; +} + +/*! \obsolete + + This constructor is equivalent to the constructor taking a QString* + parameter. +*/ + +QTextStream::QTextStream( QString& str, int filemode ) +{ + init(); + dev = new QStringBuffer( &str ); + ((QStringBuffer *)dev)->open( filemode ); + owndev = TRUE; + setEncoding(RawUnicode); + reset(); + d->sourceType = QTextStreamPrivate::String; +} + +/*! + Constructs a text stream that operates on a byte array through an + internal QBuffer device. + + Example: + \code + QByteArray array; + QTextStream ts( array, IO_WriteOnly ); + ts << "pi = " << 3.14 << '\0'; // array == "pi = 3.14" + \endcode + + Writing data to the text stream will modify the contents of the array. + The array will be expanded when data is written beyond the end of the + string. + + Same example, using a QBuffer: + \code + QByteArray array; + QBuffer buf( array ); + buf.open( IO_WriteOnly ); + QTextStream ts( &buf ); + ts << "pi = " << 3.14 << '\0'; // array == "pi = 3.14" + buf.close(); + \endcode +*/ + +QTextStream::QTextStream( QByteArray a, int mode ) +{ + init(); + dev = new QBuffer( a ); + ((QBuffer *)dev)->open( mode ); + owndev = TRUE; + setEncoding( Latin1 ); //### Locale??? + reset(); + d->sourceType = QTextStreamPrivate::ByteArray; +} + +/*! + Constructs a text stream that operates on an existing file handle \e fh + through an internal QFile device. + + Example: + \code + QTextStream cout( stdout, IO_WriteOnly ); + QTextStream cin ( stdin, IO_ReadOnly ); + QTextStream cerr( stderr, IO_WriteOnly ); + \endcode +*/ + +QTextStream::QTextStream( FILE *fh, int mode ) +{ + init(); + setEncoding( Locale ); //### + dev = new QFile; + ((QFile *)dev)->open( mode, fh ); + fstrm = owndev = TRUE; + reset(); + d->sourceType = QTextStreamPrivate::File; +} + +/*! + Destructs the text stream. + + The destructor does not affect the current IO device. +*/ + +QTextStream::~QTextStream() +{ + if ( owndev ) + delete dev; + delete d; +} + +/*! + Positions the read pointer at the first non-whitespace character. +*/ +void QTextStream::skipWhiteSpace() +{ + ts_ungetc( eat_ws() ); +} + + +/*! + \fn Encoding QTextStream::encoding() const + + Returns the encoding mode of the stream. + + \sa setEncoding() +*/ + +/*! + Tries to read len characters from the stream and stores them in \a buf. + Returns the number of characters really read. + Attention: There will no QEOF appended if the read reaches the end of + the file. EOF is reached when the return value does not equal \a len. +*/ +uint QTextStream::ts_getbuf( QChar* buf, uint len ) +{ + if( len<1 ) + return 0; + + uint rnum=0; // the number of QChars really read + + if ( d && d->ungetcBuf.length() ) { + while( rnum < len && rnum < d->ungetcBuf.length() ) { + buf[rnum] = d->ungetcBuf.constref(rnum); + rnum++; + } + d->ungetcBuf = d->ungetcBuf.mid( rnum ); + if ( rnum >= len ) + return rnum; + } + + // we use dev->ungetch() for one of the bytes of the unicode + // byte-order mark, but a local unget hack for the other byte: + int ungetHack = EOF; + + if ( doUnicodeHeader ) { + doUnicodeHeader = FALSE; //only at the top + int c1 = dev->getch(); + if ( c1 == EOF ) + return rnum; + int c2 = dev->getch(); + if ( c1 == 0xfe && c2 == 0xff ) { + mapper = 0; + latin1 = FALSE; + internalOrder = QChar::networkOrdered(); //network order + } else if ( c1 == 0xff && c2 == 0xfe ) { + mapper = 0; + latin1 = FALSE; + internalOrder = !QChar::networkOrdered(); //reverse network order + } else { + if ( c2 != EOF ) { + dev->ungetch( c2 ); + ungetHack = c1; + } else { + dev->ungetch( c1 ); + // note that a small possible bug might hide here + // here, if only the first byte of a file has made it + // so far, and that first byte is half of the + // byte-order mark, then the utfness will not be + // detected. whether or not this is a bug depends on + // taste. I can't really decide. + } + } + } + +#ifndef QT_NO_TEXTCODEC + if ( mapper ) { + bool shortRead = FALSE; + if ( !d->decoder ) + d->decoder = mapper->makeDecoder(); + while( rnum < len ) { + QString s; + bool readBlock = !( len == 1+rnum ); + while ( TRUE ) { + // for efficiency: normally read a whole block + if ( readBlock ) { + // guess buffersize; this may be wrong (too small or too + // big). But we can handle this (either iterate reading + // or use ungetcBuf). + // Note that this might cause problems for codecs where + // one byte can result in >1 Unicode Characters if bytes + // are written to the stream in the meantime (loss of + // synchronicity). + uint rlen = len - rnum; + char *cbuf = new char[ rlen ]; + if ( ungetHack != EOF ) { + rlen = 1+dev->readBlock( cbuf+1, rlen-1 ); + cbuf[0] = (char)ungetHack; + ungetHack = EOF; + } else { + rlen = dev->readBlock( cbuf, rlen ); + } + s += d->decoder->toUnicode( cbuf, rlen ); + delete[] cbuf; + // use buffered reading only for the first time, because we + // have to get the stream synchronous again (this is easier + // with single character reading) + readBlock = FALSE; + } + // get stream (and codec) in sync + int c; + if ( ungetHack == EOF ) { + c = dev->getch(); + } else { + c = ungetHack; + ungetHack = EOF; + } + if ( c == EOF ) { + shortRead = TRUE; + break; + } + char b = c; + uint lengthBefore = s.length(); + s += d->decoder->toUnicode( &b, 1 ); + if ( s.length() > lengthBefore ) + break; // it seems we are in sync now + } + uint i = 0; + while( rnum < len && i < s.length() ) + buf[rnum++] = s.constref(i++); + if ( s.length() > i ) + // could be = but append is clearer + d->ungetcBuf.append( s.mid( i ) ); + if ( shortRead ) + return rnum; + } + } else +#endif + if ( latin1 ) { + if ( len == 1+rnum ) { + // use this method for one character because it is more efficient + // (arnt doubts whether it makes a difference, but lets it stand) + int c = (ungetHack == EOF) ? dev->getch() : ungetHack; + if ( c != EOF ) + buf[rnum++] = (char)c; + } else { + if ( ungetHack != EOF ) { + buf[rnum++] = (char)ungetHack; + ungetHack = EOF; + } + char *cbuf = new char[len - rnum]; + while ( !dev->atEnd() && rnum < len ) { + uint rlen = len - rnum; + rlen = dev->readBlock( cbuf, rlen ); + uint i = 0; + while( i < rlen ) + buf[rnum++] = cbuf[i++]; + } + delete[] cbuf; + } + } else { // UCS-2 or UTF-16 + if ( len == 1+rnum ) { + int c1 = (ungetHack == EOF) ? dev->getch() : ungetHack; + if ( c1 == EOF ) + return rnum; + int c2 = dev->getch(); + if ( c2 == EOF ) + return rnum; + if ( isNetworkOrder() ) + buf[rnum++] = QChar( c2, c1 ); + else + buf[rnum++] = QChar( c1, c2 ); + } else { + char *cbuf = new char[ 2*( len - rnum ) ]; // for paranoids: overflow possible + while ( !dev->atEnd() && rnum < len ) { + uint rlen = 2 * ( len-rnum ); + if ( ungetHack != EOF ) { + rlen = 1+dev->readBlock( cbuf+1, rlen-1 ); + cbuf[0] = (char)ungetHack; + ungetHack = EOF; + } else { + rlen = dev->readBlock( cbuf, rlen ); + } + // We can't use an odd number of bytes, so put it back. But + // do it only if we are capable of reading more -- normally + // there should not be an odd number, but the file might be + // truncated or not in UTF-16... + if ( (rlen & 1) == 1 ) + if ( !dev->atEnd() ) + dev->ungetch( cbuf[--rlen] ); + uint i = 0; + if ( isNetworkOrder() ) { + while( i < rlen ) { + buf[rnum++] = QChar( cbuf[i+1], cbuf[i] ); + i+=2; + } + } else { + while( i < rlen ) { + buf[rnum++] = QChar( cbuf[i], cbuf[i+1] ); + i+=2; + } + } + } + delete[] cbuf; + } + } + return rnum; +} + + +/*! + Puts one character to the stream. +*/ +void QTextStream::ts_putc( QChar c ) +{ +#ifndef QT_NO_TEXTCODEC + if ( mapper ) { + int len = 1; + QString s = c; + QCString block = mapper->fromUnicode( s, len ); + dev->writeBlock( block, len ); + } else +#endif + if ( latin1 ) { + if( c.row() ) + dev->putch( '?' ); //######unknown character??? + else + dev->putch( c.cell() ); + } else { + if ( doUnicodeHeader ) { + doUnicodeHeader = FALSE; + ts_putc( QChar::byteOrderMark ); + } + if ( internalOrder ) { + dev->writeBlock( (char*)&c, sizeof(QChar) ); + } else if ( isNetworkOrder() ) { + dev->putch(c.row()); + dev->putch(c.cell()); + } else { + dev->putch(c.cell()); + dev->putch(c.row()); + } + } +} + +/*! + Puts one character to the stream. +*/ +void QTextStream::ts_putc(int ch) +{ + ts_putc(QChar((ushort)ch)); +} + +bool QTextStream::ts_isdigit(QChar c) +{ + return c.isDigit(); +} + +bool QTextStream::ts_isspace( QChar c ) +{ + return c.isSpace(); +} + +void QTextStream::ts_ungetc( QChar c ) +{ + if ( c.unicode() == 0xffff ) + return; + + d->ungetcBuf.prepend( c ); +} + + + +/*! + Reads \e len bytes from the stream into \e e s and returns a reference to + the stream. + + The buffer \e s must be preallocated. + + Note that no encoding is done by this function. + + \warning The behaviour of this function is undefined unless the + stream's encoding is set to Unicode or Latin1. + + \sa QIODevice::readBlock() +*/ + +QTextStream &QTextStream::readRawBytes( char *s, uint len ) +{ + dev->readBlock( s, len ); + return *this; +} + +/*! + Writes the \e len bytes from \e s to the stream and returns a reference to + the stream. + + Note that no encoding is done by this function. + + \sa QIODevice::writeBlock() +*/ + +QTextStream &QTextStream::writeRawBytes( const char* s, uint len ) +{ + dev->writeBlock( s, len ); + return *this; +} + + +QTextStream &QTextStream::writeBlock( const char* p, uint len ) +{ + if ( doUnicodeHeader ) { + doUnicodeHeader = FALSE; + if ( !mapper && !latin1 ) + ts_putc( QChar::byteOrderMark ); + } + //All QCStrings and const char* are defined to be in Latin1 + if ( !mapper && latin1 ) { + dev->writeBlock( p, len ); + } else if ( !mapper && internalOrder ) { + QChar *u = new QChar[len]; + for (uint i=0; i<len; i++) + u[i] = p[i]; + dev->writeBlock( (char*)u, len*sizeof(QChar) ); + delete [] u; + } else { + for (uint i=0; i<len; i++) + ts_putc( (uchar)p[i] ); + } + return *this; +} + +QTextStream &QTextStream::writeBlock( const QChar* p, uint len ) +{ + if ( !mapper && !latin1 && internalOrder ) { + if ( doUnicodeHeader ) { + doUnicodeHeader = FALSE; + ts_putc( QChar::byteOrderMark ); + } + dev->writeBlock( (char*)p, sizeof(QChar)*len ); + } else { + for (uint i=0; i<len; i++) + ts_putc( p[i] ); + } + return *this; +} + + + +/*! + Resets the text stream. + + <ul> + <li> All flags are set to 0. + <li> The field width is set to 0. + <li> The fill character is set to ' ' (space). + <li> The precision is set to 6. + </ul> + + \sa setf(), width(), fill(), precision() +*/ + +void QTextStream::reset() +{ + fflags = 0; + fwidth = 0; + fillchar = ' '; + fprec = 6; +} + + +/*! + \fn QIODevice *QTextStream::device() const + Returns the IO device currently set. + \sa setDevice(), unsetDevice() +*/ + +/*! + Sets the IO device to \a iod. + \sa device(), unsetDevice() +*/ + +void QTextStream::setDevice( QIODevice *iod ) +{ + if ( owndev ) { + delete dev; + owndev = FALSE; + } + dev = iod; + d->sourceType = QTextStreamPrivate::IODevice; +} + +/*! + Unsets the IO device. Equivalent to setDevice( 0 ). + \sa device(), setDevice() +*/ + +void QTextStream::unsetDevice() +{ + setDevice( 0 ); + d->sourceType = QTextStreamPrivate::NotSet; +} + +/*! + \fn bool QTextStream::atEnd() const + Returns TRUE if the IO device has reached the end position (end of + stream or file) or if there is no IO device set. + + Returns FALSE if the current position of the read/write head of the IO + device is somewhere before the end position. + + \sa QIODevice::atEnd() +*/ + +/*!\fn bool QTextStream::eof() const + + \obsolete + + This function has been renamed to atEnd(). + + \sa QIODevice::atEnd() +*/ + +/***************************************************************************** + QTextStream read functions + *****************************************************************************/ + + +/*! + Reads a \c char from the stream and returns a reference to the stream. + Note that whitespace is skipped. +*/ + +QTextStream &QTextStream::operator>>( char &c ) +{ + CHECK_STREAM_PRECOND + c = eat_ws(); + return *this; +} + +/*! + Reads a \c char from the stream and returns a reference to the stream. + Note that whitespace is \e not skipped. +*/ + +QTextStream &QTextStream::operator>>( QChar &c ) +{ + CHECK_STREAM_PRECOND + c = ts_getc(); + return *this; +} + + +ulong QTextStream::input_bin() +{ + ulong val = 0; + QChar ch = eat_ws(); + int dv = ch.digitValue(); + while ( dv == 0 || dv == 1 ) { + val = ( val << 1 ) + dv; + ch = ts_getc(); + dv = ch.digitValue(); + } + if ( ch != QEOF ) + ts_ungetc( ch ); + return val; +} + +ulong QTextStream::input_oct() +{ + ulong val = 0; + QChar ch = eat_ws(); + int dv = ch.digitValue(); + while ( dv >= 0 && dv <= 7 ) { + val = ( val << 3 ) + dv; + ch = ts_getc(); + dv = ch.digitValue(); + } + if ( dv == 8 || dv == 9 ) { + while ( ts_isdigit(ch) ) + ch = ts_getc(); + } + if ( ch != QEOF ) + ts_ungetc( ch ); + return val; +} + +ulong QTextStream::input_dec() +{ + ulong val = 0; + QChar ch = eat_ws(); + int dv = ch.digitValue(); + while ( ts_isdigit(ch) ) { + val = val * 10 + dv; + ch = ts_getc(); + dv = ch.digitValue(); + } + if ( ch != QEOF ) + ts_ungetc( ch ); + return val; +} + +ulong QTextStream::input_hex() +{ + ulong val = 0; + QChar ch = eat_ws(); + char c = ch; + while ( isxdigit(c) ) { + val <<= 4; + if ( ts_isdigit(c) ) + val += c - '0'; + else + val += 10 + tolower(c) - 'a'; + c = ch = ts_getc(); + } + if ( ch != QEOF ) + ts_ungetc( ch ); + return val; +} + +long QTextStream::input_int() +{ + long val; + QChar ch; + char c; + switch ( flags() & basefield ) { + case bin: + val = (long)input_bin(); + break; + case oct: + val = (long)input_oct(); + break; + case dec: + c = ch = eat_ws(); + if ( ch == QEOF ) { + val = 0; + } else { + if ( !(c == '-' || c == '+') ) + ts_ungetc( ch ); + if ( c == '-' ) { + ulong v = input_dec(); + if ( v ) { // ensure that LONG_MIN can be read + v--; + val = -((long)v) - 1; + } else { + val = 0; + } + } else { + val = (long)input_dec(); + } + } + break; + case hex: + val = (long)input_hex(); + break; + default: + val = 0; + c = ch = eat_ws(); + if ( c == '0' ) { // bin, oct or hex + c = ch = ts_getc(); + if ( tolower(c) == 'x' ) + val = (long)input_hex(); + else if ( tolower(c) == 'b' ) + val = (long)input_bin(); + else { // octal + ts_ungetc( ch ); + if ( c >= '0' && c <= '7' ) { + val = (long)input_oct(); + } else { + val = 0; + } + } + } else if ( ts_isdigit(ch) ) { + ts_ungetc( ch ); + val = (long)input_dec(); + } else if ( c == '-' || c == '+' ) { + ulong v = input_dec(); + if ( c == '-' ) { + if ( v ) { // ensure that LONG_MIN can be read + v--; + val = -((long)v) - 1; + } else { + val = 0; + } + } else { + val = (long)v; + } + } + } + return val; +} + +// +// We use a table-driven FSM to parse floating point numbers +// strtod() cannot be used directly since we're reading from a QIODevice +// + +double QTextStream::input_double() +{ + const int Init = 0; // states + const int Sign = 1; + const int Mantissa = 2; + const int Dot = 3; + const int Abscissa = 4; + const int ExpMark = 5; + const int ExpSign = 6; + const int Exponent = 7; + const int Done = 8; + + const int InputSign = 1; // input tokens + const int InputDigit = 2; + const int InputDot = 3; + const int InputExp = 4; + + static uchar table[8][5] = { + /* None InputSign InputDigit InputDot InputExp */ + { 0, Sign, Mantissa, Dot, 0, }, // Init + { 0, 0, Mantissa, Dot, 0, }, // Sign + { Done, Done, Mantissa, Dot, ExpMark,}, // Mantissa + { 0, 0, Abscissa, 0, 0, }, // Dot + { Done, Done, Abscissa, Done, ExpMark,}, // Abscissa + { 0, ExpSign, Exponent, 0, 0, }, // ExpMark + { 0, 0, Exponent, 0, 0, }, // ExpSign + { Done, Done, Exponent, Done, Done } // Exponent + }; + + int state = Init; // parse state + int input; // input token + + char buf[256]; + int i = 0; + QChar c = eat_ws(); + + while ( TRUE ) { + + switch ( c ) { + case '+': + case '-': + input = InputSign; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + input = InputDigit; + break; + case '.': + input = InputDot; + break; + case 'e': + case 'E': + input = InputExp; + break; + default: + input = 0; + break; + } + + state = table[state][input]; + + if ( state == 0 || state == Done || i > 250 ) { + if ( i > 250 ) { // ignore rest of digits + do { c = ts_getc(); } while ( c != QEOF && ts_isdigit(c) ); + } + if ( c != QEOF ) + ts_ungetc( c ); + buf[i] = '\0'; + char *end; + return strtod( buf, &end ); + } + + buf[i++] = c; + c = ts_getc(); + } + +#if !defined(_CC_EGG_) + return 0.0; +#endif +} + + +/*! + Reads a signed \c short integer from the stream and returns a reference to + the stream. See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( signed short &i ) +{ + CHECK_STREAM_PRECOND + i = (signed short)input_int(); + return *this; +} + + +/*! + Reads an unsigned \c short integer from the stream and returns a reference to + the stream. See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( unsigned short &i ) +{ + CHECK_STREAM_PRECOND + i = (unsigned short)input_int(); + return *this; +} + + +/*! + Reads a signed \c int from the stream and returns a reference to the + stream. See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( signed int &i ) +{ + CHECK_STREAM_PRECOND + i = (signed int)input_int(); + return *this; +} + + +/*! + Reads an unsigned \c int from the stream and returns a reference to the + stream. See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( unsigned int &i ) +{ + CHECK_STREAM_PRECOND + i = (unsigned int)input_int(); + return *this; +} + + +/*! + Reads a signed \c long int from the stream and returns a reference to the + stream. See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( signed long &i ) +{ + CHECK_STREAM_PRECOND + i = (signed long)input_int(); + return *this; +} + + +/*! + Reads an unsigned \c long int from the stream and returns a reference to the + stream. See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( unsigned long &i ) +{ + CHECK_STREAM_PRECOND + i = (unsigned long)input_int(); + return *this; +} + + +/*! + Reads a \c float from the stream and returns a reference to the stream. + See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( float &f ) +{ + CHECK_STREAM_PRECOND + f = (float)input_double(); + return *this; +} + + +/*! + Reads a \c double from the stream and returns a reference to the stream. + See flags() for an explanation of expected input format. +*/ + +QTextStream &QTextStream::operator>>( double &f ) +{ + CHECK_STREAM_PRECOND + f = input_double(); + return *this; +} + + +/*! + Reads a word from the stream and returns a reference to the stream. +*/ + +QTextStream &QTextStream::operator>>( char *s ) +{ + CHECK_STREAM_PRECOND + int maxlen = width( 0 ); + QChar c = eat_ws(); + if ( !maxlen ) + maxlen = -1; + while ( c != QEOF ) { + if ( ts_isspace(c) || maxlen-- == 0 ) { + ts_ungetc( c ); + break; + } + *s++ = c; + c = ts_getc(); + } + + *s = '\0'; + return *this; +} + +/*! + Reads a word from the stream and returns a reference to the stream. +*/ + +QTextStream &QTextStream::operator>>( QString &str ) +{ + CHECK_STREAM_PRECOND + str=QString::fromLatin1(""); + QChar c = eat_ws(); + + while ( c != QEOF ) { + if ( ts_isspace(c) ) { + ts_ungetc( c ); + break; + } + str += c; + c = ts_getc(); + } + return *this; +} + +/*! + Reads a word from the stream and returns a reference to the stream. +*/ + +QTextStream &QTextStream::operator>>( QCString &str ) +{ + CHECK_STREAM_PRECOND + QCString *dynbuf = 0; + const int buflen = 256; + char buffer[buflen]; + char *s = buffer; + int i = 0; + QChar c = eat_ws(); + + while ( c != QEOF ) { + if ( ts_isspace(c) ) { + ts_ungetc( c ); + break; + } + if ( i >= buflen-1 ) { + if ( !dynbuf ) { // create dynamic buffer + dynbuf = new QCString(buflen*2); + memcpy( dynbuf->data(), s, i ); // copy old data + } else if ( i >= (int)dynbuf->size()-1 ) { + dynbuf->resize( dynbuf->size()*2 ); + } + s = dynbuf->data(); + } + s[i++] = c; + c = ts_getc(); + } + str.resize( i+1 ); + memcpy( str.data(), s, i ); + delete dynbuf; + return *this; +} + + +/*! + Reads a line from the stream and returns a string containing the text. + + The returned string does not contain any trailing newline or carriage + return. Note that this is different from QIODevice::readLine(), which + does not strip the newline at the end of the line. + + On EOF you will get a QString that is null. On reading an empty line the + returned QString is empty but not null. + + \sa QIODevice::readLine() +*/ + +QString QTextStream::readLine() +{ +#if defined(CHECK_STATE) + if ( !dev ) { + qWarning( "QTextStream::readLine: No device" ); + return QString::null; + } +#endif + QString result( "" ); + const int buf_size = 256; + QChar c[buf_size]; + int pos = 0; + + c[pos] = ts_getc(); + if ( c[pos] == QEOF ) + return QString::null; + + while ( c[pos] != QEOF && c[pos] != '\n' ) { + pos++; + if ( pos >= buf_size ) { + result += QString( c, pos ); + pos = 0; + } + c[pos] = ts_getc(); + } + result += QString( c, pos ); + + int len = (int)result.length(); + if ( len && result[len-1] == '\r' ) + result.truncate(len-1); // (if there are two \r, let one stay) + + return result; +} + + +/*! + Reads the entire stream and returns a string containing the text. + + \sa QIODevice::readLine() +*/ + +QString QTextStream::read() +{ +#if defined(CHECK_STATE) + if ( !dev ) { + qWarning( "QTextStream::read: No device" ); + return QString::null; + } +#endif + QString result; + const uint bufsize = 512; + QChar buf[bufsize]; + uint i, num, start; + bool skipped_cr = FALSE; + + while ( 1 ) { + num = ts_getbuf(buf,bufsize); + // do a s/\r\n/\n + start = 0; + for ( i=0; i<num; i++ ) { + if ( buf[i] == '\r' ) { + // Only skip single cr's preceding lf's + if ( skipped_cr ) { + result += buf[i]; + start++; + } else { + result += QString( &buf[start], i-start ); + start = i+1; + skipped_cr = TRUE; + } + } else { + if ( skipped_cr ) { + if ( buf[i] != '\n' ) { + // Should not have skipped it + result += '\r'; + } + skipped_cr = FALSE; + } + } + } + if ( start < num ) + result += QString( &buf[start], i-start ); + if ( num != bufsize ) // if ( EOF ) + break; + } + return result; +} + + + +/***************************************************************************** + QTextStream write functions + *****************************************************************************/ + +/*! + Writes a \c char to the stream and returns a reference to the stream. + + The character \a c is assumed to be Latin1 encoded independent of the Encoding set + for the QTextStream. +*/ +QTextStream &QTextStream::operator<<( QChar c ) +{ + CHECK_STREAM_PRECOND + ts_putc( c ); + return *this; +} + +/*! + Writes a \c char to the stream and returns a reference to the stream. +*/ +QTextStream &QTextStream::operator<<( char c ) +{ + CHECK_STREAM_PRECOND + unsigned char uc = (unsigned char) c; + ts_putc( uc ); + return *this; +} + +QTextStream &QTextStream::output_int( int format, ulong n, bool neg ) +{ + static char hexdigits_lower[] = "0123456789abcdef"; + static char hexdigits_upper[] = "0123456789ABCDEF"; + CHECK_STREAM_PRECOND + char buf[76]; + register char *p; + int len; + char *hexdigits; + + switch ( flags() & I_BASE_MASK ) { + + case I_BASE_2: // output binary number + switch ( format & I_TYPE_MASK ) { + case I_SHORT: len=16; break; + case I_INT: len=sizeof(int)*8; break; + case I_LONG: len=32; break; + default: len = 0; + } + p = &buf[74]; // go reverse order + *p = '\0'; + while ( len-- ) { + *--p = (char)(n&1) + '0'; + n >>= 1; + if ( !n ) + break; + } + if ( flags() & showbase ) { // show base + *--p = (flags() & uppercase) ? 'B' : 'b'; + *--p = '0'; + } + break; + + case I_BASE_8: // output octal number + p = &buf[74]; + *p = '\0'; + do { + *--p = (char)(n&7) + '0'; + n >>= 3; + } while ( n ); + if ( flags() & showbase ) + *--p = '0'; + break; + + case I_BASE_16: // output hexadecimal number + p = &buf[74]; + *p = '\0'; + hexdigits = (flags() & uppercase) ? + hexdigits_upper : hexdigits_lower; + do { + *--p = hexdigits[(int)n&0xf]; + n >>= 4; + } while ( n ); + if ( flags() & showbase ) { + *--p = (flags() & uppercase) ? 'X' : 'x'; + *--p = '0'; + } + break; + + default: // decimal base is default + p = &buf[74]; + *p = '\0'; + if ( neg ) + n = (ulong)(-(long)n); + do { + *--p = ((int)(n%10)) + '0'; + n /= 10; + } while ( n ); + if ( neg ) + *--p = '-'; + else if ( flags() & showpos ) + *--p = '+'; + if ( (flags() & internal) && fwidth && !ts_isdigit(*p) ) { + ts_putc( *p ); // special case for internal + ++p; // padding + fwidth--; + return *this << (const char*)p; + } + } + if ( fwidth ) { // adjustment required + if ( !(flags() & left) ) { // but NOT left adjustment + len = qstrlen(p); + int padlen = fwidth - len; + if ( padlen <= 0 ) { // no padding required + writeBlock( p, len ); + } else if ( padlen < (int)(p-buf) ) { // speeds up padding + memset( p-padlen, (char)fillchar, padlen ); + writeBlock( p-padlen, padlen+len ); + } + else // standard padding + *this << (const char*)p; + } + else + *this << (const char*)p; + fwidth = 0; // reset field width + } + else + writeBlock( p, qstrlen(p) ); + return *this; +} + + +/*! + Writes a \c short integer to the stream and returns a reference to + the stream. +*/ + +QTextStream &QTextStream::operator<<( signed short i ) +{ + return output_int( I_SHORT | I_SIGNED, i, i < 0 ); +} + + +/*! + Writes an \c unsigned \c short integer to the stream and returns a reference + to the stream. +*/ + +QTextStream &QTextStream::operator<<( unsigned short i ) +{ + return output_int( I_SHORT | I_UNSIGNED, i, FALSE ); +} + + +/*! + Writes an \c int to the stream and returns a reference to + the stream. +*/ + +QTextStream &QTextStream::operator<<( signed int i ) +{ + return output_int( I_INT | I_SIGNED, i, i < 0 ); +} + + +/*! + Writes an \c unsigned \c int to the stream and returns a reference to + the stream. +*/ + +QTextStream &QTextStream::operator<<( unsigned int i ) +{ + return output_int( I_INT | I_UNSIGNED, i, FALSE ); +} + + +/*! + Writes a \c long \c int to the stream and returns a reference to + the stream. +*/ + +QTextStream &QTextStream::operator<<( signed long i ) +{ + return output_int( I_LONG | I_SIGNED, i, i < 0 ); +} + + +/*! + Writes an \c unsigned \c long \c int to the stream and returns a reference to + the stream. +*/ + +QTextStream &QTextStream::operator<<( unsigned long i ) +{ + return output_int( I_LONG | I_UNSIGNED, i, FALSE ); +} + + +/*! + Writes a \c float to the stream and returns a reference to the stream. +*/ + +QTextStream &QTextStream::operator<<( float f ) +{ + return *this << (double)f; +} + + +/*! + Writes a \c double to the stream and returns a reference to the stream. +*/ + +QTextStream &QTextStream::operator<<( double f ) +{ + CHECK_STREAM_PRECOND + char buf[64]; + char f_char; + char format[16]; + if ( (flags()&floatfield) == fixed ) + f_char = 'f'; + else if ( (flags()&floatfield) == scientific ) + f_char = (flags() & uppercase) ? 'E' : 'e'; + else + f_char = (flags() & uppercase) ? 'G' : 'g'; + register char *fs = format; // generate format string + *fs++ = '%'; // "%.<prec>l<f_char>" + *fs++ = '.'; + int prec = precision(); + if ( prec > 99 ) + prec = 99; + if ( prec >= 10 ) { + *fs++ = prec / 10 + '0'; + *fs++ = prec % 10 + '0'; + } else { + *fs++ = prec + '0'; + } + *fs++ = 'l'; + *fs++ = f_char; + *fs = '\0'; + sprintf( buf, format, f ); // convert to text + if ( fwidth ) // padding + *this << (const char*)buf; + else // just write it + writeBlock( buf, qstrlen(buf) ); + return *this; +} + + +/*! + Writes a string to the stream and returns a reference to the stream. + + The string \a s is assumed to be Latin1 encoded independent of the Encoding set + for the QTextStream. +*/ + +QTextStream &QTextStream::operator<<( const char* s ) +{ + CHECK_STREAM_PRECOND + char padbuf[48]; + uint len = qstrlen( s ); // don't write null terminator + if ( fwidth ) { // field width set + int padlen = fwidth - len; + fwidth = 0; // reset width + if ( padlen > 0 ) { + char *ppad; + if ( padlen > 46 ) { // create extra big fill buffer + ppad = new char[padlen]; + CHECK_PTR( ppad ); + } else { + ppad = padbuf; + } + memset( ppad, (char)fillchar, padlen ); // fill with fillchar + if ( !(flags() & left) ) { + writeBlock( ppad, padlen ); + padlen = 0; + } + writeBlock( s, len ); + if ( padlen ) + writeBlock( ppad, padlen ); + if ( ppad != padbuf ) // delete extra big fill buf + delete[] ppad; + return *this; + } + } + writeBlock( s, len ); + return *this; +} + +/*! + Writes \a s to the stream and returns a reference to the stream. + + The string \a s is assumed to be Latin1 encoded independent of the Encoding set + for the QTextStream. +*/ + +QTextStream &QTextStream::operator<<( const QCString & s ) +{ + return operator<<(s.data()); +} + +/*! + Writes \a s to the stream and returns a reference to the stream. +*/ + +QTextStream &QTextStream::operator<<( const QString& s ) +{ + CHECK_STREAM_PRECOND + uint len = s.length(); + QString s1 = s; + if ( fwidth ) { // field width set + if ( !(flags() & left) ) { + s1 = s.rightJustify(fwidth, (char)fillchar); + } else { + s1 = s.leftJustify(fwidth, (char)fillchar); + } + fwidth = 0; // reset width + } + writeBlock( s1.unicode(), len ); + return *this; +} + + +/*! + Writes a pointer to the stream and returns a reference to the stream. + + The \e ptr is output as an unsigned long hexadecimal integer. +*/ + +QTextStream &QTextStream::operator<<( void *ptr ) +{ + int f = flags(); + setf( hex, basefield ); + setf( showbase ); + unsetf( uppercase ); + output_int( I_LONG | I_UNSIGNED, (ulong)ptr, FALSE ); + flags( f ); + return *this; +} + + +/*! + \fn int QTextStream::flags() const + Returns the current stream flags. The default value is 0. + + The meaning of the flags are: + <ul> + <li> \e skipws - Not currently used - whitespace always skipped + <li> \e left - Numeric fields are left-aligned + <li> \e right - Not currently used (by default numerics are right aligned) + <li> \e internal - Put any padding spaces between +/- and value + <li> \e bin - Output \e and input only in binary + <li> \e oct - Output \e and input only in octal + <li> \e dec - Output \e and input only in decimal + <li> \e hex - Output \e and input only in hexadecimal + <li> \e showbase - Annotate numeric outputs with 0b, 0, or 0x if in + \e bin, \e oct, or \e hex format + <li> \e showpoint - Not currently used + <li> \e uppercase - Use 0B and 0X rather than 0b and 0x + <li> \e showpos - Show + for positive numeric values + <li> \e scientific - Use scientific notation for floating point values + <li> \e fixed - Use fixed-point notation for floating point values + </ul> + + Note that unless \e bin, \e oct, \e dec, or \e hex is set, the input base is + octal if the value starts with 0, hexadecimal if it starts with 0x, binary + if the value starts with 0b, and decimal otherwise. + + \sa setf(), unsetf() +*/ + +/*! + \fn int QTextStream::flags( int f ) + Sets the stream flags to \e f. + Returns the previous stream flags. + + \sa setf(), unsetf(), flags() +*/ + +/*! + \fn int QTextStream::setf( int bits ) + Sets the stream flag bits \e bits. + Returns the previous stream flags. + + Equivalent to <code>flags( flags() | bits )</code>. + + \sa setf(), unsetf() +*/ + +/*! + \fn int QTextStream::setf( int bits, int mask ) + Sets the stream flag bits \e bits with a bit mask \e mask. + Returns the previous stream flags. + + Equivalent to <code>flags( (flags() & ~mask) | (bits & mask) )</code>. + + \sa setf(), unsetf() +*/ + +/*! + \fn int QTextStream::unsetf( int bits ) + Clears the stream flag bits \e bits. + Returns the previous stream flags. + + Equivalent to <code>flags( flags() & ~mask )</code>. + + \sa setf() +*/ + +/*! + \fn int QTextStream::width() const + Returns the field width. The default value is 0. +*/ + +/*! + \fn int QTextStream::width( int w ) + Sets the field width to \e w. Returns the previous field width. +*/ + +/*! + \fn int QTextStream::fill() const + Returns the fill character. The default value is ' ' (space). +*/ + +/*! + \fn int QTextStream::fill( int f ) + Sets the fill character to \e f. Returns the previous fill character. +*/ + +/*! + \fn int QTextStream::precision() const + Returns the precision. The default value is 6. +*/ + +/*! + \fn int QTextStream::precision( int p ) + Sets the precision to \e p. Returns the previous precision setting. +*/ + + + /***************************************************************************** + QTextStream manipulators + *****************************************************************************/ + +QTextStream &bin( QTextStream &s ) +{ + s.setf(QTS::bin,QTS::basefield); + return s; +} + +QTextStream &oct( QTextStream &s ) +{ + s.setf(QTS::oct,QTS::basefield); + return s; +} + +QTextStream &dec( QTextStream &s ) +{ + s.setf(QTS::dec,QTS::basefield); + return s; +} + +QTextStream &hex( QTextStream &s ) +{ + s.setf(QTS::hex,QTS::basefield); + return s; +} + +QTextStream &endl( QTextStream &s ) +{ + return s << '\n'; +} + +QTextStream &flush( QTextStream &s ) +{ + if ( s.device() ) + s.device()->flush(); + return s; +} + +QTextStream &ws( QTextStream &s ) +{ + s.skipWhiteSpace(); + return s; +} + +QTextStream &reset( QTextStream &s ) +{ + s.reset(); + return s; +} + + +/*! + \class QTextIStream qtextstream.h + \brief A convenience class for input streams. + + For simple tasks, code should be simple. Hence this + class is a shorthand to avoid passing the \e mode argument + to the normal QTextStream constructors. + + This makes it easy for example, to write things like this: +\code + QString data = "123 456"; + int a, b; + QTextIStream(&data) >> a >> b; +\endcode + + \sa QTextOStream +*/ + +/*! + \fn QTextIStream::QTextIStream( QString *s ) + + Constructs a stream to read from string \a s. +*/ +/*! + \fn QTextIStream::QTextIStream( QByteArray ba ) + + Constructs a stream to read from the array \a ba. +*/ +/*! + \fn QTextIStream::QTextIStream( FILE *f ) + + Constructs a stream to read from the file \a f. +*/ + + +/*! + \class QTextOStream qtextstream.h + \brief A convenience class for output streams. + + For simple tasks, code should be simple. Hence this + class is a shorthand to avoid passing the \e mode argument + to the normal QTextStream constructors. + + This makes it easy for example, to write things like this: +\code + QString result; + QTextOStream(&result) << "pi = " << 3.14; +\endcode +*/ + +/*! + \fn QTextOStream::QTextOStream( QString *s ) + + Constructs a stream to write to string \a s. +*/ +/*! + \fn QTextOStream::QTextOStream( QByteArray ba ) + + Constructs a stream to write to the array \a ba. +*/ +/*! + \fn QTextOStream::QTextOStream( FILE *f ) + + Constructs a stream to write to the file \a f. +*/ + + + +/*! + Sets the encoding of this stream to \a e, where \a e is one of: + <ul> + <li> \c Locale Using local file format (Latin1 if locale is not + set), but autodetecting Unicode(utf16) on input. + <li> \c Unicode Using Unicode(utf16) for input and output. Output + will be written in the order most efficient for the current platform + (i.e. the order used internally in QString). + <li> \c UnicodeUTF8 Using Unicode(utf8) for input and output. If you use it + for input it will autodetect utf16 and use it instead of utf8. + <li> \c Latin1 ISO-8859-1. Will not autodetect utf16. + <li> \c UnicodeNetworkOrder Using network order Unicode(utf16) for + input and output. Useful when reading Unicode data that does not + start with the byte order marker. + <li> \c UnicodeReverse Using reverse network order Unicode(utf16) + for input and output. Useful when reading Unicode data that does not + start with the byte order marker, or writing data that should be + read by buggy Windows applications. + <li> \c RawUnicode Like Unicode, but does not write the byte order + marker, nor does it autodetect the byte order. Only useful when + writing to non-persistent storage used by a single process. + </ul> + + \c Locale and all Unicode encodings, except \c RawUnicode, will look at + the first two bytes in a input stream to determine the byte order. The + initial byte order marker will be stripped off before data is read. + + Note that this function should be called before any data is read + to/written from the stream. + \sa setCodec() +*/ + +void QTextStream::setEncoding( Encoding e ) +{ + if ( d->sourceType == QTextStreamPrivate::String ) + return; // QString does not need any encoding + switch ( e ) { + case Unicode: + mapper = 0; + latin1 = FALSE; + doUnicodeHeader = TRUE; + internalOrder = TRUE; + break; + case UnicodeUTF8: +#ifndef QT_NO_CODECS + mapper = QTextCodec::codecForMib( 106 ); + latin1 = FALSE; + doUnicodeHeader = TRUE; + internalOrder = TRUE; +#else + mapper = 0; + latin1 = TRUE; + doUnicodeHeader = TRUE; +#endif + break; + case UnicodeNetworkOrder: + mapper = 0; + latin1 = FALSE; + doUnicodeHeader = TRUE; + internalOrder = QChar::networkOrdered(); + break; + case UnicodeReverse: + mapper = 0; + latin1 = FALSE; + doUnicodeHeader = TRUE; + internalOrder = !QChar::networkOrdered(); //reverse network ordered + break; + case RawUnicode: + mapper = 0; + latin1 = FALSE; + doUnicodeHeader = FALSE; + internalOrder = TRUE; + break; + case Locale: + latin1 = TRUE; // fallback to Latin 1 +#ifndef QT_NO_TEXTCODEC + mapper = QTextCodec::codecForLocale(); +#if defined(_OS_WIN32_) + if ( GetACP() == 1252 ) + mapper = 0; // Optimized latin1 processing +#endif + if ( mapper && mapper->mibEnum() == 4 ) +#endif + mapper = 0; // Optimized latin1 processing + doUnicodeHeader = TRUE; // If it reads as Unicode, accept it + break; + case Latin1: + mapper = 0; + doUnicodeHeader = FALSE; + latin1 = TRUE; + break; + } +} + + +#ifndef QT_NO_TEXTCODEC +/*! Sets the codec for this stream to \a codec. Will not try to + autodetect Unicode. + + Note that this function should be called before any data is read + to/written from the stream. + + \sa setEncoding() +*/ + +void QTextStream::setCodec( QTextCodec *codec ) +{ + if ( d->sourceType == QTextStreamPrivate::String ) + return; // QString does not need any codec + mapper = codec; + doUnicodeHeader = FALSE; +} +#endif + +#endif // QT_NO_TEXTSTREAM diff --git a/trunk/qtools/qtextstream.h b/trunk/qtools/qtextstream.h new file mode 100644 index 0000000..c5f5ba1 --- /dev/null +++ b/trunk/qtools/qtextstream.h @@ -0,0 +1,351 @@ +/**************************************************************************** +** +** +** Definition of QTextStream class +** +** Created : 940922 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QTEXTSTREAM_H +#define QTEXTSTREAM_H + +#ifndef QT_H +#include "qiodevice.h" +#include "qstring.h" +#include <stdio.h> +#endif // QT_H + +#ifndef QT_NO_TEXTSTREAM +class QTextCodec; +class QTextDecoder; + +class QTextStreamPrivate; + +class Q_EXPORT QTextStream // text stream class +{ +public: + enum Encoding { Locale, Latin1, Unicode, UnicodeNetworkOrder, + UnicodeReverse, RawUnicode, UnicodeUTF8 }; + + void setEncoding( Encoding ); +#ifndef QT_NO_TEXTCODEC + void setCodec( QTextCodec* ); +#endif + + // Encoding encoding() const { return cmode; } + + QTextStream(); + QTextStream( QIODevice * ); + QTextStream( QString*, int mode ); + QTextStream( QString&, int mode ); // obsolete + QTextStream( QByteArray, int mode ); + QTextStream( FILE *, int mode ); + virtual ~QTextStream(); + + QIODevice *device() const; + void setDevice( QIODevice * ); + void unsetDevice(); + + bool atEnd() const; + bool eof() const; + + QTextStream &operator>>( QChar & ); + QTextStream &operator>>( char & ); + QTextStream &operator>>( signed short & ); + QTextStream &operator>>( unsigned short & ); + QTextStream &operator>>( signed int & ); + QTextStream &operator>>( unsigned int & ); + QTextStream &operator>>( signed long & ); + QTextStream &operator>>( unsigned long & ); + QTextStream &operator>>( float & ); + QTextStream &operator>>( double & ); + QTextStream &operator>>( char * ); + QTextStream &operator>>( QString & ); + QTextStream &operator>>( QCString & ); + + QTextStream &operator<<( QChar ); + QTextStream &operator<<( char ); + QTextStream &operator<<( signed short ); + QTextStream &operator<<( unsigned short ); + QTextStream &operator<<( signed int ); + QTextStream &operator<<( unsigned int ); + QTextStream &operator<<( signed long ); + QTextStream &operator<<( unsigned long ); + QTextStream &operator<<( float ); + QTextStream &operator<<( double ); + QTextStream &operator<<( const char* ); + QTextStream &operator<<( const QString & ); + QTextStream &operator<<( const QCString & ); + QTextStream &operator<<( void * ); // any pointer + + QTextStream &readRawBytes( char *, uint len ); + QTextStream &writeRawBytes( const char* , uint len ); + + QString readLine(); + QString read(); + void skipWhiteSpace(); + + enum { + skipws = 0x0001, // skip whitespace on input + left = 0x0002, // left-adjust output + right = 0x0004, // right-adjust output + internal = 0x0008, // pad after sign + bin = 0x0010, // binary format integer + oct = 0x0020, // octal format integer + dec = 0x0040, // decimal format integer + hex = 0x0080, // hex format integer + showbase = 0x0100, // show base indicator + showpoint = 0x0200, // force decimal point (float) + uppercase = 0x0400, // upper-case hex output + showpos = 0x0800, // add '+' to positive integers + scientific= 0x1000, // scientific float output + fixed = 0x2000 // fixed float output + }; + + static const int basefield; // bin | oct | dec | hex + static const int adjustfield; // left | right | internal + static const int floatfield; // scientific | fixed + + int flags() const; + int flags( int f ); + int setf( int bits ); + int setf( int bits, int mask ); + int unsetf( int bits ); + + void reset(); + + int width() const; + int width( int ); + int fill() const; + int fill( int ); + int precision() const; + int precision( int ); + +private: + long input_int(); + void init(); + QTextStream &output_int( int, ulong, bool ); + QIODevice *dev; + bool isNetworkOrder() { return internalOrder == QChar::networkOrdered(); } + + int fflags; + int fwidth; + int fillchar; + int fprec; + bool fstrm; + bool owndev; + QTextCodec *mapper; + QTextStreamPrivate * d; + QChar ungetcBuf; + bool latin1; + bool internalOrder; + bool doUnicodeHeader; + void *reserved_ptr; + + QChar eat_ws(); + void ts_ungetc( QChar ); + QChar ts_getc(); + uint ts_getbuf( QChar*, uint ); + void ts_putc(int); + void ts_putc(QChar); + bool ts_isspace(QChar); + bool ts_isdigit(QChar); + ulong input_bin(); + ulong input_oct(); + ulong input_dec(); + ulong input_hex(); + double input_double(); + QTextStream &writeBlock( const char* p, uint len ); + QTextStream &writeBlock( const QChar* p, uint len ); + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QTextStream( const QTextStream & ); + QTextStream &operator=( const QTextStream & ); +#endif +}; + +typedef QTextStream QTS; + +class Q_EXPORT QTextIStream : public QTextStream { +public: + QTextIStream( QString* s ) : + QTextStream(s,IO_ReadOnly) { } + QTextIStream( QByteArray ba ) : + QTextStream(ba,IO_ReadOnly) { } + QTextIStream( FILE *f ) : + QTextStream(f,IO_ReadOnly) { } +}; + +class Q_EXPORT QTextOStream : public QTextStream { +public: + QTextOStream( QString* s ) : + QTextStream(s,IO_WriteOnly) { } + QTextOStream( QByteArray ba ) : + QTextStream(ba,IO_WriteOnly) { } + QTextOStream( FILE *f ) : + QTextStream(f,IO_WriteOnly) { } +}; + +/***************************************************************************** + QTextStream inline functions + *****************************************************************************/ + +inline QIODevice *QTextStream::device() const +{ return dev; } + +inline bool QTextStream::atEnd() const +{ return dev ? dev->atEnd() : FALSE; } + +inline bool QTextStream::eof() const +{ return atEnd(); } + +inline int QTextStream::flags() const +{ return fflags; } + +inline int QTextStream::flags( int f ) +{ int oldf = fflags; fflags = f; return oldf; } + +inline int QTextStream::setf( int bits ) +{ int oldf = fflags; fflags |= bits; return oldf; } + +inline int QTextStream::setf( int bits, int mask ) +{ int oldf = fflags; fflags = (fflags & ~mask) | (bits & mask); return oldf; } + +inline int QTextStream::unsetf( int bits ) +{ int oldf = fflags; fflags &= ~bits; return oldf; } + +inline int QTextStream::width() const +{ return fwidth; } + +inline int QTextStream::width( int w ) +{ int oldw = fwidth; fwidth = w; return oldw; } + +inline int QTextStream::fill() const +{ return fillchar; } + +inline int QTextStream::fill( int f ) +{ int oldc = fillchar; fillchar = f; return oldc; } + +inline int QTextStream::precision() const +{ return fprec; } + +inline int QTextStream::precision( int p ) +{ int oldp = fprec; fprec = p; return oldp; } + +/*! + Returns one character from the stream, or EOF. +*/ +inline QChar QTextStream::ts_getc() +{ QChar r; return ( ts_getbuf( &r,1 ) == 1 ? r : QChar((ushort)0xffff) ); } + +/***************************************************************************** + QTextStream manipulators + *****************************************************************************/ + +typedef QTextStream & (*QTSFUNC)(QTextStream &);// manipulator function +typedef int (QTextStream::*QTSMFI)(int); // manipulator w/int argument + +class Q_EXPORT QTSManip { // text stream manipulator +public: + QTSManip( QTSMFI m, int a ) { mf=m; arg=a; } + void exec( QTextStream &s ) { (s.*mf)(arg); } +private: + QTSMFI mf; // QTextStream member function + int arg; // member function argument +}; + +Q_EXPORT inline QTextStream &operator>>( QTextStream &s, QTSFUNC f ) +{ return (*f)( s ); } + +Q_EXPORT inline QTextStream &operator<<( QTextStream &s, QTSFUNC f ) +{ return (*f)( s ); } + +Q_EXPORT inline QTextStream &operator<<( QTextStream &s, QTSManip m ) +{ m.exec(s); return s; } + +Q_EXPORT QTextStream &bin( QTextStream &s ); // set bin notation +Q_EXPORT QTextStream &oct( QTextStream &s ); // set oct notation +Q_EXPORT QTextStream &dec( QTextStream &s ); // set dec notation +Q_EXPORT QTextStream &hex( QTextStream &s ); // set hex notation +Q_EXPORT QTextStream &endl( QTextStream &s ); // insert EOL ('\n') +Q_EXPORT QTextStream &flush( QTextStream &s ); // flush output +Q_EXPORT QTextStream &ws( QTextStream &s ); // eat whitespace on input +Q_EXPORT QTextStream &reset( QTextStream &s ); // set default flags + +Q_EXPORT inline QTSManip qSetW( int w ) +{ + QTSMFI func = &QTextStream::width; + return QTSManip(func,w); +} + +Q_EXPORT inline QTSManip qSetFill( int f ) +{ + QTSMFI func = &QTextStream::fill; + return QTSManip(func,f); +} + +Q_EXPORT inline QTSManip qSetPrecision( int p ) +{ + QTSMFI func = &QTextStream::precision; + return QTSManip(func,p); +} + + +#ifndef QT_ALTERNATE_QTSMANIP + +// These will go away in Qt 3.0, as they conflict with std libs +// +// If you get conflicts now, #define QT_ALTERNATE_QTSMANIP before +// including this file. + +Q_EXPORT inline QTSManip setw( int w ) +{ + QTSMFI func = &QTextStream::width; + return QTSManip(func,w); +} + +Q_EXPORT inline QTSManip setfill( int f ) +{ + QTSMFI func = &QTextStream::fill; + return QTSManip(func,f); +} + +Q_EXPORT inline QTSManip setprecision( int p ) +{ + QTSMFI func = &QTextStream::precision; + return QTSManip(func,p); +} +#endif + +#endif // QT_NO_TEXTSTREAM +#endif // QTEXTSTREAM_H diff --git a/trunk/qtools/qtl.doc b/trunk/qtools/qtl.doc new file mode 100644 index 0000000..db5b994 --- /dev/null +++ b/trunk/qtools/qtl.doc @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** +** Qt template library classes documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +/*! +\page qtl.html + +\title Qt Template library + +Thq Qt Template Library is a set of templates within Qt dealing with +containers of objects. It provides a list of objects, a stack of +objects, a map (or dictionary) from one type to another, and +associated iterators and algorithms. + +Qt also contains similar classes that deal with pointers to objects; +\l QValueList vs. \l QList, etc. Compared to the pointer-based +templates, the QTL offers easy copying of the container, real support +for classes that e.g. require constructors, expand to much more object +code, can often be a bit faster, require that the objects stored can +be copied, and finally, have a worse record of compiler problems. + +Compared to the STL, the QTL contains only the most important features +of the STL, has more regular function naming, has no platform +differences, is often a little slower and often expands to less object +code. + + +If you can not make copies of the objects you want to store you are +better off with QCollection and friends. They were designed to handle +exactly that kind of pointer semantics. This applies for example to +all classes derived from \l QObject. A QObject does not have a copy +constructor, so using it as value is impossible. You may choose be +store pointers to QObjects in a QValueList, but using QList directly +seems to be the better choice for this kind of application +domain. QList, like all other QCollection based containers, provides +far more sanity checking than a speed-optimized value +based container. + +If you have objects that implement value semantics, use the Qt +template library. Value semantics require at least +<ul> +<li>a copy constructor, +<li>an assignment operator and +<li> a default constructor, i.e. a constructor that does not take +any arguments. +</ul> +Note that a fast copy constructor is absolutely crucial for a good +overall performance of the container, since many copy operations are +going to happen. + +Examples for value based classes are QRect, QPoint, QSize and all +simple C++ types like int, bool or double. + +The Qt template library is designed for speed. Especially iterators +are extremely fast. On the drawback side, less error checking is done +than in the QCollection based containers. A template library container +for example does not track associated iterators. This makes certain +validity checks, like on removing items, impossible to perform +automatically. + +<h2> Iterators </h2> + +The Qt template library deals with value objects, not with pointers. +For that reason, there is no other way of iterating over containers +than using iterators. This is no disadvantage as the size of an +iterator matches the size of a normal pointer - 32 or 64 bits +depending on your CPU architecture. + +To iterate over a container, use a loop like this: + +\code + typedef QValueList<int> List; + List l; + for( List::Iterator it = l.begin(); it != l.end(); ++it ) + printf("Number is %i\n",*it); +\endcode + +begin() returns the iterator pointing at the first element, while +end() returns an iterator that points \e after the last +element. end() marks an invalid position, it can never be +dereferenced. It's the break condition in any iteration, may it be +from begin() or fromLast(). For maximum speed, use increment or +decrement iterators with the prefix operator (++it, --it) instead of the the +postfix one (it++, it--), since the former is slightly faster. + +The same concept applies to the other container classes: + +\code + typedef QMap<QString,QString> Map; + Map map; + for( Map::Iterator it = map.begin(); it != map.end(); ++it ) + printf("Key=%s Data=%s\n", it.key().ascii(), it.data().ascii() ); + + typedef QArray<int> Array; + Array array; + for( Array::Iterator it = array.begin(); it != array.end(); ++it ) + printf("Data=%i\n", *it ); +\endcode + +There are two kind of iterators, the volatile iterator shown in the +examples above and a version that returns a const reference to its +current object, the ConstIterator. Const iterators are required +whenever the container itself is const, such as a member variable +inside a const function. Assigning a ConstIterator to a normal +Iterator is not allowed as it would violate const semantics. + +<h2> Algorithms </h2> + +The template library defines a number of algorithms that operate on +its containers: qHeapSort(), qBubbleSort(), qSwap() and +qCopy(). These algorithms are implemented as template functions. + +qHeapSort() and qBubbleSort() provide the well known sorting +algorithms. You can use them like this: + +\code + typedef QValueList<int> List; + List l; + l << 42 << 100 << 1234 << 12 << 8; + qHeapSort( l ); + + List l2; + l2 << 42 << 100 << 1234 << 12 << 8; + List::Iterator b = l2.find( 100 ); + List::Iterator e = l2.find( 8 ); + qHeapSort( b, e ); + + double arr[] = { 3.2, 5.6, 8.9 }; + qHeapSort( arr, arr + 3 ); +\endcode + +The first example sorts the entire list. The second one sorts all +elements enclosed in the two iterators, namely 100, 1234 and 12. The +third example shows that iterators act like pointers and can be +treated as such. + +Naturally, the sorting templates won't work with const iterators. + +Another utility is qSwap(). It exchanges the values of two variables: + +\code + QString second( "Einstein" ); + QString name( "Albert" ); + qSwap( second, name ); +\endcode + +Another template function is qCopy(). It copies a container or a slice +of it to an OutputIterator, in this case a QTextOStreamIterator: + +\code + typedef QValueList<int> List; + List l; + l << 100 << 200 << 300; + QTextOStream str( stdout ); + qCopy( l, QTextOStreamIterator( str ) ); +\endcode + +In addition, you can use any Qt template library iterator as the +OutputIterator. Just make sure that the right hand of the iterator has +as many elements present as you want to insert. The following example +illustrates this: + +\code + QStringList l1, l2; + l1 << "Weis" << "Ettrich" << "Arnt" << "Sue"; + l2 << "Torben" << "Matthias"; + qCopy( l2, l1.begin(); +\endcode + +At the end of this code fragment, the List l1 contains "Torben", +"Matthias", "Arnt" and "Sue", with the prior contents being +overwritten. Another flavor of qCopy() takes three arguments to make +it possible to copy a slice of a container: + +\code + typedef QValueList<int> List; + List l; + l << 42 << 100 << 1234 << 12 << 8; + List::Iterator b = l.find( 100 ); + List::Iterator e = l.find( 8 ); + QTextOStream str( stdout ); + qCopy( b, e, QTextOStreamIterator( str ) ); +\endcode + +If you write new algorithms, consider writing them as template +functions in order to make them usable with as many containers +possible. In the above example, you could just as easily print out a +standard C++ array with qCopy(): + +\code + int arr[] = { 100, 200, 300 }; + QTextOStream str( stdout ); + qCopy( arr, arr + 3, QTextOStreamIterator( str ) ); +\endcode + + +<h2> Streaming </h2> + +All mentioned containers can be serialized with the respective +streaming operators. Here is an example. + +\code + QDataStream str(...); + QValueList<QRect> l; + // ... fill the list here + str << l; +\endcode + +The container can be read in again with: + +\code + QValueList<QRect> l; + str >> l; +\endcode + +The same applies to QStringList, QValueStack and QMap. + +*/ diff --git a/trunk/qtools/qtl.h b/trunk/qtools/qtl.h new file mode 100644 index 0000000..bd72e7d --- /dev/null +++ b/trunk/qtools/qtl.h @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** +** Definition of Qt template library classes +** +** Created : 990128 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#ifndef QTL_H +#define QTL_H + +#ifndef QT_H +#include "qtextstream.h" +#include "qstring.h" +#endif // QT_H + +#ifndef QT_NO_TEXTSTREAM +template <class T> +class QTextOStreamIterator +{ +protected: + QTextOStream& stream; + QString separator; + +public: + QTextOStreamIterator( QTextOStream& s) : stream( s ) {} + QTextOStreamIterator( QTextOStream& s, const QString& sep ) + : stream( s ), separator( sep ) {} + QTextOStreamIterator<T>& operator= ( const T& x ) { + stream << x; + if ( !separator.isEmpty() ) + stream << separator; + return *this; + } + QTextOStreamIterator<T>& operator*() { return *this; } + QTextOStreamIterator<T>& operator++() { return *this; } + QTextOStreamIterator<T>& operator++(int) { return *this; } +}; +#endif //QT_NO_TEXTSTREAM + +template <class InputIterator, class OutputIterator> +inline OutputIterator qCopy( InputIterator _begin, InputIterator _end, + OutputIterator _dest ) +{ + while( _begin != _end ) + *_dest++ = *_begin++; + return _dest; +} + + +template <class T> +inline void qSwap( T& _value1, T& _value2 ) +{ + T tmp = _value1; + _value1 = _value2; + _value2 = tmp; +} + + +template <class InputIterator> +inline void qBubbleSort( InputIterator b, InputIterator e ) +{ + // Goto last element; + InputIterator last = e; + --last; + // only one element or no elements ? + if ( last == b ) + return; + + // So we have at least two elements in here + while( b != last ) { + bool swapped = FALSE; + InputIterator swap_pos = b; + InputIterator x = e; + InputIterator y = x; + y--; + do { + --x; + --y; + if ( *x < *y ) { + swapped = TRUE; + qSwap( *x, *y ); + swap_pos = y; + } + } while( y != b ); + if ( !swapped ) + return; + b = swap_pos; + b++; + } +} + + +template <class Container> +inline void qBubbleSort( Container &c ) +{ + qBubbleSort( c.begin(), c.end() ); +} + + +template <class Value> +inline void qHeapSortPushDown( Value* heap, int first, int last ) +{ + int r = first; + while( r <= last/2 ) { + // Node r has only one child ? + if ( last == 2*r ) { + // Need for swapping ? + if ( heap[r] > heap[ 2*r ] ) + qSwap( heap[r], heap[ 2*r ] ); + // That's it ... + r = last; + } else { // Node has two children + if ( heap[r] > heap[ 2*r ] && heap[ 2*r ] <= heap[ 2*r+1 ] ) { + // Swap with left child + qSwap( heap[r], heap[ 2*r ] ); + r *= 2; + } else if ( heap[r] > heap[ 2*r+1 ] && + heap[ 2*r+1 ] < heap[ 2*r ] ) { + // Swap with right child + qSwap( heap[r], heap[ 2*r+1 ] ); + r = 2*r+1; + } else { + // We are done + r = last; + } + } + } +} + + +template <class InputIterator, class Value> +inline void qHeapSortHelper( InputIterator b, InputIterator e, Value, uint n ) +{ + // Create the heap + InputIterator insert = b; + Value* realheap = new Value[ n ]; + // Wow, what a fake. But I want the heap to be indexed as 1...n + Value* heap = realheap - 1; + int size = 0; + for( ; insert != e; ++insert ) { + heap[++size] = *insert; + int i = size; + while( i > 1 && heap[i] < heap[ i / 2 ] ) { + qSwap( heap[i], heap[ i / 2 ] ); + i /= 2; + } + } + + // Now do the sorting + for( uint i = n; i > 0; i-- ) { + *b++ = heap[1]; + if ( i > 1 ) { + heap[1] = heap[i]; + qHeapSortPushDown( heap, 1, (int)i - 1 ); + } + } + + delete[] realheap; +} + + +template <class InputIterator> +inline void qHeapSort( InputIterator b, InputIterator e ) +{ + // Empty ? + if ( b == e ) + return; + + // How many entries have to be sorted ? + InputIterator it = b; + uint n = 0; + while ( it != e ) { + ++n; + ++it; + } + + // The second last parameter is a hack to retrieve the value type + // Do the real sorting here + qHeapSortHelper( b, e, *b, n ); +} + + +template <class Container> +inline void qHeapSort( Container &c ) +{ + if ( c.isEmpty() ) + return; + + // The second last parameter is a hack to retrieve the value type + // Do the real sorting here + qHeapSortHelper( c.begin(), c.end(), *(c.begin()), c.count() ); +} + +#endif diff --git a/trunk/qtools/qtools.pro.in b/trunk/qtools/qtools.pro.in new file mode 100644 index 0000000..d2550f6 --- /dev/null +++ b/trunk/qtools/qtools.pro.in @@ -0,0 +1,85 @@ +TEMPLATE = lib +CONFIG = warn_on staticlib $extraopts +HEADERS = qarray.h \ + qbuffer.h \ + qcache.h \ + qgcache.h \ + qcollection.h \ + qconfig.h \ + qcstring.h \ + scstring.h \ + qdatastream.h \ + qdatetime.h \ + qdict.h \ + qdir.h \ + qfeatures.h \ + qfile.h \ + qfiledefs_p.h \ + qfileinfo.h \ + qgarray.h \ + qfeatures.h \ + qgdict.h \ + qgeneric.h \ + qglist.h \ + qglobal.h \ + qgstring.h \ + qgvector.h \ + qintdict.h \ + qiodevice.h \ + qlist.h \ + qptrdict.h \ + qqueue.h \ + qregexp.h \ + qshared.h \ + qsortedlist.h \ + qstack.h \ + qstring.h \ + qstringlist.h \ + qstrlist.h \ + qstrvec.h \ + qtextstream.h \ + qtl.h \ + qvaluelist.h \ + qvector.h \ + qxml.h \ + qvaluestack.h \ + qmap.h \ + qmodules.h +SOURCES = qbuffer.cpp \ + qcollection.cpp \ + scstring.cpp \ + qdatastream.cpp \ + qdatetime.cpp \ + qdir.cpp \ + qfile.cpp \ + qfileinfo.cpp \ + qgarray.cpp \ + qgcache.cpp \ + qgdict.cpp \ + qglist.cpp \ + qglobal.cpp \ + qgstring.cpp \ + qgvector.cpp \ + qiodevice.cpp \ + qregexp.cpp \ + qstring.cpp \ + qtextstream.cpp \ + qtextcodec.cpp \ + qstringlist.cpp \ + qxml.cpp \ + qmap.cpp + +unix:SOURCES += qfile_unix.cpp \ + qdir_unix.cpp \ + qfileinfo_unix.cpp + +win32:SOURCES += qfile_win32.cpp \ + qdir_win32.cpp \ + qfileinfo_win32.cpp + +INCLUDEPATH = . +TMAKE_CXXFLAGS += -DQT_NO_CODECS -DQT_LITE_UNICODE +win32:TMAKE_CXXFLAGS += -DQT_NODLL +win32-g++:TMAKE_CXXFLAGS += -D__CYGWIN__ -DALL_STATIC +OBJECTS_DIR = ../objects +DESTDIR = ../lib diff --git a/trunk/qtools/qvaluelist.doc b/trunk/qtools/qvaluelist.doc new file mode 100644 index 0000000..e4621d5 --- /dev/null +++ b/trunk/qtools/qvaluelist.doc @@ -0,0 +1,772 @@ +/**************************************************************************** +** +** +** QValueList and QValueListIterator class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QValueList documentation + *****************************************************************************/ + +/*! + \class QValueList qvaluelist.h + \brief The QValueList class is a value based template class that provides doubly linked lists. + + \ingroup qtl + \ingroup tools + \ingroup shared + + Define a template instance QValueList\<X\> to create a list of values which all + have the class X. Please notice that QValueList does not store pointers to the + members of the list. It holds a copy of every member. That is the reason why this + kind of classes are called "value based" while QList and QDict are "reference based". + + Some classes can not be used within a QValueList, for example everything + derived from QObject and thus all classes that implement widgets. + Only values can be used in a QValueList. To qualify as a value, the class + must provide + <ul> + <li>a copy constructor, + <li>an assignment operator and + <li> a default constructor, i.e. a constructor that does not take any arguments. + </ul> + + Note that C++ defaults to field-by-field assignment operators and + copy constructors if no explicit version is supplied. In many cases, + this is sufficient. + + Example: + \code + #include <qvaluelist.h> + #include <qstring.h> + #include <stdio.h> + + class Employee + { + public: + Employee(): s(0) {} + Employee( const QString& name, int salary ) + : n(name), s(salary) + {} + + QString name() const { return n; } + int salary() const { return s; } + void setSalary( int salary ) { s = salary; } + private: + QString n; + int s; + }; + + void main() + { + typedef QValueList<Employee> EmployeeList; + EmployeeList list; // list of Employee + + list.append( Employee("Bill", 50000) ); + list.append( Employee("Steve",80000) ); + list.append( Employee("Ron", 60000) ); + + Employee joe( "Joe", 50000 ); + list.append( joe ); + joe.setSalary( 4000 ); + + EmployeeList::Iterator it; + for( it = list.begin(); it != list.end(); ++it ) + printf( "%s earns %d\n", (*it).name().latin1(), (*it).salary().latin1() ); + } + \endcode + + Program output: + \code + Bill earns 50000 + Steve earns 80000 + Ron earns 60000 + Joe earns 50000 + \endcode + + As you can see, the latest changes to Joes salary did not affect the value + in the list because the list created a copy of Joes entry. + + There are three ways of finding items in the list. The first one is by using + the at() function. It returns an iterator. The advantages of + getting an iterator is that you can now move forward or backward from this + position by incrementing/decrementing the iterator. To get the amount of + items in the list call count(). Valid indices are 0..count(). + + The second way of accessing a list is with operator[]. That means you can address + it like an array. The return value is a reference to the value stored in the list. + There exist two versions of this operator. The first one is const and returns a + const reference to the value. The second on is non const and returns a non const + reference to the value. It is up to your compiler to choose the correct one. + + The third method is to use the functions begin() and end(). + With a simple for loop as shown in the example you can iterate over the complete list. + It is save to have multiple iterators at the same time. If some member of the list is + removed then only iterators pointing to the removed member become invalid. Inserting in + the list does not invalidate any iterator. For convenience the function last() returns + an iterator for the last and first() for the first element in the list. + + In addition you can search items in the list with the find() function. It exists in a const + and a non const version. It starts searching from the beginning of the list, but another + flavor of the find() function allows you to specify where searching should start. + If you just want to know wether a certain item is at least once in the list, then you + can use the contains() function. + + Since QValueList is value based there is no need to care about deleting elements in the + list. The list holds its own copies and will free them if the corresponding member or + the list itself is deleted. You can force the list to free all of its item with clear(). + + QValueList is implicitly shared. That means you can just make copies of the list + in time O(1). If multiple QValueList instances share the same data and one + is doing a modification of the lists data then this modifying instance makes a copy + and modifies its private copy. So it does not affect the other instances. + From a developers point of view you can think that a QValueList and a copy of this + list have nothing to do with each other. Developers may only notice that copying is + very fast. People known to a CPUs MMU architecture will know this pattern as "copy on write". + + There exist three functions to insert items in the list. append() + inserts an item at the end, prepend() inserts at the beginning + and insert() inserts in front of the position given by an iterator. + + Items can be removed from the list in two ways. The first is to pass an iterator to + the remove(). The other possibility is to pass a value to remove() which will + delete all members which match this value. + + Lists can be sorted with the algorithms provided by the <a + href="qtl.html">Qt Template Library</a>, for example with + qHeapSort(): + + Example: + \code + QValueList l; + l.append( 5 ); + l.append( 8 ); + l.append( 3 ); + l.append( 4 ); + qHeapSort( l ); + \endcode + + \sa QValueListIterator +*/ + + +/*! + \fn QValueList::QValueList() + Constructs an empty list. +*/ + +/*! + \fn QValueList::QValueList( const QValueList<T>& l ) + Constructs a copy of \e l. + + This operation costs O(1) time since QValueList is implicit shared. + The first instance applying modifications to a shared list will create + a copy which takes in turn O(n) time. However returning a QValueList from + a function is very fast. +*/ + +/*! + \fn QValueList::~QValueList() + Destroys the list. References to the values in the list and all iterators + of this list become invalidated. Since QValueList is highly tuned for performance + you wont see warnings if you use invalid iterators, + because it is impossible for + an iterator to check wether it is valid or not. +*/ + +/*! + \fn QValueList<T>& QValueList::operator= ( const QValueList<T>& l ) + Assigns \e l to this list and returns a reference to this list. + + All iterators of the current list become invalidated by this operation. + The cost of such an assignment is O(1) since QValueList is implicitly shared. +*/ + +/*! + \fn QValueList<T> QValueList::operator+ ( const QValueList<T>& l ) const + Creates a new list and fills it with the elements of this list. Then the + elements of \e l are appended. + + Returns the new list. +*/ + +/*! + \fn QValueList<T>& QValueList::operator+= ( const QValueList<T>& l ) + Adds \e list to this list. + + Returns a reference to this list. +*/ + +/*! + \fn bool QValueList::operator== ( const QValueList<T>& l ) const + Compares both lists. + + Returns TRUE if both list are equal. +*/ + +/*! + \fn bool QValueList::operator!= ( const QValueList<T>& l ) const + Compares both lists. + + Returns TRUE if both list are unequal. +*/ + +/*! + \fn QValueList<T>& QValueList::operator+= ( const T& x ) + Adds the value \e x to the end of the list. + + Returns a reference to the list. +*/ + +/*! + \fn QValueList<T>& QValueList::operator<< ( const T& x ) + Adds the value \e x to the end of the list. + + Returns a reference to the list. +*/ + +/*! + \fn const T& QValueList::operator[] ( uint i ) const + Returns a const reference to the item with index \e i in the list. + It is up to you to check wether this item really exists. You can do that easily + with the count() function. However this operator does not check wether \e i + is in range and will deliver undefined results if it does not exist. +*/ + +/*! + \fn T& QValueList::operator[] ( uint i ) + Returns a reference to the item with index \e i in the list. + It is up to you to check wether this item really exists. You can do that easily + with the count() function. However this operator does not check wether \e i + is in range and will deliver undefined results if it does not exist. + In contrast to the const operator[] you may manipulate the value returned by this + operator. +*/ + +/*! + \fn uint QValueList::count() const + Returns the number of items in the list. + \sa isEmpty() +*/ + +/*! + \fn bool QValueList::isEmpty() const + Returns TRUE if the list is empty, i.e. count() == 0. Returns FALSE + otherwise. + \sa count() +*/ + +/*! + \fn Iterator QValueList::insert( Iterator it, const T& x ) + Inserts the value \e x in front of the iterator \e it. + + Returns an iterator pointing at the inserted item. + + \sa append(), prepend() +*/ + +/*! + \fn Iterator QValueList::append( const T& x ) + Inserts the value \e x at the end of the list. + + Returns an iterator pointing at the inserted item. + + \sa insert(), prepend() +*/ + +/*! + \fn Iterator QValueList::prepend( const T& x ) + Inserts the value \e x at the beginning of the list. + + Returns an iterator pointing at the inserted item. + + \sa insert(), append() +*/ + +/*! + \fn Iterator QValueList::remove( Iterator it ) + Removes the item at position \e it in the list. + + Returns an iterator pointing to the item following the + removed on or end() if the last item was deleted. + + \sa clear() +*/ + +/*! + \fn void QValueList::remove( const T& x ) + Removes all items which have the value \e x. + + \sa clear() +*/ + +/*! + \fn void QValueList::clear() + Removes all items from the list. + + \sa remove() +*/ + +/*! + \fn Iterator QValueList::find( const T& x ) + Finds the first occurrence of \e x in the list. + + Returns end() if no item did match. +*/ + +/*! + \fn ConstIterator QValueList::find( const T& x ) const + Finds the first occurrence of \e x in the list. + + Returns end() if no item did match. +*/ + +/*! + \fn Iterator QValueList::find( Iterator it, const T& x ) + Finds the first occurrence of \e x in the list starting at + the position given by \e it. + + Returns end() if no item did match. +*/ + +/*! + \fn ConstIterator QValueList::find( ConstIterator it, const T& x ) const + Finds the first occurrence of \e x in the list starting at + the position given by \e it. + + Returns end() if no item did match. +*/ + +/*! + \fn uint QValueList::contains( const T& x ) const + Counts and returns the number of occurrences of the value \e x in the list. +*/ + +/*! + \fn int QValueList::findIndex( const T& x ) const + Returns the first index of the value \e x in the list or -1 if no such value + can be found in the list. +*/ + +/*! + \fn Iterator QValueList::at( uint i ) + Returns an iterator pointing to the item at position \e i in the list, or + end() if the index is out of range. +*/ + +/*! + \fn ConstIterator QValueList::at( uint i ) const + Returns an iterator pointing to the item at position \e i in the list, or + end() if the index is out of range. +*/ + +/*! + \fn T& QValueList::first() + Returns a reference to the first item in the list or the item + referenced by end() + if no such items exists. Please note that you may not change + the value the end() Iterator is pointing to. + + \sa begin(), last() +*/ + +/*! + \fn const T& QValueList::first() const + Returns a reference to the first item in the list or the item + referenced by end() if + no such items exists. + + \sa begin(), last() +*/ + +/*! + \fn Iterator QValueList::fromLast() + Returns an iterator pointing to the last element in the list or + end() if no such item exists. + + \sa last() +*/ + +/*! + \fn ConstIterator QValueList::fromLast() const + Returns an iterator pointing to the last element in the list or + end() if no such item exists. + + \sa last() +*/ + +/*! + \fn T& QValueList::last() + Returns a reference to the last item in the list or the item + referenced by end() if no + such item exists. Please note that you may not change + the value the end() Iterator is pointing to. + + \sa end(), first(), fromLast() +*/ + +/*! + \fn const T& QValueList::last() const + Returns a reference to the last item in the list or the item + referenced by end() if no such item exists. + + \sa end(), first(), fromLast() +*/ + +/*! + \fn Iterator QValueList::begin() + Returns an iterator pointing to the first element in the list. This + iterator equals end() if the list is empty; + \sa first(), end() +*/ + +/*! + \fn ConstIterator QValueList::begin() const + Returns an iterator pointing to the first element in the list. This + iterator equals end() if the list is empty; + \sa first(), end() +*/ + +/*! + \fn Iterator QValueList::end() + Returns an iterator pointing behind the last element in the list. This + iterator equals begin() if the list is empty. + + \sa last(), begin() +*/ + +/*! + \fn ConstIterator QValueList::end() const + Returns an iterator pointing behind the last element in the list. This + iterator equals begin() if the list is empty. + + \sa last(), begin() +*/ + +/*! + \fn void QValueList::detach() + If the list does not share its data with another QValueList instance, then nothing + happens, otherwise the function creates a new copy of this data and detaches + from the shared one. This function is called whenever the list is modified. + The implicit sharing mechanism is implemented this way. +*/ + +/*! + \fn QDataStream& operator>>( QDataStream& s, QValueList<T>& l ) + \relates QValueList + Reads a list from the stream. The type \e T stored in the list must implement + the streaming operator, too. +*/ + +/*! + \fn QDataStream& operator<<( QDataStream& s, const QValueList<T>& l ) + \relates QValueList + Writes a list to the stream. The type \e T stored in the list must implement + the streaming operator, too. +*/ + +/***************************************************************************** + QValueListIterator documentation + *****************************************************************************/ + +/*! + \class QValueListIterator qvaluelist.h + \brief The QValueListIterator class provides an iterator for QValueList. + + \ingroup qtl + \ingroup tools + + You can not create an iterator by yourself. Instead you have to + ask a list to give you one. An iterator has only the size of a pointer. + On 32 bit machines that means 4 bytes otherwise 8 bytes. That makes them + very fast. In fact they resemble the semantics of pointers as good as possible + and they are almost as fast as usual pointers. + + Example: + \code + #include <qvaluelist.h> + #include <qstring.h> + #include <stdio.h> + + class Employee + { + public: + Employee(): s(0) {} + Employee( const QString& name, int salary ) + : n(name), s(salary) + {} + + QString name() const { return n; } + int salary() const { return s; } + void setSalary( int salary ) { s = salary; } + private: + QString n; + int s; + }; + + void main() + { + typedef QValueList<Employee> EmployeeList; + EmployeeList list; // list of Employee + + list.append( Employee("Bill", 50000) ); + list.append( Employee("Steve",80000) ); + list.append( Employee("Ron", 60000) ); + + Employee joe( "Joe", 50000 ); + list.append( joe ); + joe.setSalary( 4000 ); + + EmployeeList::Iterator it; + for( it = list.begin(); it != list.end(); ++it ) + printf( "%s earns %d\n", (*it).name().latin1(), (*it).salary() ); + } + \endcode + + Program output: + \code + Bill earns 50000 + Steve earns 80000 + Ron earns 60000 + Joe earns 50000 + \endcode + + In contrast to QList there are no built in functions in QValueList to + traverse the list. The only way to do this is to use iterators. + QValueList is highly optimized for performance and memory usage. + On the other hand that means that you have to be a bit more careful + by what you are doing. QValueList does not know about all its iterators + and the iterators dont even know to which list they belong. That makes + things fast and slim but a bit dangerous because it is up to you to make + sure that iterators you are using are still valid. QListIterator will be able + to give warnings while QValueListIterator may end up in an undefined state. + + For every Iterator there is a ConstIterator. When accessing a QValueList + in a const environment or if the reference or pointer to the list is itself + const, then you have to use the ConstIterator. Its semantics are the same, + but it returns only const references to the item it points to. + + \sa QValueList, QValueListConstIterator +*/ + +/*! + \fn QValueListIterator::QValueListIterator() + Creates un uninitialized iterator. +*/ + +/*! + \fn QValueListIterator::QValueListIterator( NodePtr p ) + Internal function. +*/ + +/*! + \fn QValueListIterator::QValueListIterator( const QValueListIterator<T>& it ) + Constructs a copy of the iterator \e it. +*/ + +/*! + \fn QValueListIterator::~QValueListIterator() + Destroys the iterator. +*/ + +/* Unfortunately not with MSVC + \fn T *QValueListIterator::operator->() + Pointer operator. Returns a pointer to the current iterator item. + The great advantage of this operator is that you can treat the + iterator like a pointer. + + Example: + \code + QValueList<int>::Iterator it = list.begin(); + for( ; it != end(); ++it ) + it->show(); + \endcode +*/ + +/*! + \fn T& QValueListIterator::operator*() + Asterix operator. Returns a reference to the current iterator item. +*/ + +/*! + \fn const T& QValueListIterator::operator*() const + Asterix operator. Returns a reference to the current iterator item. +*/ + +/*! + \fn QValueListIterator<T>& QValueListIterator::operator++() + Prefix ++ makes the succeeding item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the end of the list. Incrementing + the iterator as returned by end() causes undefined results. +*/ + +/*! + \fn QValueListIterator<T> QValueListIterator::operator++(int) + Postfix ++ makes the succeeding item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the end of the list. Incrementing + the iterator as returned by end() causes undefined results. +*/ + +/*! + \fn QValueListIterator<T>& QValueListIterator::operator--() + Prefix -- makes the previous item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the beginning of the list. Decrementing + the iterator as returned by begin() causes undefined results. +*/ + +/*! + \fn QValueListIterator<T> QValueListIterator::operator--(int) + Postfix -- makes the previous item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the beginning of the list. Decrementing + the iterator as returned by begin() causes undefined results. +*/ + +/*! + \fn bool QValueListIterator::operator==( const QValueListIterator<T>& it ) const + Compares both iterators and returns TRUE if they point to the same item. +*/ + +/*! + \fn bool QValueListIterator::operator!=( const QValueListIterator<T>& it ) const + Compares both iterators and returns TRUE if they point to different items. +*/ + +/***************************************************************************** + QValueListConstIterator documentation + *****************************************************************************/ + +/*! + \class QValueListConstIterator qvaluelist.h + \brief The QValueListConstIterator class provides an iterator for QValueList. + + \ingroup qtl + \ingroup tools + + In contrast to QValueListIterator this class is used to iterate over a const + list. It does not allow to modify the values of the list since this would + break the const semantics. + + For more informations on QValueList iterators see QValueListIterator. + + \sa QValueListIterator, QValueList +*/ + +/*! + \fn QValueListConstIterator::QValueListConstIterator() + Creates un uninitialized iterator. +*/ + +/*! + \fn QValueListConstIterator::QValueListConstIterator( NodePtr p ) + Internal function. +*/ + +/*! + \fn QValueListConstIterator::QValueListConstIterator( const QValueListConstIterator<T>& it ) + Constructs a copy of the iterator \e it. +*/ + +/*! + \fn QValueListConstIterator::QValueListConstIterator( const QValueListIterator<T>& it ) + Constructs a copy of the iterator \e it. +*/ + +/*! + \fn QValueListConstIterator::~QValueListConstIterator() + Destroys the iterator. +*/ + +/* Unfortunately not with MSVC + \fn const T *QValueListConstIterator::operator->() + Pointer operator. Returns a pointer to the current iterator item. + The great advantage of this operator is that you can treat the + iterator like a pointer. + + Example: + \code + QValueList<int>::Iterator it = list.begin(); + for( ; it != end(); ++it ) + it->show(); + \endcode +*/ + +/*! + \fn const T& QValueListConstIterator::operator*() const + Asterix operator. Returns a reference to the current iterator item. +*/ + +/*! + \fn QValueListConstIterator<T>& QValueListConstIterator::operator++() + Prefix ++ makes the succeeding item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the end of the list. Incrementing + the iterator as returned by end() causes undefined results. +*/ + +/*! + \fn QValueListConstIterator<T> QValueListConstIterator::operator++(int) + Postfix ++ makes the succeeding item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the end of the list. Incrementing + the iterator as returned by end() causes undefined results. +*/ + +/*! + \fn QValueListConstIterator<T>& QValueListConstIterator::operator--() + Prefix -- makes the previous item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the beginning of the list. Decrementing + the iterator as returned by begin() causes undefined results. +*/ + +/*! + \fn QValueListConstIterator<T> QValueListConstIterator::operator--(int) + Postfix -- makes the previous item current and returns + an iterator pointing to the new current item. + The iterator can not check wether it reached the beginning of the list. Decrementing + the iterator as returned by begin() causes undefined results. +*/ + +/*! + \fn bool QValueListConstIterator::operator==( const QValueListConstIterator<T>& it ) const + Compares both iterators and returns TRUE if they point to the same item. +*/ + +/*! + \fn bool QValueListConstIterator::operator!=( const QValueListConstIterator<T>& it ) const + Compares both iterators and returns TRUE if they point to different items. +*/ diff --git a/trunk/qtools/qvaluelist.h b/trunk/qtools/qvaluelist.h new file mode 100644 index 0000000..a1014ed --- /dev/null +++ b/trunk/qtools/qvaluelist.h @@ -0,0 +1,449 @@ +/**************************************************************************** +** +** +** Definition of QValueList class +** +** Created : 990406 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QVALUELIST_H +#define QVALUELIST_H + +#ifndef QT_H +#include "qshared.h" +#include "qdatastream.h" +#endif // QT_H + +#if defined(_CC_MSVC_) +#pragma warning(disable:4284) // "return type for operator -> is not a UDT" +#endif + +template <class T> +class Q_EXPORT QValueListNode +{ +public: + QValueListNode( const T& t ) : data( t ) { } + QValueListNode() { } +#if defined(Q_TEMPLATEDLL) + // Workaround MS bug in memory de/allocation in DLL vs. EXE + virtual ~QValueListNode() { } +#endif + + QValueListNode<T>* next; + QValueListNode<T>* prev; + T data; +}; + +template<class T> +class Q_EXPORT QValueListIterator +{ + public: + /** + * Typedefs + */ + typedef QValueListNode<T>* NodePtr; + + /** + * Variables + */ + NodePtr node; + + /** + * Functions + */ + QValueListIterator() : node( 0 ) {} + QValueListIterator( NodePtr p ) : node( p ) {} + QValueListIterator( const QValueListIterator<T>& it ) : node( it.node ) {} + + bool operator==( const QValueListIterator<T>& it ) const { return node == it.node; } + bool operator!=( const QValueListIterator<T>& it ) const { return node != it.node; } + const T& operator*() const { return node->data; } + T& operator*() { return node->data; } + + // Compilers are too dumb to understand this for QValueList<int> + //T* operator->() const { return &(node->data); } + + QValueListIterator<T>& operator++() { + node = node->next; + return *this; + } + + QValueListIterator<T> operator++(int) { + QValueListIterator<T> tmp = *this; + node = node->next; + return tmp; + } + + QValueListIterator<T>& operator--() { + node = node->prev; + return *this; + } + + QValueListIterator<T> operator--(int) { + QValueListIterator<T> tmp = *this; + node = node->prev; + return tmp; + } +}; + +template<class T> +class Q_EXPORT QValueListConstIterator +{ + public: + /** + * Typedefs + */ + typedef QValueListNode<T>* NodePtr; + + /** + * Variables + */ + NodePtr node; + + /** + * Functions + */ + QValueListConstIterator() : node( 0 ) {} + QValueListConstIterator( NodePtr p ) : node( p ) {} + QValueListConstIterator( const QValueListConstIterator<T>& it ) : node( it.node ) {} + QValueListConstIterator( const QValueListIterator<T>& it ) : node( it.node ) {} + + bool operator==( const QValueListConstIterator<T>& it ) const { return node == it.node; } + bool operator!=( const QValueListConstIterator<T>& it ) const { return node != it.node; } + const T& operator*() const { return node->data; } + + // Compilers are too dumb to understand this for QValueList<int> + //const T* operator->() const { return &(node->data); } + + QValueListConstIterator<T>& operator++() { + node = node->next; + return *this; + } + + QValueListConstIterator<T> operator++(int) { + QValueListConstIterator<T> tmp = *this; + node = node->next; + return tmp; + } + + QValueListConstIterator<T>& operator--() { + node = node->prev; + return *this; + } + + QValueListConstIterator<T> operator--(int) { + QValueListConstIterator<T> tmp = *this; + node = node->prev; + return tmp; + } +}; + +template <class T> +class Q_EXPORT QValueListPrivate : public QShared +{ +public: + /** + * Typedefs + */ + typedef QValueListIterator<T> Iterator; + typedef QValueListConstIterator<T> ConstIterator; + typedef QValueListNode<T> Node; + typedef QValueListNode<T>* NodePtr; + + /** + * Functions + */ + QValueListPrivate() { node = new Node; node->next = node->prev = node; nodes = 0; } + QValueListPrivate( const QValueListPrivate<T>& _p ) : QShared() { + node = new Node; node->next = node->prev = node; nodes = 0; + Iterator b( _p.node->next ); + Iterator e( _p.node ); + Iterator i( node ); + while( b != e ) + insert( i, *b++ ); + } + + void derefAndDelete() // ### hack to get around hp-cc brain damage + { + if ( deref() ) + delete this; + } + +#if defined(Q_TEMPLATEDLL) + // Workaround MS bug in memory de/allocation in DLL vs. EXE + virtual +#endif + ~QValueListPrivate() { + NodePtr p = node->next; + while( p != node ) { + NodePtr x = p->next; + delete p; + p = x; + } + delete node; + } + + Iterator insert( Iterator it, const T& x ) { + NodePtr p = new Node( x ); + p->next = it.node; + p->prev = it.node->prev; + it.node->prev->next = p; + it.node->prev = p; + nodes++; + return p; + } + + Iterator remove( Iterator it ) { + ASSERT ( it.node != node ); + NodePtr next = it.node->next; + NodePtr prev = it.node->prev; + prev->next = next; + next->prev = prev; + delete it.node; + nodes--; + return Iterator( next ); + } + + NodePtr find( NodePtr start, const T& x ) const { + ConstIterator first( start ); + ConstIterator last( node ); + while( first != last) { + if ( *first == x ) + return first.node; + ++first; + } + return last.node; + } + + int findIndex( NodePtr start, const T& x ) const { + ConstIterator first( start ); + ConstIterator last( node ); + int pos = 0; + while( first != last) { + if ( *first == x ) + return pos; + ++first; + ++pos; + } + return -1; + } + + uint contains( const T& x ) const { + uint result = 0; + Iterator first = Iterator( node->next ); + Iterator last = Iterator( node ); + while( first != last) { + if ( *first == x ) + ++result; + ++first; + } + return result; + } + + void remove( const T& x ) { + Iterator first = Iterator( node->next ); + Iterator last = Iterator( node ); + while( first != last) { + if ( *first == x ) + first = remove( first ); + else + ++first; + } + } + + NodePtr at( uint i ) const { + ASSERT( i <= nodes ); + NodePtr p = node->next; + for( uint x = 0; x < i; ++x ) + p = p->next; + return p; + } + + void clear() { + nodes = 0; + NodePtr p = node->next; + while( p != node ) { + NodePtr next = p->next; + delete p; + p = next; + } + node->next = node->prev = node; + } + + NodePtr node; + uint nodes; +}; + +template <class T> +class Q_EXPORT QValueList +{ +public: + /** + * Typedefs + */ + typedef QValueListIterator<T> Iterator; + typedef QValueListConstIterator<T> ConstIterator; + typedef T ValueType; + + /** + * API + */ + QValueList() { sh = new QValueListPrivate<T>; } + QValueList( const QValueList<T>& l ) { sh = l.sh; sh->ref(); } + ~QValueList() { sh->derefAndDelete(); } + + QValueList<T>& operator= ( const QValueList<T>& l ) + { + l.sh->ref(); + sh->derefAndDelete(); + sh = l.sh; + return *this; + } + + QValueList<T> operator+ ( const QValueList<T>& l ) const + { + QValueList<T> l2( *this ); + for( ConstIterator it = l.begin(); it != l.end(); ++it ) + l2.append( *it ); + return l2; + } + + QValueList<T>& operator+= ( const QValueList<T>& l ) + { + for( ConstIterator it = l.begin(); it != l.end(); ++it ) + append( *it ); + return *this; + } + + bool operator== ( const QValueList<T>& l ) const + { + if ( count() != l.count() ) + return FALSE; + ConstIterator it2 = begin(); + ConstIterator it = l.begin(); + for( ; it != l.end(); ++it, ++it2 ) + if ( !( *it == *it2 ) ) + return FALSE; + return TRUE; + } + + bool operator!= ( const QValueList<T>& l ) const { return !( *this == l ); } + + Iterator begin() { detach(); return Iterator( sh->node->next ); } + ConstIterator begin() const { return ConstIterator( sh->node->next ); } + Iterator end() { detach(); return Iterator( sh->node ); } + ConstIterator end() const { return ConstIterator( sh->node ); } + Iterator fromLast() { detach(); return Iterator( sh->node->prev ); } + ConstIterator fromLast() const { return ConstIterator( sh->node->prev ); } + + bool isEmpty() const { return ( sh->nodes == 0 ); } + + Iterator insert( Iterator it, const T& x ) { detach(); return sh->insert( it, x ); } + + Iterator append( const T& x ) { detach(); return sh->insert( end(), x ); } + Iterator prepend( const T& x ) { detach(); return sh->insert( begin(), x ); } + + Iterator remove( Iterator it ) { detach(); return sh->remove( it ); } + void remove( const T& x ) { detach(); sh->remove( x ); } + + T& first() { detach(); return sh->node->next->data; } + const T& first() const { return sh->node->next->data; } + T& last() { detach(); return sh->node->prev->data; } + const T& last() const { return sh->node->prev->data; } + + T& operator[] ( uint i ) { detach(); return sh->at(i)->data; } + const T& operator[] ( uint i ) const { return sh->at(i)->data; } + Iterator at( uint i ) { detach(); return Iterator( sh->at(i) ); } + ConstIterator at( uint i ) const { return ConstIterator( sh->at(i) ); } + Iterator find ( const T& x ) { detach(); return Iterator( sh->find( sh->node->next, x) ); } + ConstIterator find ( const T& x ) const { return ConstIterator( sh->find( sh->node->next, x) ); } + Iterator find ( Iterator it, const T& x ) { detach(); return Iterator( sh->find( it.node, x ) ); } + ConstIterator find ( ConstIterator it, const T& x ) const { return ConstIterator( sh->find( it.node, x ) ); } + int findIndex( const T& x ) const { return sh->findIndex( sh->node->next, x) ; } + uint contains( const T& x ) const { return sh->contains( x ); } + + uint count() const { return sh->nodes; } + + void clear() { if ( sh->count == 1 ) sh->clear(); else { sh->deref(); sh = new QValueListPrivate<T>; } } + + + QValueList<T>& operator+= ( const T& x ) + { + append( x ); + return *this; + } + QValueList<T>& operator<< ( const T& x ) + { + append( x ); + return *this; + } + + +protected: + /** + * Helpers + */ + void detach() { if ( sh->count > 1 ) { sh->deref(); sh = new QValueListPrivate<T>( *sh ); } } + + /** + * Variables + */ + QValueListPrivate<T>* sh; +}; + +#ifndef QT_NO_DATASTREAM +template<class T> +inline QDataStream& operator>>( QDataStream& s, QValueList<T>& l ) +{ + l.clear(); + Q_UINT32 c; + s >> c; + for( Q_UINT32 i = 0; i < c; ++i ) + { + T t; + s >> t; + l.append( t ); + } + return s; +} + +template<class T> +inline QDataStream& operator<<( QDataStream& s, const QValueList<T>& l ) +{ + s << (Q_UINT32)l.count(); + QValueListConstIterator<T> it = l.begin(); + for( ; it != l.end(); ++it ) + s << *it; + return s; +} +#endif // QT_NO_DATASTREAM +#endif // QVALUELIST_H diff --git a/trunk/qtools/qvaluestack.h b/trunk/qtools/qvaluestack.h new file mode 100644 index 0000000..3fb61fd --- /dev/null +++ b/trunk/qtools/qvaluestack.h @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** +** Definition of QValueStack class +** +** Created : 990925 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QVALUESTACK_H +#define QVALUESTACK_H + +#ifndef QT_H +#include "qvaluelist.h" +#endif // QT_H + + +template<class T> +class Q_EXPORT QValueStack : public QValueList<T> +{ +public: + QValueStack() {} + ~QValueStack() {} + void push( const T& d ) { append(d); } + T pop() + { + T elem( this->last() ); + if ( !this->isEmpty() ) + this->remove( this->fromLast() ); + return elem; + } + T& top() { return this->last(); } + const T& top() const { return this->last(); } +}; + +#endif diff --git a/trunk/qtools/qvector.doc b/trunk/qtools/qvector.doc new file mode 100644 index 0000000..2acf567 --- /dev/null +++ b/trunk/qtools/qvector.doc @@ -0,0 +1,344 @@ +/**************************************************************************** +** +** +** QVector class documentation +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + + +/***************************************************************************** + QVector documentation + *****************************************************************************/ + +// BEING REVISED: ettrich +/*! + \class QVector qvector.h + + \brief The QVector class is a template collection class that + provides a vector (array). + + \ingroup tools + + QVector is implemented as a template class. Define a template + instance QVector\<X\> to create a vector that contains pointers to + X, or X*. + + A vector is the same as an array. The main difference between + QVector and QArray is that QVector stores pointers to the elements, + while QArray stores the elements themselves (i.e. QArray is + value-based). + + Unless where otherwise stated, all functions that remove items from + the vector will also delete the element pointed to if auto-deletion + is enabled - see setAutoDelete(). By default, auto-deletion is + disabled. This behaviour can be changed in a subclass by + reimplementing the virtual method deleteItem(). + + Functions that compares items, e.g. find() and sort(), will do so + using the virtual function compareItems(). The default + implementation of this function will only compare the absolute + pointer values. Reimplement compareItems() in a subclass to get + searching and sorting based on the item contents. + + \sa \link collection.html Collection Classes\endlink, QArray +*/ + +/*! + \fn QVector::QVector() + + Constructs a null vector. + + \sa isNull() +*/ + +/*! + \fn QVector::QVector( uint size ) + + Constructs an vector with room for \a size items. Makes a null + vector if \a size == 0. + + All \a size positions in the vector are initialized to 0. + + \sa size(), resize(), isNull() +*/ + +/*! + \fn QVector::QVector( const QVector<type> &v ) + + Constructs a copy of \a v. Only the pointers are copied (i.e. shallow copy). +*/ + +/*! + \fn QVector::~QVector() + + Removes all items from the vector, and destroys the vector itself. + + \sa clear() +*/ + +/*! + \fn QVector<type> &QVector::operator=( const QVector<type> &v ) + + Assigns \a v to this vector and returns a reference to this vector. + + This vector is first cleared, then all the items from \a v is copied + into this vector. Only the pointers are copied (i.e. shallow copy). + + \sa clear() +*/ + +/*! + \fn type **QVector::data() const + Returns a pointer to the actual vector data, which is an array of type*. + + The vector is a null vector if data() == 0 (null pointer). + + \sa isNull() +*/ + +/*! + \fn uint QVector::size() const + + Returns the size of the vector, i.e. the number of vector + positions. This is also the maximum number of items the vector can + hold. + + The vector is a null vector if size() == 0. + + \sa isNull(), resize(), count() +*/ + +/*! + \fn uint QVector::count() const + + Returns the number of items in the vector. The vector is empty if + count() == 0. + + \sa isEmpty(), size() +*/ + +/*! + \fn bool QVector::isEmpty() const + + Returns TRUE if the vector is empty, i.e. count() == 0, otherwise FALSE. + + \sa count() +*/ + +/*! + \fn bool QVector::isNull() const + + Returns TRUE if the vector is null, otherwise FALSE. + + A null vector has size() == 0 and data() == 0. + + \sa size() +*/ + +/*! + \fn bool QVector::resize( uint size ) + Resizes (expands or shrinks) the vector to \a size elements. The array + becomes a null array if \a size == 0. + + Any items in position \a size or beyond in the vector are removed. + New positions are initialized 0. + + Returns TRUE if successful, or FALSE if the memory cannot be allocated. + + \sa size(), isNull() +*/ + +/*! + \fn bool QVector::insert( uint i, const type *d ) + + Sets position \a i in the vector to contain the item \a d. \a i must + be less than size(). Any previous element in position \a i is removed. + + \sa at() +*/ + +/*! + \fn bool QVector::remove( uint i ) + + Removes the item at position \a i in the vector, if there is one. + \a i must be less than size(). + + Returns TRUE unless \a i is out of range. + + \sa take(), at() +*/ + +/*! + \fn type* QVector::take( uint i ) + + Returns the item at position \a i in the vector, and removes that + item from the vector. \a i must be less than size(). If there is no + item at position \a i, 0 is returned. + + In contrast to remove(), this function does \e not call deleteItem() + for the removed item. + + \sa remove(), at() +*/ + +/*! + \fn void QVector::clear() + + Removes all items from the vector, and destroys the vector + itself. + + The vector becomes a null vector. + + \sa isNull() +*/ + +/*! + \fn bool QVector::fill( const type *d, int size ) + + Inserts item \a d in all positions in the vector. Any existing items + are removed. If \a d is 0, the vector becomes empty. + + If \a size >= 0, the vector is first resized to \a size. By default, + \a size is -1. + + Returns TRUE if successful, or FALSE if the memory cannot be allocated + (only if a resize has been requested). + + \sa resize(), insert(), isEmpty() +*/ + +/*! + \fn void QVector::sort() + + Sorts the items in ascending order. Any empty positions will be put + last. + + Compares items using the virtual function compareItems(). + + \sa bsearch() +*/ + +/*! + \fn int QVector::bsearch( const type* d ) const + + In a sorted array, finds the first occurrence of \a d using binary + search. For a sorted array, this is generally much faster than + find(), which does a linear search. + + Returns the position of \a d, or -1 if \a d could not be found. \a d + may not be 0. + + Compares items using the virtual function compareItems(). + + \sa sort(), find() +*/ + + +/*! + \fn int QVector::findRef( const type *d, uint i ) const + + Finds the first occurrence of the item pointer \a d in the vector, + using linear search. The search starts at position \a i, which must + be less than size(). \a i is by default 0; i.e. the search starts at + the start of the vector. + + Returns the position of \a d, or -1 if \a d could not be found. + + This function does \e not use compareItems() to compare items. + + \sa find(), bsearch() +*/ + +/*! + \fn int QVector::find( const type *d, uint i ) const + + Finds the first occurrence of item \a d in the vector, using linear + search. The search starts at position \a i, which must be less than + size(). \a i is by default 0; i.e. the search starts at the start of + the vector. + + Returns the position of \e v, or -1 if \e v could not be found. + + Compares items using the virtual function compareItems(). + + \sa findRef(), bsearch() +*/ + + +/*! + \fn uint QVector::containsRef( const type *d ) const + + Returns the number of occurrences of the item pointer \a d in the + vector. + + This function does \e not use compareItems() to compare items. + + \sa findRef() +*/ + +/*! + \fn uint QVector::contains( const type *d ) const + + Returns the number of occurrences of item \a d in the vector. + + Compares items using the virtual function compareItems(). + + \sa containsRef() +*/ + +/*! + \fn type *QVector::operator[]( int i ) const + + Returns the item at position \a i, or 0 if there is no item at + that position. \a i must be less than size(). + + Equivalent to at( \a i ). + + \sa at() +*/ + +/*! + \fn type *QVector::at( uint i ) const + + Returns the item at position \a i, or 0 if there is no item at + that position. \a i must be less than size(). +*/ + + +/*! + \fn void QVector::toList( QGList *list ) const + + Copies all items in this vector to the list \a list. First, \a list + is cleared, then all items are appended to \a list. + + \sa QList, QStack, QQueue +*/ + diff --git a/trunk/qtools/qvector.h b/trunk/qtools/qvector.h new file mode 100644 index 0000000..36f0be7 --- /dev/null +++ b/trunk/qtools/qvector.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** +** Definition of QVector template/macro class +** +** Created : 930907 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QVECTOR_H +#define QVECTOR_H + +#ifndef QT_H +#include "qgvector.h" +#endif // QT_H + + +template<class type> class QVector : public QGVector +{ +public: + QVector() {} + QVector( uint size ) : QGVector(size) {} + QVector( const QVector<type> &v ) : QGVector(v) {} + ~QVector() { clear(); } + QVector<type> &operator=(const QVector<type> &v) + { return (QVector<type>&)QGVector::operator=(v); } + type **data() const { return (type **)QGVector::data(); } + uint size() const { return QGVector::size(); } + uint count() const { return QGVector::count(); } + bool isEmpty() const { return QGVector::count() == 0; } + bool isNull() const { return QGVector::size() == 0; } + bool resize( uint size ) { return QGVector::resize(size); } + bool insert( uint i, const type *d){ return QGVector::insert(i,(Item)d); } + bool remove( uint i ) { return QGVector::remove(i); } + type *take( uint i ) { return (type *)QGVector::take(i); } + void clear() { QGVector::clear(); } + bool fill( const type *d, int size=-1 ) + { return QGVector::fill((Item)d,size);} + void sort() { QGVector::sort(); } + int bsearch( const type *d ) const{ return QGVector::bsearch((Item)d); } + int findRef( const type *d, uint i=0 ) const + { return QGVector::findRef((Item)d,i);} + int find( const type *d, uint i= 0 ) const + { return QGVector::find((Item)d,i); } + uint containsRef( const type *d ) const + { return QGVector::containsRef((Item)d); } + uint contains( const type *d ) const + { return QGVector::contains((Item)d); } + type *operator[]( int i ) const { return (type *)QGVector::at(i); } + type *at( uint i ) const { return (type *)QGVector::at(i); } + void toList( QGList *list ) const { QGVector::toList(list); } +private: + void deleteItem( Item d ) { if ( del_item ) delete (type *)d; } +}; + + +#endif // QVECTOR_H diff --git a/trunk/qtools/qxml.cpp b/trunk/qtools/qxml.cpp new file mode 100644 index 0000000..c05ab88 --- /dev/null +++ b/trunk/qtools/qxml.cpp @@ -0,0 +1,6046 @@ +/**************************************************************************** +** +** +** Implementation of QXmlSimpleReader and related classes. +** +** Created : 000518 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the XML module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition licenses may use this +** file in accordance with the Qt Commercial License Agreement provided +** with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#define QT_XML_CPP +#include "qxml.h" +#include "qtextcodec.h" +#include "qbuffer.h" + +#ifndef QT_NO_XML +// NOT REVISED + +// Error strings for the XML reader +#define XMLERR_OK "no error occured" +#define XMLERR_TAGMISMATCH "tag mismatch" +#define XMLERR_UNEXPECTEDEOF "unexpected end of file" +#define XMLERR_FINISHEDPARSINGWHILENOTEOF "parsing is finished but end of file is not reached" +#define XMLERR_LETTEREXPECTED "letter is expected" +#define XMLERR_ERRORPARSINGELEMENT "error while parsing element" +#define XMLERR_ERRORPARSINGPROLOG "error while parsing prolog" +#define XMLERR_ERRORPARSINGMAINELEMENT "error while parsing main element" +#define XMLERR_ERRORPARSINGCONTENT "error while parsing content" +#define XMLERR_ERRORPARSINGNAME "error while parsing name" +#define XMLERR_ERRORPARSINGNMTOKEN "error while parsing Nmtoken" +#define XMLERR_ERRORPARSINGATTRIBUTE "error while parsing attribute" +#define XMLERR_ERRORPARSINGMISC "error while parsing misc" +#define XMLERR_ERRORPARSINGCHOICE "error while parsing choice or seq" +#define XMLERR_ERRORBYCONSUMER "error triggered by consumer" +#define XMLERR_UNEXPECTEDCHARACTER "unexpected character" +#define XMLERR_EQUALSIGNEXPECTED "expected '=' but not found" +#define XMLERR_QUOTATIONEXPECTED "expected \" or ' but not found" +#define XMLERR_ERRORPARSINGREFERENCE "error while parsing reference" +#define XMLERR_ERRORPARSINGPI "error while parsing processing instruction" +#define XMLERR_ERRORPARSINGATTLISTDECL "error while parsing attribute list declaration" +#define XMLERR_ERRORPARSINGATTTYPE "error while parsing attribute type declaration" +#define XMLERR_ERRORPARSINGATTVALUE "error while parsing attribute value declaration" +#define XMLERR_ERRORPARSINGELEMENTDECL "error while parsing element declaration" +#define XMLERR_ERRORPARSINGENTITYDECL "error while parsing entity declaration" +#define XMLERR_ERRORPARSINGNOTATIONDECL "error while parsing notation declaration" +#define XMLERR_ERRORPARSINGEXTERNALID "error while parsing external id" +#define XMLERR_ERRORPARSINGCOMMENT "error while parsing comment" +#define XMLERR_ERRORPARSINGENTITYVALUE "error while parsing entity value declaration" +#define XMLERR_CDSECTHEADEREXPECTED "expected the header for a cdata section" +#define XMLERR_MORETHANONEDOCTYPE "more than one document type definition" +#define XMLERR_ERRORPARSINGDOCTYPE "error while parsing document type definition" +#define XMLERR_INVALIDNAMEFORPI "invalid name for processing instruction" +#define XMLERR_VERSIONEXPECTED "version expected while reading the XML declaration" +#define XMLERR_EDECLORSDDECLEXPECTED "EDecl or SDDecl expected while reading the XML declaration" +#define XMLERR_SDDECLEXPECTED "SDDecl expected while reading the XML declaration" +#define XMLERR_WRONGVALUEFORSDECL "wrong value for standalone declaration" +#define XMLERR_UNPARSEDENTITYREFERENCE "unparsed entity reference in wrong context" +#define XMLERR_INTERNALGENERALENTITYINDTD "internal general entity reference not allowed in DTD" +#define XMLERR_EXTERNALGENERALENTITYINDTD "external parsed general entity reference not allowed in DTD" +#define XMLERR_EXTERNALGENERALENTITYINAV "external parsed general entity reference not allowed in attribute value" + + +// the constants for the lookup table +static const signed char cltWS = 0; // white space +static const signed char cltPer = 1; // % +static const signed char cltAmp = 2; // & +static const signed char cltGt = 3; // > +static const signed char cltLt = 4; // < +static const signed char cltSlash = 5; // / +static const signed char cltQm = 6; // ? +static const signed char cltEm = 7; // ! +static const signed char cltDash = 8; // - +static const signed char cltCB = 9; // ] +static const signed char cltOB = 10; // [ +static const signed char cltEq = 11; // = +static const signed char cltDq = 12; // " +static const signed char cltSq = 13; // ' +static const signed char cltUnknown = 14; + +// character lookup table +static const signed char charLookupTable[256]={ + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x00 - 0x07 + cltUnknown, // 0x08 + cltWS, // 0x09 \t + cltWS, // 0x0A \n + cltUnknown, // 0x0B + cltUnknown, // 0x0C + cltWS, // 0x0D \r + cltUnknown, // 0x0E + cltUnknown, // 0x0F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x17 - 0x16 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x18 - 0x1F + cltWS, // 0x20 Space + cltEm, // 0x21 ! + cltDq, // 0x22 " + cltUnknown, // 0x23 + cltUnknown, // 0x24 + cltPer, // 0x25 % + cltAmp, // 0x26 & + cltSq, // 0x27 ' + cltUnknown, // 0x28 + cltUnknown, // 0x29 + cltUnknown, // 0x2A + cltUnknown, // 0x2B + cltUnknown, // 0x2C + cltDash, // 0x2D - + cltUnknown, // 0x2E + cltSlash, // 0x2F / + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x30 - 0x37 + cltUnknown, // 0x38 + cltUnknown, // 0x39 + cltUnknown, // 0x3A + cltUnknown, // 0x3B + cltLt, // 0x3C < + cltEq, // 0x3D = + cltGt, // 0x3E > + cltQm, // 0x3F ? + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x40 - 0x47 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x48 - 0x4F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x50 - 0x57 + cltUnknown, // 0x58 + cltUnknown, // 0x59 + cltUnknown, // 0x5A + cltOB, // 0x5B [ + cltUnknown, // 0x5C + cltCB, // 0x5D ] + cltUnknown, // 0x5E + cltUnknown, // 0x5F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x60 - 0x67 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x68 - 0x6F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x70 - 0x77 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x78 - 0x7F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x80 - 0x87 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x88 - 0x8F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x90 - 0x97 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0x98 - 0x9F + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xA0 - 0xA7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xA8 - 0xAF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xB0 - 0xB7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xB8 - 0xBF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xC0 - 0xC7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xC8 - 0xCF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xD0 - 0xD7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xD8 - 0xDF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xE0 - 0xE7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xE8 - 0xEF + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, // 0xF0 - 0xF7 + cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown, cltUnknown // 0xF8 - 0xFF +}; + + +class QXmlNamespaceSupportPrivate +{ +}; +class QXmlAttributesPrivate +{ +}; +class QXmlInputSourcePrivate +{ +}; +class QXmlParseExceptionPrivate +{ +}; +class QXmlLocatorPrivate +{ +}; +class QXmlDefaultHandlerPrivate +{ +}; + +#if defined(Q_FULL_TEMPLATE_INSTANTIATION) +bool operator==( const QMap<QString, QString>, const QMap<QString, QString> ) +{ + return FALSE; +} +#endif + +/*! + \class QXmlParseException qxml.h + \brief The QXmlParseException class is used to report errors with the + QXmlErrorHandler interface. + + \module XML + + \sa QXmlErrorHandler +*/ +/*! + \fn QXmlParseException::QXmlParseException( const QString& name, int c, int l, const QString& p, const QString& s ) + + Constructs a parse exception with the error string \a name in the column + \a c and line \a l for the public identifier \a p and the system identifier + \a s. +*/ +/*! + Returns the error message. +*/ +QString QXmlParseException::message() const +{ + return msg; +} +/*! + Returns the column number the error occured. +*/ +int QXmlParseException::columnNumber() const +{ + return column; +} +/*! + Returns the line number the error occured. +*/ +int QXmlParseException::lineNumber() const +{ + return line; +} +/*! + Returns the public identifier the error occured. +*/ +QString QXmlParseException::publicId() const +{ + return pub; +} +/*! + Returns the system identifier the error occured. +*/ +QString QXmlParseException::systemId() const +{ + return sys; +} + + +/*! + \class QXmlLocator qxml.h + \brief The QXmlLocator class provides the XML handler classes with + information about the actual parsing position. + + \module XML + + The reader reports a QXmlLocator to the content handler before he starts to + parse the document. This is done with the + QXmlContentHandler::setDocumentLocator() function. The handler classes can + now use this locator to get the actual position the reader is at. +*/ +/*! + \fn QXmlLocator::QXmlLocator( QXmlSimpleReader* parent ) + + Constructor. +*/ +/*! + \fn QXmlLocator::~QXmlLocator() + + Destructor. +*/ +/*! + Gets the column number (starting with 1) or -1 if there is no column number + available. +*/ +int QXmlLocator::columnNumber() +{ + return ( reader->columnNr == -1 ? -1 : reader->columnNr + 1 ); +} +/*! + Gets the line number (starting with 1) or -1 if there is no line number + available. +*/ +int QXmlLocator::lineNumber() +{ + return ( reader->lineNr == -1 ? -1 : reader->lineNr + 1 ); +} + + +/********************************************* + * + * QXmlNamespaceSupport + * + *********************************************/ + +/*! + \class QXmlNamespaceSupport qxml.h + \brief The QXmlNamespaceSupport class is a helper class for XML readers which + want to include namespace support. + + \module XML + + It provides some functions that makes it easy to handle namespaces. Its main + use is for subclasses of QXmlReader which want to provide namespace + support. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ + +/*! + Constructs a QXmlNamespaceSupport. +*/ +QXmlNamespaceSupport::QXmlNamespaceSupport() +{ + reset(); +} + +/*! + Destructs a QXmlNamespaceSupport. +*/ +QXmlNamespaceSupport::~QXmlNamespaceSupport() +{ +} + +/*! + This function declares a prefix in the current namespace context; the prefix + will remain in force until this context is popped, unless it is shadowed in a + descendant context. + + Note that there is an asymmetry in this library: while prefix() will not + return the default "" prefix, even if you have declared one; to check for a + default prefix, you have to look it up explicitly using uri(). This + asymmetry exists to make it easier to look up prefixes for attribute names, + where the default prefix is not allowed. +*/ +void QXmlNamespaceSupport::setPrefix( const QString& pre, const QString& uri ) +{ + if( pre.isNull() ) { + ns.insert( "", uri ); + } else { + ns.insert( pre, uri ); + } +} + +/*! + Returns one of the prefixes mapped to a namespace URI. + + If more than one prefix is currently mapped to the same URI, this function + will make an arbitrary selection; if you want all of the prefixes, use the + prefixes() function instead. + + Note: this will never return the empty (default) prefix; to check for a + default prefix, use the uri() function with an argument of "". +*/ +QString QXmlNamespaceSupport::prefix( const QString& uri ) const +{ + QMap<QString, QString>::ConstIterator itc, it = ns.begin(); + while ( (itc=it) != ns.end() ) { + ++it; + if ( itc.data() == uri && !itc.key().isEmpty() ) + return itc.key(); + } + return ""; +} + +/*! + Looks up a prefix in the current context and returns the currently-mapped + namespace URI. Use the empty string ("") for the default namespace. +*/ +QString QXmlNamespaceSupport::uri( const QString& prefix ) const +{ + const QString& returi = ns[ prefix ]; + return returi; +} + +/*! + Splits the name at the ':' and returns the prefix and the local name. +*/ +void QXmlNamespaceSupport::splitName( const QString& qname, + QString& prefix, QString& localname ) const +{ + uint pos; + // search the ':' + for( pos=0; pos<qname.length(); pos++ ) { + if ( qname.at(pos) == ':' ) + break; + } + // and split + prefix = qname.left( pos ); + localname = qname.mid( pos+1 ); +} + +/*! + Processes a raw XML 1.0 name in the current context by removing the prefix + and looking it up among the prefixes currently declared. + + First parameter is the raw XML 1.0 name to be processed. The second parameter + is a flag wheter the name is the name of an attribute (TRUE) or not (FALSE). + + The return values will be stored in the last two parameters as follows: + <ul> + <li> The namespace URI, or an empty string if none is in use. + <li> The local name (without prefix). + </ul> + + If the raw name has a prefix that has not been declared, then the return + value will be empty. + + Note that attribute names are processed differently than element names: an + unprefixed element name will received the default namespace (if any), while + an unprefixed element name will not +*/ +void QXmlNamespaceSupport::processName( const QString& qname, + bool isAttribute, + QString& nsuri, QString& localname ) const +{ + uint pos; + // search the ':' + for( pos=0; pos<qname.length(); pos++ ) { + if ( qname.at(pos) == ':' ) + break; + } + if ( pos < qname.length() ) { + // there was a ':' + nsuri = uri( qname.left( pos ) ); + localname = qname.mid( pos+1 ); + } else { + // there was no ':' + if ( isAttribute ) { + nsuri = ""; // attributes don't take default namespace + } else { + nsuri = uri( "" ); // get default namespace + } + localname = qname; + } +} + +/*! + Returns an enumeration of all prefixes currently declared. + + Note: if there is a default prefix, it will not be returned in this + enumeration; check for the default prefix using uri() with an argument + of "". +*/ +QStringList QXmlNamespaceSupport::prefixes() const +{ + QStringList list; + + QMap<QString, QString>::ConstIterator itc, it = ns.begin(); + while ( (itc=it) != ns.end() ) { + ++it; + if ( !itc.key().isEmpty() ) + list.append( itc.key() ); + } + return list; +} + +/*! + Returns a list of all prefixes currently declared for a URI. + + The xml: prefix will be included. If you want only one prefix that's + mapped to the namespace URI, and you don't care which one you get, use the + prefix() function instead. + + Note: the empty (default) prefix is never included in this enumeration; to + check for the presence of a default namespace, use uri() with an + argument of "". +*/ +QStringList QXmlNamespaceSupport::prefixes( const QString& uri ) const +{ + QStringList list; + + QMap<QString, QString>::ConstIterator itc, it = ns.begin(); + while ( (itc=it) != ns.end() ) { + ++it; + if ( itc.data() == uri && !itc.key().isEmpty() ) + list.append( itc.key() ); + } + return list; +} + +/*! + Starts a new namespace context. + + Normally, you should push a new context at the beginning of each XML element: + the new context will automatically inherit the declarations of its parent + context, but it will also keep track of which declarations were made within + this context. +*/ +void QXmlNamespaceSupport::pushContext() +{ + nsStack.push( ns ); +} + +/*! + Reverts to the previous namespace context. + + Normally, you should pop the context at the end of each XML element. After + popping the context, all namespace prefix mappings that were previously in + force are restored. +*/ +void QXmlNamespaceSupport::popContext() +{ + if( !nsStack.isEmpty() ) + ns = nsStack.pop(); +} + +/*! + Resets this namespace support object for reuse. +*/ +void QXmlNamespaceSupport::reset() +{ + nsStack.clear(); + ns.clear(); + ns.insert( "xml", "http://www.w3.org/XML/1998/namespace" ); // the XML namespace +} + + + +/********************************************* + * + * QXmlAttributes + * + *********************************************/ + +/*! + \class QXmlAttributes qxml.h + \brief The QXmlAttributes class provides XML attributes. + + \module XML + + If attributes are reported by QXmlContentHandler::startElement() this + class is used to pass the attribute values. It provides you with different + functions to access the attribute names and values. +*/ +/*! + \fn QXmlAttributes::QXmlAttributes() + + Constructs an empty attribute list. +*/ +/*! + \fn QXmlAttributes::~QXmlAttributes() + + Destructs attributes. +*/ + +/*! + Look up the index of an attribute by an XML 1.0 qualified name. + + Returns the index of the attribute (starting with 0) or -1 if it wasn't + found. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +int QXmlAttributes::index( const QString& qName ) const +{ + return qnameList.findIndex( qName ); +} + +/*! + Looks up the index of an attribute by a namespace name. + + \a uri specifies the namespace URI, or the empty string if the name has no + namespace URI. \a localPart specifies the attribute's local name. + + Returns the index of the attribute (starting with 0) or -1 if it wasn't + found. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +int QXmlAttributes::index( const QString& uri, const QString& localPart ) const +{ + uint count = uriList.count(); + for ( uint i=0; i<count; i++ ) { + if ( uriList[i] == uri && localnameList[i] == localPart ) + return i; + } + return -1; +} + +/*! + Returns the number of attributes in the list. +*/ +int QXmlAttributes::length() const +{ + return valueList.count(); +} + +/*! + Looks up an attribute's local name by index (starting with 0). + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +QString QXmlAttributes::localName( int index ) const +{ + return localnameList[index]; +} + +/*! + Looks up an attribute's XML 1.0 qualified name by index (starting with 0). + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +QString QXmlAttributes::qName( int index ) const +{ + return qnameList[index]; +} + +/*! + Looks up an attribute's namespace URI by index (starting with 0). + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +QString QXmlAttributes::uri( int index ) const +{ + return uriList[index]; +} + +/*! + Looks up an attribute's type by index (starting with 0). + + At the moment only 'CDATA' is returned. +*/ +QString QXmlAttributes::type( int ) const +{ + return "CDATA"; +} + +/*! + Looks up an attribute's type by XML 1.0 qualified name. + + At the moment only 'CDATA' is returned. +*/ +QString QXmlAttributes::type( const QString& ) const +{ + return "CDATA"; +} + +/*! + Looks up an attribute's type by namespace name. + + The first parameter specifies the namespace URI, or the empty string if + the name has no namespace URI. The second parameter specifies the + attribute's local name. + + At the moment only 'CDATA' is returned. +*/ +QString QXmlAttributes::type( const QString&, const QString& ) const +{ + return "CDATA"; +} + +/*! + Looks up an attribute's value by index (starting with 0). +*/ +QString QXmlAttributes::value( int index ) const +{ + return valueList[index]; +} + +/*! + Looks up an attribute's value by XML 1.0 qualified name. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +QString QXmlAttributes::value( const QString& qName ) const +{ + int i = index( qName ); + if ( i == -1 ) + return QString::null; + return valueList[ i ]; +} + +/*! + Looks up an attribute's value by namespace name. + + \a uri specifies the namespace URI, or the empty string if the name has no + namespace URI. \a localName specifies the attribute's local name. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. +*/ +QString QXmlAttributes::value( const QString& uri, const QString& localName ) const +{ + int i = index( uri, localName ); + if ( i == -1 ) + return QString::null; + return valueList[ i ]; +} + + +/********************************************* + * + * QXmlInputSource + * + *********************************************/ + +/*! + \class QXmlInputSource qxml.h + \brief The QXmlInputSource class is the source where XML data is read from. + + \module XML + + All subclasses of QXmlReader read the input from this class. +*/ + +/*! + Returns all the data this input source contains. +*/ +const QString& QXmlInputSource::data() const +{ + return input; +} + +/*! + Constructs a input source which contains no data. +*/ +QXmlInputSource::QXmlInputSource( ) +{ + input = ""; +} + +/*! + Constructs a input source and get the data from the text stream. +*/ +QXmlInputSource::QXmlInputSource( QTextStream& stream ) +{ + QByteArray rawData; + if ( stream.device()->isDirectAccess() ) { + rawData = stream.device()->readAll(); + } else { + int nread = 0; + const int bufsize = 512; + while ( !stream.device()->atEnd() ) { + rawData.resize( nread + bufsize ); + nread += stream.device()->readBlock( rawData.data()+nread, bufsize ); + } + rawData.resize( nread ); + } + readInput( rawData ); +} + +/*! + Constructs a input source and get the data from a file. If the file cannot be + read the input source is empty. +*/ +QXmlInputSource::QXmlInputSource( QFile& file ) +{ + if ( !file.open(IO_ReadOnly) ) { + input = ""; + return; + } + QByteArray rawData = file.readAll(); + readInput( rawData ); + file.close(); +} + +/*! + Destructor. +*/ +QXmlInputSource::~QXmlInputSource() +{ +} + +/*! + Sets the data of the input source to \a dat. +*/ +void QXmlInputSource::setData( const QString& dat ) +{ + input = dat; +} + +/*! + Read the XML file from the byte array; try to recoginize the encoding. +*/ +// ### The input source should not do the encoding detection! +void QXmlInputSource::readInput( QByteArray& rawData ) +{ + QBuffer buf( rawData ); + buf.open( IO_ReadOnly ); + QTextStream *stream = new QTextStream( &buf ); + QChar tmp; + // assume UTF8 or UTF16 at first + stream->setEncoding( QTextStream::UnicodeUTF8 ); + input = ""; + // read the first 5 characters + for ( int i=0; i<5; i++ ) { + *stream >> tmp; + input += tmp; + } + // starts the document with an XML declaration? + if ( input == "<?xml" ) { + // read the whole XML declaration + do { + *stream >> tmp; + input += tmp; + } while( tmp != '>' ); + // and try to find out if there is an encoding + int pos = input.find( "encoding" ); + if ( pos != -1 ) { + QString encoding; + do { + pos++; + if ( pos > (int)input.length() ) + goto finished; + } while( input[pos] != '"' && input[pos] != '\'' ); + pos++; + while( input[pos] != '"' && input[pos] != '\'' ) { + encoding += input[pos]; + pos++; + if ( pos > (int)input.length() ) + goto finished; + } + delete stream; + stream = new QTextStream( &buf ); + stream->setCodec( QTextCodec::codecForName( encoding ) ); + buf.reset(); + input = ""; + } + } +finished: + input += stream->read(); + delete stream; + buf.close(); +} + + +/********************************************* + * + * QXmlDefaultHandler + * + *********************************************/ + +/*! + \class QXmlContentHandler qxml.h + \brief The QXmlContentHandler class provides an interface to report logical + content of XML data. + + \module XML + + If the application needs to be informed of basic parsing events, it + implements this interface and sets it with QXmlReader::setContentHandler(). + The reader reports basic document-related events like the start and end of + elements and character data through this interface. + + The order of events in this interface is very important, and mirrors the + order of information in the document itself. For example, all of an element's + content (character data, processing instructions, and/or subelements) will + appear, in order, between the startElement() event and the corresponding + endElement() event. + + The class QXmlDefaultHandler gives a default implementation for this + interface; subclassing from this class is very convenient if you want only be + informed of some parsing events. + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDTDHandler QXmlDeclHandler QXmlEntityResolver QXmlErrorHandler + QXmlLexicalHandler +*/ +/*! + \fn void QXmlContentHandler::setDocumentLocator( QXmlLocator* locator ) + + The reader calls this function before he starts parsing the document. The + argument \a locator is a pointer to a QXmlLocator which allows the + application to get the actual position of the parsing in the document. + + Do not destroy the \a locator; it is destroyed when the reader is destroyed + (do not use the \a locator after the reader got destroyed). +*/ +/*! + \fn bool QXmlContentHandler::startDocument() + + The reader calls this function when he starts parsing the document. + The reader will call this function only once before any other functions in + this class or in the QXmlDTDHandler class are called (except + QXmlContentHandler::setDocumentLocator()). + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + \sa endDocument() +*/ +/*! + \fn bool QXmlContentHandler::endDocument() + + The reader calls this function after he has finished the parsing. It + is only called once. It is the last function of all handler functions that is + called. It is called after the reader has read all input or has abandoned + parsing because of a fatal error. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + \sa startDocument() +*/ +/*! + \fn bool QXmlContentHandler::startPrefixMapping( const QString& prefix, const QString& uri ) + + The reader calls this function to signal the begin of a prefix-URI + namespace mapping scope. This information is not necessary for normal + namespace processing since the reader automatically replaces prefixes for + element and attribute names. + + Note that startPrefixMapping and endPrefixMapping calls are not guaranteed to + be properly nested relative to each-other: all startPrefixMapping events will + occur before the corresponding startElement event, and all endPrefixMapping + events will occur after the corresponding endElement event, but their order + is not otherwise guaranteed. + + The argument \a prefix is the namespace prefix being declared and the + argument \a uri is the namespace URI the prefix is mapped to. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. + + \sa endPrefixMapping() +*/ +/*! + \fn bool QXmlContentHandler::endPrefixMapping( const QString& prefix ) + + The reader calls this function to signal the end of a prefix mapping. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. + + \sa startPrefixMapping() +*/ +/*! + \fn bool QXmlContentHandler::startElement( const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts ) + + The reader calls this function when he has parsed a start element tag. + + There will be a corresponding endElement() call when the corresponding end + element tag was read. The startElement() and endElement() calls are always + nested correctly. Empty element tags (e.g. <a/>) are reported by + startElement() directly followed by a call to endElement(). + + The attribute list provided will contain only attributes with explicit + values. The attribute list will contain attributes used for namespace + declaration (i.e. attributes starting with xmlns) only if the + namespace-prefix property of the reader is TRUE. + + The argument \a uri is the namespace URI, or the empty string if the element + has no namespace URI or if namespace processing is not being performed, \a + localName is the local name (without prefix), or the empty string if + namespace processing is not being performed, \a qName is the qualified name + (with prefix), or the empty string if qualified names are not available and + \a atts are the attributes attached to the element. If there are no + attributes, \a atts is an empty attributes object + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. + + \sa endElement() +*/ +/*! + \fn bool QXmlContentHandler::endElement( const QString& namespaceURI, const QString& localName, const QString& qName ) + + The reader calls this function when he has parsed an end element tag. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + See also the <a href="xml-sax.html#namespaces">namespace description</a>. + + \sa startElement() +*/ +/*! + \fn bool QXmlContentHandler::characters( const QString& ch ) + + The reader calls this function when he has parsed a chunk of character + data (either normal character data or character data inside a CDATA section; + if you have to distinguish between those two types you have to use + QXmlLexicalHandler::startCDATA() and QXmlLexicalHandler::endCDATA() in + addition). + + Some readers will report whitespace in element content using the + ignorableWhitespace() function rather than this one (QXmlSimpleReader will + do it not though). + + A reader is allowed to report the character data of an element in more than + one chunk; e.g. a reader might want to report "a &lt; b" in three + characters() events ("a ", "<" and " b"). + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlContentHandler::ignorableWhitespace( const QString& ch ) + + Some readers may use this function to report each chunk of whitespace in + element content (QXmlSimpleReader does not though). + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlContentHandler::processingInstruction( const QString& target, const QString& data ) + + The reader calls this function when he has parsed a processing + instruction. + + \a target is the target name of the processing instruction and \a data is the + data of the processing instruction. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlContentHandler::skippedEntity( const QString& name ) + + Some readers may skip entities if they have not seen the declarations (e.g. + because they are in an external DTD). If they do so they will report it by + calling this function. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn QString QXmlContentHandler::errorString() + + The reader calls this function to get an error string if any of the handler + functions returns FALSE to him. +*/ + + +/*! + \class QXmlErrorHandler qxml.h + \brief The QXmlErrorHandler class provides an interface to report errors in + XML data. + + \module XML + + If the application is interested in reporting errors to the user or any other + customized error handling, you should subclass this class. + + You can set the error handler with QXmlReader::setErrorHandler(). + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDTDHandler QXmlDeclHandler QXmlContentHandler QXmlEntityResolver + QXmlLexicalHandler +*/ +/*! + \fn bool QXmlErrorHandler::warning( const QXmlParseException& exception ) + + A reader might use this function to report a warning. Warnings are conditions + that are not errors or fatal errors as defined by the XML 1.0 specification. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlErrorHandler::error( const QXmlParseException& exception ) + + A reader might use this function to report a recoverable error. A recoverable + error corresponds to the definiton of "error" in section 1.2 of the XML 1.0 + specification. + + The reader must continue to provide normal parsing events after invoking this + function. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlErrorHandler::fatalError( const QXmlParseException& exception ) + + A reader must use this function to report a non-recoverable error. + + If this function returns TRUE the reader might try to go on parsing and + reporting further errors; but no regular parsing events are reported. +*/ +/*! + \fn QString QXmlErrorHandler::errorString() + + The reader calls this function to get an error string if any of the handler + functions returns FALSE to him. +*/ + + +/*! + \class QXmlDTDHandler qxml.h + \brief The QXmlDTDHandler class provides an interface to report DTD content + of XML data. + + \module XML + + If an application needs information about notations and unparsed entities, + then the application implements this interface and registers an instance with + QXmlReader::setDTDHandler(). + + Note that this interface includes only those DTD events that the XML + recommendation requires processors to report: notation and unparsed entity + declarations. + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDeclHandler QXmlContentHandler QXmlEntityResolver QXmlErrorHandler + QXmlLexicalHandler +*/ +/*! + \fn bool QXmlDTDHandler::notationDecl( const QString& name, const QString& publicId, const QString& systemId ) + + The reader calls this function when he has parsed a notation + declaration. + + The argument \a name is the notation name, \a publicId is the notations's + public identifier and \a systemId is the notations's system identifier. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlDTDHandler::unparsedEntityDecl( const QString& name, const QString& publicId, const QString& systemId, const QString& notationName ) + + The reader calls this function when he finds an unparsed entity declaration. + + The argument \a name is the unparsed entity's name, \a publicId is the + entity's public identifier, \a systemId is the entity's system identifier and + \a notation is the name of the associated notation. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn QString QXmlDTDHandler::errorString() + + The reader calls this function to get an error string if any of the handler + functions returns FALSE to him. +*/ + + +/*! + \class QXmlEntityResolver qxml.h + \brief The QXmlEntityResolver class provides an interface to resolve extern + entities contained in XML data. + + \module XML + + If an application needs to implement customized handling for external + entities, it must implement this interface and register it with + QXmlReader::setEntityResolver(). + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDTDHandler QXmlDeclHandler QXmlContentHandler QXmlErrorHandler + QXmlLexicalHandler +*/ +/*! + \fn bool QXmlEntityResolver::resolveEntity( const QString& publicId, const QString& systemId, QXmlInputSource* ret ) + + The reader will call this function before he opens any external entity, + except the top-level document entity. The application may request the reader + to resolve the entity itself (\a ret is 0) or to use an entirely different + input source (\a ret points to the input source). + + The reader will delete the input source \a ret when he no longer needs it. So + you should allocate it on the heap with \c new. + + The argument \a publicId is the public identifier of the external entity, \a + systemId is the system identifier of the external entity and \a ret is the + return value of this function: if it is 0 the reader should resolve the + entity itself, if it is non-zero it must point to an input source which the + reader will use instead. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn QString QXmlEntityResolver::errorString() + + The reader calls this function to get an error string if any of the handler + functions returns FALSE to him. +*/ + + +/*! + \class QXmlLexicalHandler qxml.h + \brief The QXmlLexicalHandler class provides an interface to report lexical + content of XML data. + + \module XML + + The events in the lexical handler apply to the entire document, not just to + the document element, and all lexical handler events appear between the + content handler's startDocument and endDocument events. + + You can set the lexical handler with QXmlReader::setLexicalHandler(). + + This interface is designed after the SAX2 extension LexicalHandler. The + functions startEntity() and endEntity() are not included though. + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDTDHandler QXmlDeclHandler QXmlContentHandler QXmlEntityResolver + QXmlErrorHandler +*/ +/*! + \fn bool QXmlLexicalHandler::startDTD( const QString& name, const QString& publicId, const QString& systemId ) + + The reader calls this function to report the start of a DTD declaration, if + any. + + All declarations reported through QXmlDTDHandler or QXmlDeclHandler appear + between the startDTD() and endDTD() calls. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + \sa endDTD() +*/ +/*! + \fn bool QXmlLexicalHandler::endDTD() + + The reader calls this function to report the end of a DTD declaration, if + any. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + \sa startDTD() +*/ +/*! + \fn bool QXmlLexicalHandler::startCDATA() + + The reader calls this function to report the start of a CDATA section. The + content of the CDATA section will be reported through the regular + QXmlContentHandler::characters(). This function is intended only to report + the boundary. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + \sa endCDATA() +*/ +/*! + \fn bool QXmlLexicalHandler::endCDATA() + + The reader calls this function to report the end of a CDATA section. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. + + \sa startCDATA() +*/ +/*! + \fn bool QXmlLexicalHandler::comment( const QString& ch ) + + The reader calls this function to report an XML comment anywhere in the + document. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn QString QXmlLexicalHandler::errorString() + + The reader calls this function to get an error string if any of the handler + functions returns FALSE to him. +*/ + + +/*! + \class QXmlDeclHandler qxml.h + \brief The QXmlDeclHandler class provides an interface to report declaration + content of XML data. + + \module XML + + You can set the declaration handler with QXmlReader::setDeclHandler(). + + This interface is designed after the SAX2 extension DeclHandler. + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDTDHandler QXmlContentHandler QXmlEntityResolver QXmlErrorHandler + QXmlLexicalHandler +*/ +/*! + \fn bool QXmlDeclHandler::attributeDecl( const QString& eName, const QString& aName, const QString& type, const QString& valueDefault, const QString& value ) + + The reader calls this function to report an attribute type declaration. Only + the effective (first) declaration for an attribute will be reported. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlDeclHandler::internalEntityDecl( const QString& name, const QString& value ) + + The reader calls this function to report an internal entity declaration. Only + the effective (first) declaration will be reported. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn bool QXmlDeclHandler::externalEntityDecl( const QString& name, const QString& publicId, const QString& systemId ) + + The reader calls this function to report a parsed external entity + declaration. Only the effective (first) declaration for each entity will be + reported. + + If this function returns FALSE the reader will stop parsing and will report + an error. The reader will use the function errorString() to get the error + message that will be used for reporting the error. +*/ +/*! + \fn QString QXmlDeclHandler::errorString() + + The reader calls this function to get an error string if any of the handler + functions returns FALSE to him. +*/ + + +/*! + \class QXmlDefaultHandler qxml.h + \brief The QXmlDefaultHandler class provides a default implementation of all + XML handler classes. + + \module XML + + Very often you are only interested in parts of the things that that the + reader reports to you. This class simply implements a default behaviour of + the handler classes (most of the time: do nothing). Normally this is the + class you subclass for implementing your customized handler. + + See also the <a href="xml.html#introSAX2">Introduction to SAX2</a>. + + \sa QXmlDTDHandler QXmlDeclHandler QXmlContentHandler QXmlEntityResolver + QXmlErrorHandler QXmlLexicalHandler +*/ +/*! + \fn QXmlDefaultHandler::QXmlDefaultHandler() + + Constructor. +*/ +/*! + \fn QXmlDefaultHandler::~QXmlDefaultHandler() + + Destructor. +*/ + +/*! + Does nothing. +*/ +void QXmlDefaultHandler::setDocumentLocator( QXmlLocator* ) +{ +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::startDocument() +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::endDocument() +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::startPrefixMapping( const QString&, const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::endPrefixMapping( const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::startElement( const QString&, const QString&, + const QString&, const QXmlAttributes& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::endElement( const QString&, const QString&, + const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::characters( const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::ignorableWhitespace( const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::processingInstruction( const QString&, + const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::skippedEntity( const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::warning( const QXmlParseException& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::error( const QXmlParseException& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::fatalError( const QXmlParseException& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::notationDecl( const QString&, const QString&, + const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::unparsedEntityDecl( const QString&, const QString&, + const QString&, const QString& ) +{ + return TRUE; +} + +/*! + Always sets \a ret to 0, so that the reader will use the system identifier + provided in the XML document. +*/ +bool QXmlDefaultHandler::resolveEntity( const QString&, const QString&, + QXmlInputSource* ret ) +{ + ret = 0; + return TRUE; +} + +/*! + Returns the default error string. +*/ +QString QXmlDefaultHandler::errorString() +{ + return QString( XMLERR_ERRORBYCONSUMER ); +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::startDTD( const QString&, const QString&, const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::endDTD() +{ + return TRUE; +} + +#if 0 +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::startEntity( const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::endEntity( const QString& ) +{ + return TRUE; +} +#endif + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::startCDATA() +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::endCDATA() +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::comment( const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::attributeDecl( const QString&, const QString&, const QString&, const QString&, const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::internalEntityDecl( const QString&, const QString& ) +{ + return TRUE; +} + +/*! + Does nothing. +*/ +bool QXmlDefaultHandler::externalEntityDecl( const QString&, const QString&, const QString& ) +{ + return TRUE; +} + + +/********************************************* + * + * QXmlSimpleReaderPrivate + * + *********************************************/ + +class QXmlSimpleReaderPrivate +{ +private: + // constructor + QXmlSimpleReaderPrivate() + { } + + + // used for entity declarations + struct ExternParameterEntity + { + ExternParameterEntity( ) {} + ExternParameterEntity( const QString &p, const QString &s ) + : publicId(p), systemId(s) {} + QString publicId; + QString systemId; + }; + struct ExternEntity + { + ExternEntity( ) {} + ExternEntity( const QString &p, const QString &s, const QString &n ) + : publicId(p), systemId(s), notation(n) {} + QString publicId; + QString systemId; + QString notation; + }; + QMap<QString,ExternParameterEntity> externParameterEntities; + QMap<QString,QString> parameterEntities; + QMap<QString,ExternEntity> externEntities; + QMap<QString,QString> entities; + + // used for standalone declaration + enum Standalone { Yes, No, Unknown }; + + QString doctype; // only used for the doctype + QString xmlVersion; // only used to store the version information + QString encoding; // only used to store the encoding + Standalone standalone; // used to store the value of the standalone declaration + + QString publicId; // used by parseExternalID() to store the public ID + QString systemId; // used by parseExternalID() to store the system ID + QString attDeclEName; // use by parseAttlistDecl() + QString attDeclAName; // use by parseAttlistDecl() + + // flags for some features support + bool useNamespaces; + bool useNamespacePrefixes; + bool reportWhitespaceCharData; + + // used to build the attribute list + QXmlAttributes attList; + + // helper classes + QXmlLocator *locator; + QXmlNamespaceSupport namespaceSupport; + + // error string + QString error; + + // friend declarations + friend class QXmlSimpleReader; +}; + + +/********************************************* + * + * QXmlSimpleReader + * + *********************************************/ + +/*! + \class QXmlReader qxml.h + \brief The QXmlReader class provides an interface for XML readers (i.e. + parsers). + + \module XML + + This abstract class describes an interface for all XML readers in Qt. At the + moment there is only one implementation of a reader included in the XML + module of Qt (QXmlSimpleReader). In future releases there might be more + readers with different properties available (e.g. a validating parser). + + The design of the XML classes follow the + <a href="http://www.megginson.com/SAX/">SAX2 java interface</a>. + It was adopted to fit into the Qt naming conventions; so it should be very + easy for anybody who has worked with SAX2 to get started with the Qt XML + classes. + + All readers use the class QXmlInputSource to read the input document from. + Since you are normally interested in certain contents of the XML document, + the reader reports those contents through special handler classes + (QXmlDTDHandler, QXmlDeclHandler, QXmlContentHandler, QXmlEntityResolver, + QXmlErrorHandler and QXmlLexicalHandler). + + You have to subclass these classes. Since the handler classes describe only + interfaces you must implement all functions; there is a class + (QXmlDefaultHandler) to make this easier; it implements a default behaviour + (do nothing) for all functions. + + For getting started see also the + <a href="xml-sax.html#quickStart">Quick start</a>. + + \sa QXmlSimpleReader +*/ +/*! + \fn bool QXmlReader::feature( const QString& name, bool *ok ) const + + If the reader has the feature \a name, this function returns the value of the + feature. + + If the reader has not the feature \a name, the return value may be anything. + + If \a ok is not 0, then \a ok is set to TRUE if the reader has the feature + \a name, otherwise \a ok is set to FALSE. + + \sa setFeature() hasFeature() +*/ +/*! + \fn void QXmlReader::setFeature( const QString& name, bool value ) + + Sets the feature \a name to \a value. If the reader has not the feature \a + name, this value is ignored. + + \sa feature() hasFeature() +*/ +/*! + \fn bool QXmlReader::hasFeature( const QString& name ) const + + Returns \c TRUE if the reader has the feature \a name, otherwise FALSE. + + \sa feature() setFeature() +*/ +/*! + \fn void* QXmlReader::property( const QString& name, bool *ok ) const + + If the reader has the property \a name, this function returns the value of + the property. + + If the reader has not the property \a name, the return value is 0. + + If \a ok is not 0, then \a ok is set to TRUE if the reader has the property + \a name, otherwise \a ok is set to FALSE. + + \sa setProperty() hasProperty() +*/ +/*! + \fn void QXmlReader::setProperty( const QString& name, void* value ) + + Sets the property \a name to \a value. If the reader has not the property \a + name, this value is ignored. + + \sa property() hasProperty() +*/ +/*! + \fn bool QXmlReader::hasProperty( const QString& name ) const + + Returns TRUE if the reader has the property \a name, otherwise FALSE. + + \sa property() setProperty() +*/ +/*! + \fn void QXmlReader::setEntityResolver( QXmlEntityResolver* handler ) + + Sets the entity resolver to \a handler. + + \sa entityResolver() +*/ +/*! + \fn QXmlEntityResolver* QXmlReader::entityResolver() const + + Returns the entity resolver or 0 if none was set. + + \sa setEntityResolver() +*/ +/*! + \fn void QXmlReader::setDTDHandler( QXmlDTDHandler* handler ) + + Sets the DTD handler to \a handler. + + \sa DTDHandler() +*/ +/*! + \fn QXmlDTDHandler* QXmlReader::DTDHandler() const + + Returns the DTD handler or 0 if none was set. + + \sa setDTDHandler() +*/ +/*! + \fn void QXmlReader::setContentHandler( QXmlContentHandler* handler ) + + Sets the content handler to \a handler. + + \sa contentHandler() +*/ +/*! + \fn QXmlContentHandler* QXmlReader::contentHandler() const + + Returns the content handler or 0 if none was set. + + \sa setContentHandler() +*/ +/*! + \fn void QXmlReader::setErrorHandler( QXmlErrorHandler* handler ) + + Sets the error handler to \a handler. + + \sa errorHandler() +*/ +/*! + \fn QXmlErrorHandler* QXmlReader::errorHandler() const + + Returns the error handler or 0 if none was set + + \sa setErrorHandler() +*/ +/*! + \fn void QXmlReader::setLexicalHandler( QXmlLexicalHandler* handler ) + + Sets the lexical handler to \a handler. + + \sa lexicalHandler() +*/ +/*! + \fn QXmlLexicalHandler* QXmlReader::lexicalHandler() const + + Returns the lexical handler or 0 if none was set. + + \sa setLexicalHandler() +*/ +/*! + \fn void QXmlReader::setDeclHandler( QXmlDeclHandler* handler ) + + Sets the declaration handler to \a handler. + + \sa declHandler() +*/ +/*! + \fn QXmlDeclHandler* QXmlReader::declHandler() const + + Returns the declaration handler or 0 if none was set. + + \sa setDeclHandler() +*/ +/*! + \fn bool QXmlReader::parse( const QXmlInputSource& input ) + + Parses the XML document \a input. Returns TRUE if the parsing was successful, + otherwise FALSE. +*/ +/*! + \fn bool QXmlReader::parse( const QString& systemId ) + + Parses the XML document at the location \a systemId. Returns TRUE if the + parsing was successful, otherwise FALSE. +*/ + + +/*! + \class QXmlSimpleReader qxml.h + \brief The QXmlSimpleReader class provides an implementation of a simple XML + reader (i.e. parser). + + \module XML + + This XML reader is sufficient for simple parsing tasks. Here is a short list + of the properties of this reader: + <ul> + <li> well-formed parser + <li> does not parse any external entities + <li> can do namespace processing + </ul> + + For getting started see also the + <a href="xml-sax.html#quickStart">Quick start</a>. +*/ + +//guaranteed not to be a characater +const QChar QXmlSimpleReader::QEOF = QChar((ushort)0xffff); + +/*! + Constructs a simple XML reader. +*/ +QXmlSimpleReader::QXmlSimpleReader() +{ + d = new QXmlSimpleReaderPrivate(); + d->locator = new QXmlLocator( this ); + + entityRes = 0; + dtdHnd = 0; + contentHnd = 0; + errorHnd = 0; + lexicalHnd = 0; + declHnd = 0; + + // default feature settings + d->useNamespaces = TRUE; + d->useNamespacePrefixes = FALSE; + d->reportWhitespaceCharData = TRUE; +} + +/*! + Destroys a simple XML reader. +*/ +QXmlSimpleReader::~QXmlSimpleReader() +{ + delete d->locator; + delete d; +} + +/*! + Gets the state of a feature. + + \sa setFeature() hasFeature() +*/ +bool QXmlSimpleReader::feature( const QString& name, bool *ok ) const +{ + if ( ok != 0 ) + *ok = TRUE; + if ( name == "http://xml.org/sax/features/namespaces" ) { + return d->useNamespaces; + } else if ( name == "http://xml.org/sax/features/namespace-prefixes" ) { + return d->useNamespacePrefixes; + } else if ( name == "http://trolltech.com/xml/features/report-whitespace-only-CharData" ) { + return d->reportWhitespaceCharData; + } else { + qWarning( "Unknown feature " + name ); + if ( ok != 0 ) + *ok = FALSE; + } + return FALSE; +} + +/*! + Sets the state of a feature. + + Supported features are: + <ul> + <li> http://xml.org/sax/features/namespaces: + if this feature is TRUE, namespace processing is performed + <li> http://xml.org/sax/features/namespace-prefixes: + if this feature is TRUE, the the original prefixed names and attributes + used for namespace declarations are reported + <li> http://trolltech.com/xml/features/report-whitespace-only-CharData: + if this feature is TRUE, CharData that consists only of whitespace (and + no other characters) is not reported via + QXmlContentHandler::characters() + </ul> + + \sa feature() hasFeature() +*/ +void QXmlSimpleReader::setFeature( const QString& name, bool value ) +{ + if ( name == "http://xml.org/sax/features/namespaces" ) { + d->useNamespaces = value; + } else if ( name == "http://xml.org/sax/features/namespace-prefixes" ) { + d->useNamespacePrefixes = value; + } else if ( name == "http://trolltech.com/xml/features/report-whitespace-only-CharData" ) { + d->reportWhitespaceCharData = value; + } else { + qWarning( "Unknown feature " + name ); + } +} + +/*! + Returns TRUE if the class has a feature named \a feature, otherwise FALSE. + + \sa setFeature() feature() +*/ +bool QXmlSimpleReader::hasFeature( const QString& name ) const +{ + if ( name == "http://xml.org/sax/features/namespaces" || + name == "http://xml.org/sax/features/namespace-prefixes" || + name == "http://trolltech.com/xml/features/report-whitespace-only-CharData" ) { + return TRUE; + } else { + return FALSE; + } +} + +/*! + Returns 0 since this class does not support any properties. +*/ +void* QXmlSimpleReader::property( const QString&, bool *ok ) const +{ + if ( ok != 0 ) + *ok = FALSE; + return 0; +} + +/*! + Does nothing since this class does not support any properties. +*/ +void QXmlSimpleReader::setProperty( const QString&, void* ) +{ +} + +/*! + Returns FALSE since this class does not support any properties. +*/ +bool QXmlSimpleReader::hasProperty( const QString& ) const +{ + return FALSE; +} + +/*! \reimp */ +void QXmlSimpleReader::setEntityResolver( QXmlEntityResolver* handler ) +{ entityRes = handler; } + +/*! \reimp */ +QXmlEntityResolver* QXmlSimpleReader::entityResolver() const +{ return entityRes; } + +/*! \reimp */ +void QXmlSimpleReader::setDTDHandler( QXmlDTDHandler* handler ) +{ dtdHnd = handler; } + +/*! \reimp */ +QXmlDTDHandler* QXmlSimpleReader::DTDHandler() const +{ return dtdHnd; } + +/*! \reimp */ +void QXmlSimpleReader::setContentHandler( QXmlContentHandler* handler ) +{ contentHnd = handler; } + +/*! \reimp */ +QXmlContentHandler* QXmlSimpleReader::contentHandler() const +{ return contentHnd; } + +/*! \reimp */ +void QXmlSimpleReader::setErrorHandler( QXmlErrorHandler* handler ) +{ errorHnd = handler; } + +/*! \reimp */ +QXmlErrorHandler* QXmlSimpleReader::errorHandler() const +{ return errorHnd; } + +/*! \reimp */ +void QXmlSimpleReader::setLexicalHandler( QXmlLexicalHandler* handler ) +{ lexicalHnd = handler; } + +/*! \reimp */ +QXmlLexicalHandler* QXmlSimpleReader::lexicalHandler() const +{ return lexicalHnd; } + +/*! \reimp */ +void QXmlSimpleReader::setDeclHandler( QXmlDeclHandler* handler ) +{ declHnd = handler; } + +/*! \reimp */ +QXmlDeclHandler* QXmlSimpleReader::declHandler() const +{ return declHnd; } + + + +/*! \reimp */ +bool QXmlSimpleReader::parse( const QXmlInputSource& input ) +{ + init( input ); + // call the handler + if ( contentHnd ) { + contentHnd->setDocumentLocator( d->locator ); + if ( !contentHnd->startDocument() ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + // parse prolog + if ( !parseProlog() ) { + d->error = XMLERR_ERRORPARSINGPROLOG; + goto parseError; + } + // parse element + if ( !parseElement() ) { + d->error = XMLERR_ERRORPARSINGMAINELEMENT; + goto parseError; + } + // parse Misc* + while ( !atEnd() ) { + if ( !parseMisc() ) { + d->error = XMLERR_ERRORPARSINGMISC; + goto parseError; + } + } + // is stack empty? + if ( !tags.isEmpty() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + // call the handler + if ( contentHnd ) { + if ( !contentHnd->endDocument() ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + + return TRUE; + + // error handling + +parseError: + reportParseError(); + tags.clear(); + return FALSE; +} + +/*! + Parses the prolog [22]. +*/ +bool QXmlSimpleReader::parseProlog() +{ + bool xmldecl_possible = TRUE; + bool doctype_read = FALSE; + + const signed char Init = 0; + const signed char EatWS = 1; // eat white spaces + const signed char Lt = 2; // '<' read + const signed char Em = 3; // '!' read + const signed char DocType = 4; // read doctype + const signed char Comment = 5; // read comment + const signed char PI = 6; // read PI + const signed char Done = 7; + + const signed char InpWs = 0; + const signed char InpLt = 1; // < + const signed char InpQm = 2; // ? + const signed char InpEm = 3; // ! + const signed char InpD = 4; // D + const signed char InpDash = 5; // - + const signed char InpUnknown = 6; + + // use some kind of state machine for parsing + static signed char table[7][7] = { + /* InpWs InpLt InpQm InpEm InpD InpDash InpUnknown */ + { EatWS, Lt, -1, -1, -1, -1, -1 }, // Init + { -1, Lt, -1, -1, -1, -1, -1 }, // EatWS + { -1, -1, PI, Em, Done, -1, Done }, // Lt + { -1, -1, -1, -1, DocType, Comment, -1 }, // Em + { EatWS, Lt, -1, -1, -1, -1, -1 }, // DocType + { EatWS, Lt, -1, -1, -1, -1, -1 }, // Comment + { EatWS, Lt, -1, -1, -1, -1, -1 } // PI + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // read input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '<' ) { + input = InpLt; + } else if ( c == '?' ) { + input = InpQm; + } else if ( c == '!' ) { + input = InpEm; + } else if ( c == 'D' ) { + input = InpD; + } else if ( c == '-' ) { + input = InpDash; + } else { + input = InpUnknown; + } + // get new state + state = table[state][input]; + + // in some cases do special actions depending on state + switch ( state ) { + case EatWS: + // XML declaration only on first position possible + xmldecl_possible = FALSE; + // eat white spaces + eat_ws(); + break; + case Lt: + // next character + next(); + break; + case Em: + // XML declaration only on first position possible + xmldecl_possible = FALSE; + // next character + next(); + break; + case DocType: + parseOk = parseDoctype(); + break; + case Comment: + parseOk = parseComment(); + break; + case PI: + parseOk = parsePI( xmldecl_possible ); + break; + } + // no input is read after this + switch ( state ) { + case DocType: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGPROLOG; + goto parseError; + } + if ( doctype_read ) { + d->error = XMLERR_MORETHANONEDOCTYPE; + goto parseError; + } else { + doctype_read = FALSE; + } + break; + case Comment: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGPROLOG; + goto parseError; + } + if ( lexicalHnd ) { + if ( !lexicalHnd->comment( string() ) ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + break; + case PI: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGPROLOG; + goto parseError; + } + // call the handler + if ( contentHnd ) { + if ( xmldecl_possible && !d->xmlVersion.isEmpty() ) { + QString value( "version = '" ); + value += d->xmlVersion; + value += "'"; + if ( !d->encoding.isEmpty() ) { + value += " encoding = '"; + value += d->encoding; + value += "'"; + } + if ( d->standalone == QXmlSimpleReaderPrivate::Yes ) { + value += " standalone = 'yes'"; + } else if ( d->standalone == QXmlSimpleReaderPrivate::No ) { + value += " standalone = 'no'"; + } + if ( !contentHnd->processingInstruction( "xml", value ) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } else { + if ( !contentHnd->processingInstruction( name(), string() ) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + } + // XML declaration only on first position possible + xmldecl_possible = FALSE; + break; + case Done: + return TRUE; + case -1: + d->error = XMLERR_ERRORPARSINGELEMENT; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse an element [39]. + + Precondition: the opening '<' is already read. +*/ +bool QXmlSimpleReader::parseElement() +{ + static QString uri, lname, prefix; + static bool t; + + const signed char Init = 0; + const signed char ReadName = 1; + const signed char Ws1 = 2; + const signed char STagEnd = 3; + const signed char STagEnd2 = 4; + const signed char ETagBegin = 5; + const signed char ETagBegin2 = 6; + const signed char Ws2 = 7; + const signed char EmptyTag = 8; + const signed char Attribute = 9; + const signed char Ws3 = 10; + const signed char Done = 11; + + const signed char InpWs = 0; // whitespace + const signed char InpNameBe = 1; // is_NameBeginning() + const signed char InpGt = 2; // > + const signed char InpSlash = 3; // / + const signed char InpUnknown = 4; + + // use some kind of state machine for parsing + static signed char table[11][5] = { + /* InpWs InpNameBe InpGt InpSlash InpUnknown */ + { -1, ReadName, -1, -1, -1 }, // Init + { Ws1, Attribute, STagEnd, EmptyTag, -1 }, // ReadName + { -1, Attribute, STagEnd, EmptyTag, -1 }, // Ws1 + { STagEnd2, STagEnd2, STagEnd2, STagEnd2, STagEnd2 }, // STagEnd + { -1, -1, -1, ETagBegin, -1 }, // STagEnd2 + { -1, ETagBegin2, -1, -1, -1 }, // ETagBegin + { Ws2, -1, Done, -1, -1 }, // ETagBegin2 + { -1, -1, Done, -1, -1 }, // Ws2 + { -1, -1, Done, -1, -1 }, // EmptyTag + { Ws3, Attribute, STagEnd, EmptyTag, -1 }, // Attribute + { -1, Attribute, STagEnd, EmptyTag, -1 } // Ws3 + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // read input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( is_NameBeginning(c) ) { + input = InpNameBe; + } else if ( c == '>' ) { + input = InpGt; + } else if ( c == '/' ) { + input = InpSlash; + } else { + input = InpUnknown; + } + // get new state +//qDebug( "%d -%d(%c)-> %d", state, input, c.latin1(), table[state][input] ); + state = table[state][input]; + + // in some cases do special actions depending on state + switch ( state ) { + case ReadName: + parseOk = parseName(); + break; + case Ws1: + case Ws2: + case Ws3: + eat_ws(); + break; + case STagEnd: + // call the handler + if ( contentHnd ) { + if ( d->useNamespaces ) { + d->namespaceSupport.processName( tags.top(), FALSE, uri, lname ); + t = contentHnd->startElement( uri, lname, tags.top(), d->attList ); + } else { + t = contentHnd->startElement( "", "", tags.top(), d->attList ); + } + if ( !t ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + next(); + break; + case STagEnd2: + parseOk = parseContent(); + break; + case ETagBegin: + next(); + break; + case ETagBegin2: + // get the name of the tag + parseOk = parseName(); + break; + case EmptyTag: + if ( tags.isEmpty() ) { + d->error = XMLERR_TAGMISMATCH; + goto parseError; + } + if ( !parseElementEmptyTag( t, uri, lname ) ) + goto parseError; + // next character + next(); + break; + case Attribute: + // get name and value of attribute + parseOk = parseAttribute(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case ReadName: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + // store it on the stack + tags.push( name() ); + // empty the attributes + d->attList.qnameList.clear(); + d->attList.uriList.clear(); + d->attList.localnameList.clear(); + d->attList.valueList.clear(); + // namespace support? + if ( d->useNamespaces ) { + d->namespaceSupport.pushContext(); + } + break; + case STagEnd2: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGCONTENT; + goto parseError; + } + break; + case ETagBegin2: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + if ( !parseElementETagBegin2() ) + goto parseError; + break; + case Attribute: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGATTRIBUTE; + goto parseError; + } + if ( !parseElementAttribute( prefix, uri, lname ) ) + goto parseError; + break; + case Done: + return TRUE; + case -1: + d->error = XMLERR_ERRORPARSINGELEMENT; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} +/*! + Helper to break down the size of the code in the case statement. + Return FALSE on error, otherwise TRUE. +*/ +bool QXmlSimpleReader::parseElementEmptyTag( bool &t, QString &uri, QString &lname ) +{ + // pop the stack and call the handler + if ( contentHnd ) { + // report startElement first... + if ( d->useNamespaces ) { + d->namespaceSupport.processName( tags.top(), FALSE, uri, lname ); + t = contentHnd->startElement( uri, lname, tags.top(), d->attList ); + } else { + t = contentHnd->startElement( "", "", tags.top(), d->attList ); + } + if ( !t ) { + d->error = contentHnd->errorString(); + return FALSE; + } + // ... followed by endElement + // ### missing namespace support! + if ( !contentHnd->endElement( "","",tags.pop() ) ) { + d->error = contentHnd->errorString(); + return FALSE; + } + // namespace support? + if ( d->useNamespaces ) { + QStringList prefixesBefore, prefixesAfter; + if ( contentHnd ) { + prefixesBefore = d->namespaceSupport.prefixes(); + } + d->namespaceSupport.popContext(); + // call the handler for prefix mapping + if ( contentHnd ) { + prefixesAfter = d->namespaceSupport.prefixes(); + for ( QStringList::Iterator it = prefixesBefore.begin(); it != prefixesBefore.end(); ++it ) { + if ( prefixesAfter.contains(*it) == 0 ) { + if ( !contentHnd->endPrefixMapping( *it ) ) { + d->error = contentHnd->errorString(); + return FALSE; + } + } + } + } + } + } else { + tags.pop(); + } + return TRUE; +} +/*! + Helper to break down the size of the code in the case statement. + Return FALSE on error, otherwise TRUE. +*/ +bool QXmlSimpleReader::parseElementETagBegin2() +{ + + // pop the stack and compare it with the name + if ( tags.pop() != name() ) { + d->error = XMLERR_TAGMISMATCH; + return FALSE; + } + // call the handler + // ### missing namespace support! + if ( contentHnd ) { + if ( !contentHnd->endElement("","",name()) ) { + d->error = contentHnd->errorString(); + return FALSE; + } + } + // namespace support? + if ( d->useNamespaces ) { + QStringList prefixesBefore, prefixesAfter; + if ( contentHnd ) { + prefixesBefore = d->namespaceSupport.prefixes(); + } + d->namespaceSupport.popContext(); + // call the handler for prefix mapping + if ( contentHnd ) { + prefixesAfter = d->namespaceSupport.prefixes(); + for ( QStringList::Iterator it = prefixesBefore.begin(); it != prefixesBefore.end(); ++it ) { + if ( prefixesAfter.contains(*it) == 0 ) { + if ( !contentHnd->endPrefixMapping( *it ) ) { + d->error = contentHnd->errorString(); + return FALSE; + } + } + } + } + } + return TRUE; +} +/*! + Helper to break down the size of the code in the case statement. + Return FALSE on error, otherwise TRUE. +*/ +bool QXmlSimpleReader::parseElementAttribute( QString &prefix, QString &uri, QString &lname ) +{ + // add the attribute to the list + if ( d->useNamespaces ) { + // is it a namespace declaration? + d->namespaceSupport.splitName( name(), prefix, lname ); + if ( prefix == "xmlns" ) { + // namespace declaration + d->namespaceSupport.setPrefix( lname, string() ); + if ( d->useNamespacePrefixes ) { + d->attList.qnameList.append( name() ); + d->attList.uriList.append( "" ); + d->attList.localnameList.append( "" ); + d->attList.valueList.append( string() ); + } + // call the handler for prefix mapping + if ( contentHnd ) { + if ( !contentHnd->startPrefixMapping( lname, string() ) ) { + d->error = contentHnd->errorString(); + return FALSE; + } + } + } else { + // no namespace delcaration + d->namespaceSupport.processName( name(), TRUE, uri, lname ); + d->attList.qnameList.append( name() ); + d->attList.uriList.append( uri ); + d->attList.localnameList.append( lname ); + d->attList.valueList.append( string() ); + } + } else { + // no namespace support + d->attList.qnameList.append( name() ); + d->attList.uriList.append( "" ); + d->attList.localnameList.append( "" ); + d->attList.valueList.append( string() ); + } + return TRUE; +} + +/*! + Parse a content [43]. + + A content is only used between tags. If a end tag is found the < is already + read and the head stand on the '/' of the end tag '</name>'. +*/ +bool QXmlSimpleReader::parseContent() +{ + bool charDataRead = FALSE; + + const signed char Init = 0; + const signed char ChD = 1; // CharData + const signed char ChD1 = 2; // CharData help state + const signed char ChD2 = 3; // CharData help state + const signed char Ref = 4; // Reference + const signed char Lt = 5; // '<' read + const signed char PI = 6; // PI + const signed char Elem = 7; // Element + const signed char Em = 8; // '!' read + const signed char Com = 9; // Comment + const signed char CDS = 10; // CDSect + const signed char CDS1 = 11; // read a CDSect + const signed char CDS2 = 12; // read a CDSect (help state) + const signed char CDS3 = 13; // read a CDSect (help state) + const signed char Done = 14; // finished reading content + + const signed char InpLt = 0; // < + const signed char InpGt = 1; // > + const signed char InpSlash = 2; // / + const signed char InpQMark = 3; // ? + const signed char InpEMark = 4; // ! + const signed char InpAmp = 5; // & + const signed char InpDash = 6; // - + const signed char InpOpenB = 7; // [ + const signed char InpCloseB = 8; // ] + const signed char InpUnknown = 9; + + static signed char mapCLT2FSMChar[] = { + InpUnknown, // white space + InpUnknown, // % + InpAmp, // & + InpGt, // > + InpLt, // < + InpSlash, // / + InpQMark, // ? + InpEMark, // ! + InpDash, // - + InpCloseB, // ] + InpOpenB, // [ + InpUnknown, // = + InpUnknown, // " + InpUnknown, // ' + InpUnknown // unknown + }; + + // use some kind of state machine for parsing + static signed char const table[14][10] = { + /* InpLt InpGt InpSlash InpQMark InpEMark InpAmp InpDash InpOpenB InpCloseB InpUnknown */ + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD1, ChD }, // Init + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD1, ChD }, // ChD + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD2, ChD }, // ChD1 + { Lt, -1, ChD, ChD, ChD, Ref, ChD, ChD, ChD2, ChD }, // ChD2 + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // Ref (same as Init) + { -1, -1, Done, PI, Em, -1, -1, -1, -1, Elem }, // Lt + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // PI (same as Init) + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // Elem (same as Init) + { -1, -1, -1, -1, -1, -1, Com, CDS, -1, -1 }, // Em + { Lt, ChD, ChD, ChD, ChD, Ref, ChD, ChD, ChD, ChD }, // Com (same as Init) + { CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS2, CDS1 }, // CDS + { CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS2, CDS1 }, // CDS1 + { CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS3, CDS1 }, // CDS2 + { CDS1, Init, CDS1, CDS1, CDS1, CDS1, CDS1, CDS1, CDS3, CDS1 } // CDS3 + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input (use lookup-table instead of nested ifs for performance + // reasons) + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c.row() ) { + input = InpUnknown; + } else { + input = mapCLT2FSMChar[ charLookupTable[ c.cell() ] ]; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Init: + // next character + next(); + break; + case ChD: + // on first call: clear string + if ( !charDataRead ) { + charDataRead = TRUE; + stringClear(); + } + stringAddC(); + next(); + break; + case ChD1: + // on first call: clear string + if ( !charDataRead ) { + charDataRead = TRUE; + stringClear(); + } + stringAddC(); + next(); + break; + case ChD2: + stringAddC(); + next(); + break; + case Ref: + if ( !charDataRead) { + // reference may be CharData; so clear string to be safe + stringClear(); + parseOk = parseReference( charDataRead, InContent ); + } else { + bool tmp; + parseOk = parseReference( tmp, InContent ); + } + break; + case Lt: + // call the handler for CharData + if ( contentHnd ) { + if ( charDataRead ) { + if ( d->reportWhitespaceCharData || !string().simplifyWhiteSpace().isEmpty() ) { + if ( !contentHnd->characters( string() ) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + } + } + charDataRead = FALSE; + // next character + next(); + break; + case PI: + parseOk = parsePI(); + break; + case Elem: + parseOk = parseElement(); + break; + case Em: + // next character + next(); + break; + case Com: + parseOk = parseComment(); + break; + case CDS: + parseOk = parseString( "[CDATA[" ); + break; + case CDS1: + // read one character and add it + stringAddC(); + next(); + break; + case CDS2: + // skip ']' + next(); + break; + case CDS3: + // skip ']'... + next(); + break; + } + // no input is read after this + switch ( state ) { + case Ref: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGREFERENCE; + goto parseError; + } + break; + case PI: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGPI; + goto parseError; + } + // call the handler + if ( contentHnd ) { + if ( !contentHnd->processingInstruction(name(),string()) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + break; + case Elem: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGELEMENT; + goto parseError; + } + break; + case Com: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGCOMMENT; + goto parseError; + } + if ( lexicalHnd ) { + if ( !lexicalHnd->comment( string() ) ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + break; + case CDS: + if( !parseOk ) { + d->error = XMLERR_CDSECTHEADEREXPECTED; + goto parseError; + } + // empty string + stringClear(); + break; + case CDS2: + if (c != ']') { + stringAddC( ']' ); + } + break; + case CDS3: + // test if this skipping was legal + if ( c == '>' ) { + // the end of the CDSect + if ( lexicalHnd ) { + if ( !lexicalHnd->startCDATA() ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + if ( contentHnd ) { + if ( !contentHnd->characters( string() ) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + if ( lexicalHnd ) { + if ( !lexicalHnd->endCDATA() ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + } else if (c == ']') { + // three or more ']' + stringAddC( ']' ); + } else { + // after ']]' comes another character + stringAddC( ']' ); + stringAddC( ']' ); + } + break; + case Done: + // call the handler for CharData + if ( contentHnd ) { + if ( charDataRead ) { + if ( d->reportWhitespaceCharData || !string().simplifyWhiteSpace().isEmpty() ) { + if ( !contentHnd->characters( string() ) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + } + } + // Done + return TRUE; + case -1: + // Error + d->error = XMLERR_ERRORPARSINGCONTENT; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse Misc [27]. +*/ +bool QXmlSimpleReader::parseMisc() +{ + const signed char Init = 0; + const signed char Lt = 1; // '<' was read + const signed char Comment = 2; // read comment + const signed char eatWS = 3; // eat whitespaces + const signed char PI = 4; // read PI + const signed char Comment2 = 5; // read comment + + const signed char InpWs = 0; // S + const signed char InpLt = 1; // < + const signed char InpQm = 2; // ? + const signed char InpEm = 3; // ! + const signed char InpUnknown = 4; + + // use some kind of state machine for parsing + static signed char table[3][5] = { + /* InpWs InpLt InpQm InpEm InpUnknown */ + { eatWS, Lt, -1, -1, -1 }, // Init + { -1, -1, PI, Comment, -1 }, // Lt + { -1, -1, -1, -1, Comment2 } // Comment + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '<' ) { + input = InpLt; + } else if ( c == '?' ) { + input = InpQm; + } else if ( c == '!' ) { + input = InpEm; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case eatWS: + eat_ws(); + break; + case Lt: + next(); + break; + case PI: + parseOk = parsePI(); + break; + case Comment: + next(); + break; + case Comment2: + parseOk = parseComment(); + break; + } + // no input is read after this + switch ( state ) { + case eatWS: + return TRUE; + case PI: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGPI; + goto parseError; + } + if ( contentHnd ) { + if ( !contentHnd->processingInstruction(name(),string()) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + return TRUE; + case Comment2: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGCOMMENT; + goto parseError; + } + if ( lexicalHnd ) { + if ( !lexicalHnd->comment( string() ) ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a processing instruction [16]. + + If xmldec is TRUE, it tries to parse a PI or a XML declaration [23]. + + Precondition: the beginning '<' of the PI is already read and the head stand + on the '?' of '<?'. + + If this funktion was successful, the head-position is on the first + character after the PI. +*/ +bool QXmlSimpleReader::parsePI( bool xmldecl ) +{ + const signed char Init = 0; + const signed char QmI = 1; // ? was read + const signed char Name = 2; // read Name + const signed char XMLDecl = 3; // read XMLDecl + const signed char Ws1 = 4; // eat ws after "xml" of XMLDecl + const signed char PI = 5; // read PI + const signed char Ws2 = 6; // eat ws after Name of PI + const signed char Version = 7; // read versionInfo + const signed char Ws3 = 8; // eat ws after versionInfo + const signed char EorSD = 9; // read EDecl or SDDecl + const signed char Ws4 = 10; // eat ws after EDecl or SDDecl + const signed char SD = 11; // read SDDecl + const signed char Ws5 = 12; // eat ws after SDDecl + const signed char ADone = 13; // almost done + const signed char Char = 14; // Char was read + const signed char Qm = 15; // Qm was read + const signed char Done = 16; // finished reading content + + const signed char InpWs = 0; // whitespace + const signed char InpNameBe = 1; // is_nameBeginning() + const signed char InpGt = 2; // > + const signed char InpQm = 3; // ? + const signed char InpUnknown = 4; + + // use some kind of state machine for parsing + static signed char table[16][5] = { + /* InpWs, InpNameBe InpGt InpQm InpUnknown */ + { -1, -1, -1, QmI, -1 }, // Init + { -1, Name, -1, -1, -1 }, // QmI + { -1, -1, -1, -1, -1 }, // Name (this state is left not through input) + { Ws1, -1, -1, -1, -1 }, // XMLDecl + { -1, Version, -1, -1, -1 }, // Ws1 + { Ws2, -1, -1, Qm, -1 }, // PI + { Char, Char, Char, Qm, Char }, // Ws2 + { Ws3, -1, -1, ADone, -1 }, // Version + { -1, EorSD, -1, ADone, -1 }, // Ws3 + { Ws4, -1, -1, ADone, -1 }, // EorSD + { -1, SD, -1, ADone, -1 }, // Ws4 + { Ws5, -1, -1, ADone, -1 }, // SD + { -1, -1, -1, ADone, -1 }, // Ws5 + { -1, -1, Done, -1, -1 }, // ADone + { Char, Char, Char, Qm, Char }, // Char + { Char, Char, Done, Qm, Char }, // Qm + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( is_NameBeginning(c) ) { + input = InpNameBe; + } else if ( c == '>' ) { + input = InpGt; + } else if ( c == '?' ) { + input = InpQm; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case QmI: + next(); + break; + case Name: + parseOk = parseName(); + break; + case Ws1: + case Ws2: + case Ws3: + case Ws4: + case Ws5: + eat_ws(); + break; + case Version: + parseOk = parseAttribute(); + break; + case EorSD: + parseOk = parseAttribute(); + break; + case SD: + // get the SDDecl (syntax like an attribute) + if ( d->standalone != QXmlSimpleReaderPrivate::Unknown ) { + // already parsed the standalone declaration + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + parseOk = parseAttribute(); + break; + case ADone: + next(); + break; + case Char: + stringAddC(); + next(); + break; + case Qm: + // skip the '?' + next(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Name: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + // test what name was read and determine the next state + // (not very beautiful, I admit) + if ( name().lower() == "xml" ) { + if ( xmldecl && name()=="xml" ) { + state = XMLDecl; + } else { + d->error = XMLERR_INVALIDNAMEFORPI; + goto parseError; + } + } else { + state = PI; + stringClear(); + } + break; + case Version: + // get version (syntax like an attribute) + if ( !parseOk ) { + d->error = XMLERR_VERSIONEXPECTED; + goto parseError; + } + if ( name() != "version" ) { + d->error = XMLERR_VERSIONEXPECTED; + goto parseError; + } + d->xmlVersion = string(); + break; + case EorSD: + // get the EDecl or SDDecl (syntax like an attribute) + if ( !parseOk ) { + d->error = XMLERR_EDECLORSDDECLEXPECTED; + goto parseError; + } + if ( name() == "standalone" ) { + if ( string()=="yes" ) { + d->standalone = QXmlSimpleReaderPrivate::Yes; + } else if ( string()=="no" ) { + d->standalone = QXmlSimpleReaderPrivate::No; + } else { + d->error = XMLERR_WRONGVALUEFORSDECL; + goto parseError; + } + } else if ( name() == "encoding" ) { + d->encoding = string(); + } else { + d->error = XMLERR_EDECLORSDDECLEXPECTED; + goto parseError; + } + break; + case SD: + if ( !parseOk ) { + d->error = XMLERR_SDDECLEXPECTED; + goto parseError; + } + if ( name() != "standalone" ) { + d->error = XMLERR_SDDECLEXPECTED; + goto parseError; + } + if ( string()=="yes" ) { + d->standalone = QXmlSimpleReaderPrivate::Yes; + } else if ( string()=="no" ) { + d->standalone = QXmlSimpleReaderPrivate::No; + } else { + d->error = XMLERR_WRONGVALUEFORSDECL; + goto parseError; + } + break; + case Qm: + // test if the skipping was legal + if ( c != '>' ) { + stringAddC( '?' ); + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a document type definition (doctypedecl [28]). + + Precondition: the beginning '<!' of the doctype is already read the head + stands on the 'D' of '<!DOCTYPE'. + + If this funktion was successful, the head-position is on the first + character after the document type definition. +*/ +bool QXmlSimpleReader::parseDoctype() +{ + // some init-stuff + d->systemId = QString::null; + d->publicId = QString::null; + + const signed char Init = 0; + const signed char Doctype = 1; // read the doctype + const signed char Ws1 = 2; // eat_ws + const signed char Doctype2 = 3; // read the doctype, part 2 + const signed char Ws2 = 4; // eat_ws + const signed char Sys = 5; // read SYSTEM + const signed char Ws3 = 6; // eat_ws + const signed char MP = 7; // markupdecl or PEReference + const signed char PER = 8; // PERReference + const signed char Mup = 9; // markupdecl + const signed char Ws4 = 10; // eat_ws + const signed char MPE = 11; // end of markupdecl or PEReference + const signed char Done = 12; + + const signed char InpWs = 0; + const signed char InpD = 1; // 'D' + const signed char InpS = 2; // 'S' or 'P' + const signed char InpOB = 3; // [ + const signed char InpCB = 4; // ] + const signed char InpPer = 5; // % + const signed char InpGt = 6; // > + const signed char InpUnknown = 7; + + // use some kind of state machine for parsing + static signed char table[12][8] = { + /* InpWs, InpD InpS InpOB InpCB InpPer InpGt InpUnknown */ + { -1, Doctype, -1, -1, -1, -1, -1, -1 }, // Init + { Ws1, Doctype2, Doctype2, -1, -1, -1, -1, Doctype2 }, // Doctype + { -1, Doctype2, Doctype2, -1, -1, -1, -1, Doctype2 }, // Ws1 + { Ws2, -1, Sys, MP, -1, -1, Done, -1 }, // Doctype2 + { -1, -1, Sys, MP, -1, -1, Done, -1 }, // Ws2 + { Ws3, -1, -1, MP, -1, -1, Done, -1 }, // Sys + { -1, -1, -1, MP, -1, -1, Done, -1 }, // Ws3 + { -1, -1, -1, -1, MPE, PER, -1, Mup }, // MP + { Ws4, -1, -1, -1, MPE, PER, -1, Mup }, // PER + { Ws4, -1, -1, -1, MPE, PER, -1, Mup }, // Mup + { -1, -1, -1, -1, MPE, PER, -1, Mup }, // Ws4 + { -1, -1, -1, -1, -1, -1, Done, -1 } // MPE + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == 'D' ) { + input = InpD; + } else if ( c == 'S' ) { + input = InpS; + } else if ( c == 'P' ) { + input = InpS; + } else if ( c == '[' ) { + input = InpOB; + } else if ( c == ']' ) { + input = InpCB; + } else if ( c == '%' ) { + input = InpPer; + } else if ( c == '>' ) { + input = InpGt; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Doctype: + parseOk = parseString( "DOCTYPE" ); + break; + case Ws1: + case Ws2: + case Ws3: + case Ws4: + eat_ws(); + break; + case Doctype2: + parseName(); + break; + case Sys: + parseOk = parseExternalID(); + break; + case MP: + next_eat_ws(); + break; + case PER: + parseOk = parsePEReference( InDTD ); + break; + case Mup: + parseOk = parseMarkupdecl(); + break; + case MPE: + next_eat_ws(); + break; + case Done: + if ( lexicalHnd ) { + if ( !lexicalHnd->endDTD() ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + next(); + break; + } + // no input is read after this + switch ( state ) { + case Doctype: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + if ( !is_S(c) ) { + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + break; + case Doctype2: + d->doctype = name(); + if ( lexicalHnd ) { + if ( !lexicalHnd->startDTD( d->doctype, d->publicId, d->systemId ) ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + break; + case Sys: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + break; + case PER: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + break; + case Mup: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a ExternalID [75]. + + If allowPublicID is TRUE parse ExternalID [75] or PublicID [83]. +*/ +bool QXmlSimpleReader::parseExternalID( bool allowPublicID ) +{ + // some init-stuff + d->systemId = QString::null; + d->publicId = QString::null; + + const signed char Init = 0; + const signed char Sys = 1; // parse 'SYSTEM' + const signed char SysWS = 2; // parse the whitespace after 'SYSTEM' + const signed char SysSQ = 3; // parse SystemLiteral with ' + const signed char SysSQ2 = 4; // parse SystemLiteral with ' + const signed char SysDQ = 5; // parse SystemLiteral with " + const signed char SysDQ2 = 6; // parse SystemLiteral with " + const signed char Pub = 7; // parse 'PUBLIC' + const signed char PubWS = 8; // parse the whitespace after 'PUBLIC' + const signed char PubSQ = 9; // parse PubidLiteral with ' + const signed char PubSQ2 = 10; // parse PubidLiteral with ' + const signed char PubDQ = 11; // parse PubidLiteral with " + const signed char PubDQ2 = 12; // parse PubidLiteral with " + const signed char PubE = 13; // finished parsing the PubidLiteral + const signed char PubWS2 = 14; // parse the whitespace after the PubidLiteral + const signed char PDone = 15; // done if allowPublicID is TRUE + const signed char Done = 16; + + const signed char InpSQ = 0; // ' + const signed char InpDQ = 1; // " + const signed char InpS = 2; // S + const signed char InpP = 3; // P + const signed char InpWs = 4; // white space + const signed char InpUnknown = 5; + + // use some kind of state machine for parsing + static signed char table[15][6] = { + /* InpSQ InpDQ InpS InpP InpWs InpUnknown */ + { -1, -1, Sys, Pub, -1, -1 }, // Init + { -1, -1, -1, -1, SysWS, -1 }, // Sys + { SysSQ, SysDQ, -1, -1, -1, -1 }, // SysWS + { Done, SysSQ2, SysSQ2, SysSQ2, SysSQ2, SysSQ2 }, // SysSQ + { Done, SysSQ2, SysSQ2, SysSQ2, SysSQ2, SysSQ2 }, // SysSQ2 + { SysDQ2, Done, SysDQ2, SysDQ2, SysDQ2, SysDQ2 }, // SysDQ + { SysDQ2, Done, SysDQ2, SysDQ2, SysDQ2, SysDQ2 }, // SysDQ2 + { -1, -1, -1, -1, PubWS, -1 }, // Pub + { PubSQ, PubDQ, -1, -1, -1, -1 }, // PubWS + { PubE, -1, PubSQ2, PubSQ2, PubSQ2, PubSQ2 }, // PubSQ + { PubE, -1, PubSQ2, PubSQ2, PubSQ2, PubSQ2 }, // PubSQ2 + { -1, PubE, PubDQ2, PubDQ2, PubDQ2, PubDQ2 }, // PubDQ + { -1, PubE, PubDQ2, PubDQ2, PubDQ2, PubDQ2 }, // PubDQ2 + { PDone, PDone, PDone, PDone, PubWS2, PDone }, // PubE + { SysSQ, SysDQ, PDone, PDone, PDone, PDone } // PubWS2 + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '\'' ) { + input = InpSQ; + } else if ( c == '"' ) { + input = InpDQ; + } else if ( c == 'S' ) { + input = InpS; + } else if ( c == 'P' ) { + input = InpP; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Sys: + parseOk = parseString( "SYSTEM" ); + break; + case SysWS: + eat_ws(); + break; + case SysSQ: + case SysDQ: + stringClear(); + next(); + break; + case SysSQ2: + case SysDQ2: + stringAddC(); + next(); + break; + case Pub: + parseOk = parseString( "PUBLIC" ); + break; + case PubWS: + eat_ws(); + break; + case PubSQ: + case PubDQ: + stringClear(); + next(); + break; + case PubSQ2: + case PubDQ2: + stringAddC(); + next(); + break; + case PubE: + next(); + break; + case PubWS2: + d->publicId = string(); + eat_ws(); + break; + case Done: + d->systemId = string(); + next(); + break; + } + // no input is read after this + switch ( state ) { + case Sys: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Pub: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case PDone: + if ( allowPublicID ) { + d->publicId = string(); + return TRUE; + } else { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a markupdecl [29]. +*/ +bool QXmlSimpleReader::parseMarkupdecl() +{ + const signed char Init = 0; + const signed char Lt = 1; // < was read + const signed char Em = 2; // ! was read + const signed char CE = 3; // E was read + const signed char Qm = 4; // ? was read + const signed char Dash = 5; // - was read + const signed char CA = 6; // A was read + const signed char CEL = 7; // EL was read + const signed char CEN = 8; // EN was read + const signed char CN = 9; // N was read + const signed char Done = 10; + + const signed char InpLt = 0; // < + const signed char InpQm = 1; // ? + const signed char InpEm = 2; // ! + const signed char InpDash = 3; // - + const signed char InpA = 4; // A + const signed char InpE = 5; // E + const signed char InpL = 6; // L + const signed char InpN = 7; // N + const signed char InpUnknown = 8; + + // use some kind of state machine for parsing + static signed char table[4][9] = { + /* InpLt InpQm InpEm InpDash InpA InpE InpL InpN InpUnknown */ + { Lt, -1, -1, -1, -1, -1, -1, -1, -1 }, // Init + { -1, Qm, Em, -1, -1, -1, -1, -1, -1 }, // Lt + { -1, -1, -1, Dash, CA, CE, -1, CN, -1 }, // Em + { -1, -1, -1, -1, -1, -1, CEL, CEN, -1 } // CE + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c == '<' ) { + input = InpLt; + } else if ( c == '?' ) { + input = InpQm; + } else if ( c == '!' ) { + input = InpEm; + } else if ( c == '-' ) { + input = InpDash; + } else if ( c == 'A' ) { + input = InpA; + } else if ( c == 'E' ) { + input = InpE; + } else if ( c == 'L' ) { + input = InpL; + } else if ( c == 'N' ) { + input = InpN; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Lt: + next(); + break; + case Em: + next(); + break; + case CE: + next(); + break; + case Qm: + parseOk = parsePI(); + break; + case Dash: + parseOk = parseComment(); + break; + case CA: + parseOk = parseAttlistDecl(); + break; + case CEL: + parseOk = parseElementDecl(); + break; + case CEN: + parseOk = parseEntityDecl(); + break; + case CN: + parseOk = parseNotationDecl(); + break; + } + // no input is read after this + switch ( state ) { + case Qm: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGPI; + goto parseError; + } + if ( contentHnd ) { + if ( !contentHnd->processingInstruction(name(),string()) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + return TRUE; + case Dash: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGCOMMENT; + goto parseError; + } + if ( lexicalHnd ) { + if ( !lexicalHnd->comment( string() ) ) { + d->error = lexicalHnd->errorString(); + goto parseError; + } + } + return TRUE; + case CA: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGATTLISTDECL; + goto parseError; + } + return TRUE; + case CEL: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGELEMENTDECL; + goto parseError; + } + return TRUE; + case CEN: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGENTITYDECL; + goto parseError; + } + return TRUE; + case CN: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNOTATIONDECL; + goto parseError; + } + return TRUE; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a PEReference [69] +*/ +bool QXmlSimpleReader::parsePEReference( EntityRecognitionContext context ) +{ + const signed char Init = 0; + const signed char Next = 1; + const signed char Name = 2; + const signed char Done = 3; + + const signed char InpSemi = 0; // ; + const signed char InpPer = 1; // % + const signed char InpUnknown = 2; + + // use some kind of state machine for parsing + static signed char table[3][3] = { + /* InpSemi InpPer InpUnknown */ + { -1, Next, -1 }, // Init + { -1, -1, Name }, // Next + { Done, -1, -1 } // Name + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c == ';' ) { + input = InpSemi; + } else if ( c == '%' ) { + input = InpPer; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Next: + next(); + break; + case Name: + parseOk = parseName( TRUE ); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Name: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + if ( d->parameterEntities.find( ref() ) == d->parameterEntities.end() ) { + // ### skip it??? + if ( contentHnd ) { + if ( !contentHnd->skippedEntity( QString("%") + ref() ) ) { + d->error = contentHnd->errorString(); + goto parseError; + } + } + } else { + if ( context == InEntityValue ) { + // Included in literal + xmlRef = d->parameterEntities.find( ref() ) + .data().replace( QRegExp("\""), """ ).replace( QRegExp("'"), "'" ) + + xmlRef; + } else if ( context == InDTD ) { + // Included as PE + xmlRef = QString(" ") + + d->parameterEntities.find( ref() ).data() + + QString(" ") + xmlRef; + } + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a AttlistDecl [52]. + + Precondition: the beginning '<!' is already read and the head + stands on the 'A' of '<!ATTLIST' +*/ +bool QXmlSimpleReader::parseAttlistDecl() +{ + const signed char Init = 0; + const signed char Attlist = 1; // parse the string "ATTLIST" + const signed char Ws = 2; // whitespace read + const signed char Name = 3; // parse name + const signed char Ws1 = 4; // whitespace read + const signed char Attdef = 5; // parse the AttDef + const signed char Ws2 = 6; // whitespace read + const signed char Atttype = 7; // parse the AttType + const signed char Ws3 = 8; // whitespace read + const signed char DDecH = 9; // DefaultDecl with # + const signed char DefReq = 10; // parse the string "REQUIRED" + const signed char DefImp = 11; // parse the string "IMPLIED" + const signed char DefFix = 12; // parse the string "FIXED" + const signed char Attval = 13; // parse the AttValue + const signed char Ws4 = 14; // whitespace read + const signed char Done = 15; + + const signed char InpWs = 0; // white space + const signed char InpGt = 1; // > + const signed char InpHash = 2; // # + const signed char InpA = 3; // A + const signed char InpI = 4; // I + const signed char InpF = 5; // F + const signed char InpR = 6; // R + const signed char InpUnknown = 7; + + // use some kind of state machine for parsing + static signed char table[15][8] = { + /* InpWs InpGt InpHash InpA InpI InpF InpR InpUnknown */ + { -1, -1, -1, Attlist, -1, -1, -1, -1 }, // Init + { Ws, -1, -1, -1, -1, -1, -1, -1 }, // Attlist + { -1, -1, -1, Name, Name, Name, Name, Name }, // Ws + { Ws1, Done, Attdef, Attdef, Attdef, Attdef, Attdef, Attdef }, // Name + { -1, Done, Attdef, Attdef, Attdef, Attdef, Attdef, Attdef }, // Ws1 + { Ws2, -1, -1, -1, -1, -1, -1, -1 }, // Attdef + { -1, Atttype, Atttype, Atttype, Atttype, Atttype, Atttype, Atttype }, // Ws2 + { Ws3, -1, -1, -1, -1, -1, -1, -1 }, // Attype + { -1, Attval, DDecH, Attval, Attval, Attval, Attval, Attval }, // Ws3 + { -1, -1, -1, -1, DefImp, DefFix, DefReq, -1 }, // DDecH + { Ws4, Ws4, -1, -1, -1, -1, -1, -1 }, // DefReq + { Ws4, Ws4, -1, -1, -1, -1, -1, -1 }, // DefImp + { Ws3, -1, -1, -1, -1, -1, -1, -1 }, // DefFix + { Ws4, Ws4, -1, -1, -1, -1, -1, -1 }, // Attval + { -1, Done, Attdef, Attdef, Attdef, Attdef, Attdef, Attdef } // Ws4 + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '>' ) { + input = InpGt; + } else if ( c == '#' ) { + input = InpHash; + } else if ( c == 'A' ) { + input = InpA; + } else if ( c == 'I' ) { + input = InpI; + } else if ( c == 'F' ) { + input = InpF; + } else if ( c == 'R' ) { + input = InpR; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Attlist: + parseOk = parseString( "ATTLIST" ); + break; + case Ws: + case Ws1: + case Ws2: + case Ws3: + eat_ws(); + break; + case Name: + parseOk = parseName(); + break; + case Attdef: + parseOk = parseName(); + break; + case Atttype: + parseOk = parseAttType(); + break; + case DDecH: + next(); + break; + case DefReq: + parseOk = parseString( "REQUIRED" ); + break; + case DefImp: + parseOk = parseString( "IMPLIED" ); + break; + case DefFix: + parseOk = parseString( "FIXED" ); + break; + case Attval: + parseOk = parseAttValue(); + break; + case Ws4: + if ( declHnd ) { + // TODO: not all values are computed yet... + if ( !declHnd->attributeDecl( d->attDeclEName, d->attDeclAName, "", "", "" ) ) { + d->error = declHnd->errorString(); + goto parseError; + } + } + eat_ws(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Attlist: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Name: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + d->attDeclEName = name(); + break; + case Attdef: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + d->attDeclAName = name(); + break; + case Atttype: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGATTTYPE; + goto parseError; + } + break; + case DefReq: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case DefImp: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case DefFix: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Attval: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGATTVALUE; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a AttType [54] +*/ +bool QXmlSimpleReader::parseAttType() +{ + const signed char Init = 0; + const signed char ST = 1; // StringType + const signed char TTI = 2; // TokenizedType starting with 'I' + const signed char TTI2 = 3; // TokenizedType helpstate + const signed char TTI3 = 4; // TokenizedType helpstate + const signed char TTE = 5; // TokenizedType starting with 'E' + const signed char TTEY = 6; // TokenizedType starting with 'ENTITY' + const signed char TTEI = 7; // TokenizedType starting with 'ENTITI' + const signed char N = 8; // N read (TokenizedType or Notation) + const signed char TTNM = 9; // TokenizedType starting with 'NM' + const signed char TTNM2 = 10; // TokenizedType helpstate + const signed char NO = 11; // Notation + const signed char NO2 = 12; // Notation helpstate + const signed char NO3 = 13; // Notation helpstate + const signed char NOName = 14; // Notation, read name + const signed char NO4 = 15; // Notation helpstate + const signed char EN = 16; // Enumeration + const signed char ENNmt = 17; // Enumeration, read Nmtoken + const signed char EN2 = 18; // Enumeration helpstate + const signed char ADone = 19; // almost done (make next and accept) + const signed char Done = 20; + + const signed char InpWs = 0; // whitespace + const signed char InpOp = 1; // ( + const signed char InpCp = 2; // ) + const signed char InpPipe = 3; // | + const signed char InpC = 4; // C + const signed char InpE = 5; // E + const signed char InpI = 6; // I + const signed char InpM = 7; // M + const signed char InpN = 8; // N + const signed char InpO = 9; // O + const signed char InpR = 10; // R + const signed char InpS = 11; // S + const signed char InpY = 12; // Y + const signed char InpUnknown = 13; + + // use some kind of state machine for parsing + static signed char table[19][14] = { + /* InpWs InpOp InpCp InpPipe InpC InpE InpI InpM InpN InpO InpR InpS InpY InpUnknown */ + { -1, EN, -1, -1, ST, TTE, TTI, -1, N, -1, -1, -1, -1, -1 }, // Init + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // ST + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, TTI2, Done, Done, Done }, // TTI + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, TTI3, Done, Done }, // TTI2 + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTI3 + { -1, -1, -1, -1, -1, -1, TTEI, -1, -1, -1, -1, -1, TTEY, -1 }, // TTE + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTEY + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTEI + { -1, -1, -1, -1, -1, -1, -1, TTNM, -1, NO, -1, -1, -1, -1 }, // N + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, TTNM2, Done, Done }, // TTNM + { Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done, Done }, // TTNM2 + { NO2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NO + { -1, NO3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NO2 + { NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName, NOName }, // NO3 + { NO4, -1, ADone, NO3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NOName + { -1, -1, ADone, NO3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // NO4 + { -1, -1, ENNmt, -1, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt, ENNmt }, // EN + { EN2, -1, ADone, EN, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // ENNmt + { -1, -1, ADone, EN, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } // EN2 + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '(' ) { + input = InpOp; + } else if ( c == ')' ) { + input = InpCp; + } else if ( c == '|' ) { + input = InpPipe; + } else if ( c == 'C' ) { + input = InpC; + } else if ( c == 'E' ) { + input = InpE; + } else if ( c == 'I' ) { + input = InpI; + } else if ( c == 'M' ) { + input = InpM; + } else if ( c == 'N' ) { + input = InpN; + } else if ( c == 'O' ) { + input = InpO; + } else if ( c == 'R' ) { + input = InpR; + } else if ( c == 'S' ) { + input = InpS; + } else if ( c == 'Y' ) { + input = InpY; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case ST: + parseOk = parseString( "CDATA" ); + break; + case TTI: + parseOk = parseString( "ID" ); + break; + case TTI2: + parseOk = parseString( "REF" ); + break; + case TTI3: + next(); // S + break; + case TTE: + parseOk = parseString( "ENTIT" ); + break; + case TTEY: + next(); // Y + break; + case TTEI: + parseOk = parseString( "IES" ); + break; + case N: + next(); // N + break; + case TTNM: + parseOk = parseString( "MTOKEN" ); + break; + case TTNM2: + next(); // S + break; + case NO: + parseOk = parseString( "OTATION" ); + break; + case NO2: + eat_ws(); + break; + case NO3: + next_eat_ws(); + break; + case NOName: + parseOk = parseName(); + break; + case NO4: + eat_ws(); + break; + case EN: + next_eat_ws(); + break; + case ENNmt: + parseOk = parseNmtoken(); + break; + case EN2: + eat_ws(); + break; + case ADone: + next(); + break; + } + // no input is read after this + switch ( state ) { + case ST: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case TTI: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case TTI2: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case TTE: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case TTEI: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case TTNM: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case NO: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case NOName: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case ENNmt: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNMTOKEN; + goto parseError; + } + break; + case ADone: + return TRUE; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a AttValue [10] + + Precondition: the head stands on the beginning " or ' + + If this function was successful, the head stands on the first + character after the closing " or ' and the value of the attribute + is in string(). +*/ +bool QXmlSimpleReader::parseAttValue() +{ + bool tmp; + + const signed char Init = 0; + const signed char Dq = 1; // double quotes were read + const signed char DqRef = 2; // read references in double quotes + const signed char DqC = 3; // signed character read in double quotes + const signed char Sq = 4; // single quotes were read + const signed char SqRef = 5; // read references in single quotes + const signed char SqC = 6; // signed character read in single quotes + const signed char Done = 7; + + const signed char InpDq = 0; // " + const signed char InpSq = 1; // ' + const signed char InpAmp = 2; // & + const signed char InpLt = 3; // < + const signed char InpUnknown = 4; + + // use some kind of state machine for parsing + static signed char table[7][5] = { + /* InpDq InpSq InpAmp InpLt InpUnknown */ + { Dq, Sq, -1, -1, -1 }, // Init + { Done, DqC, DqRef, -1, DqC }, // Dq + { Done, DqC, DqRef, -1, DqC }, // DqRef + { Done, DqC, DqRef, -1, DqC }, // DqC + { SqC, Done, SqRef, -1, SqC }, // Sq + { SqC, Done, SqRef, -1, SqC }, // SqRef + { SqC, Done, SqRef, -1, SqC } // SqRef + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c == '"' ) { + input = InpDq; + } else if ( c == '\'' ) { + input = InpSq; + } else if ( c == '&' ) { + input = InpAmp; + } else if ( c == '<' ) { + input = InpLt; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Dq: + case Sq: + stringClear(); + next(); + break; + case DqRef: + case SqRef: + parseOk = parseReference( tmp, InAttributeValue ); + break; + case DqC: + case SqC: + stringAddC(); + next(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case DqRef: + case SqRef: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGREFERENCE; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a elementdecl [45]. + + Precondition: the beginning '<!E' is already read and the head + stands on the 'L' of '<!ELEMENT' +*/ +bool QXmlSimpleReader::parseElementDecl() +{ + const signed char Init = 0; + const signed char Elem = 1; // parse the beginning string + const signed char Ws1 = 2; // whitespace required + const signed char Nam = 3; // parse Name + const signed char Ws2 = 4; // whitespace required + const signed char Empty = 5; // read EMPTY + const signed char Any = 6; // read ANY + const signed char Cont = 7; // read contentspec (except ANY or EMPTY) + const signed char Mix = 8; // read Mixed + const signed char Mix2 = 9; // + const signed char Mix3 = 10; // + const signed char MixN1 = 11; // + const signed char MixN2 = 12; // + const signed char MixN3 = 13; // + const signed char MixN4 = 14; // + const signed char Cp = 15; // parse cp + const signed char Cp2 = 16; // + const signed char WsD = 17; // eat whitespace before Done + const signed char Done = 18; + + const signed char InpWs = 0; + const signed char InpGt = 1; // > + const signed char InpPipe = 2; // | + const signed char InpOp = 3; // ( + const signed char InpCp = 4; // ) + const signed char InpHash = 5; // # + const signed char InpQm = 6; // ? + const signed char InpAst = 7; // * + const signed char InpPlus = 8; // + + const signed char InpA = 9; // A + const signed char InpE = 10; // E + const signed char InpL = 11; // L + const signed char InpUnknown = 12; + + // use some kind of state machine for parsing + static signed char table[18][13] = { + /* InpWs InpGt InpPipe InpOp InpCp InpHash InpQm InpAst InpPlus InpA InpE InpL InpUnknown */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, Elem, -1 }, // Init + { Ws1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Elem + { -1, -1, -1, -1, -1, -1, -1, -1, -1, Nam, Nam, Nam, Nam }, // Ws1 + { Ws2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Nam + { -1, -1, -1, Cont, -1, -1, -1, -1, -1, Any, Empty, -1, -1 }, // Ws2 + { WsD, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Empty + { WsD, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Any + { -1, -1, -1, Cp, Cp, Mix, -1, -1, -1, Cp, Cp, Cp, Cp }, // Cont + { Mix2, -1, MixN1, -1, Mix3, -1, -1, -1, -1, -1, -1, -1, -1 }, // Mix + { -1, -1, MixN1, -1, Mix3, -1, -1, -1, -1, -1, -1, -1, -1 }, // Mix2 + { WsD, Done, -1, -1, -1, -1, -1, WsD, -1, -1, -1, -1, -1 }, // Mix3 + { -1, -1, -1, -1, -1, -1, -1, -1, -1, MixN2, MixN2, MixN2, MixN2 }, // MixN1 + { MixN3, -1, MixN1, -1, MixN4, -1, -1, -1, -1, -1, -1, -1, -1 }, // MixN2 + { -1, -1, MixN1, -1, MixN4, -1, -1, -1, -1, -1, -1, -1, -1 }, // MixN3 + { -1, -1, -1, -1, -1, -1, -1, WsD, -1, -1, -1, -1, -1 }, // MixN4 + { WsD, Done, -1, -1, -1, -1, Cp2, Cp2, Cp2, -1, -1, -1, -1 }, // Cp + { WsD, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, // Cp2 + { -1, Done, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } // WsD + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // read input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '>' ) { + input = InpGt; + } else if ( c == '|' ) { + input = InpPipe; + } else if ( c == '(' ) { + input = InpOp; + } else if ( c == ')' ) { + input = InpCp; + } else if ( c == '#' ) { + input = InpHash; + } else if ( c == '?' ) { + input = InpQm; + } else if ( c == '*' ) { + input = InpAst; + } else if ( c == '+' ) { + input = InpPlus; + } else if ( c == 'A' ) { + input = InpA; + } else if ( c == 'E' ) { + input = InpE; + } else if ( c == 'L' ) { + input = InpL; + } else { + input = InpUnknown; + } + // get new state +//qDebug( "%d -%d(%c)-> %d", state, input, c.latin1(), table[state][input] ); + state = table[state][input]; + + // in some cases do special actions depending on state + switch ( state ) { + case Elem: + parseOk = parseString( "LEMENT" ); + break; + case Ws1: + eat_ws(); + break; + case Nam: + parseOk = parseName(); + break; + case Ws2: + eat_ws(); + break; + case Empty: + parseOk = parseString( "EMPTY" ); + break; + case Any: + parseOk = parseString( "ANY" ); + break; + case Cont: + next_eat_ws(); + break; + case Mix: + parseOk = parseString( "#PCDATA" ); + break; + case Mix2: + eat_ws(); + break; + case Mix3: + next(); + break; + case MixN1: + next_eat_ws(); + break; + case MixN2: + parseOk = parseName(); + break; + case MixN3: + eat_ws(); + break; + case MixN4: + next(); + break; + case Cp: + parseOk = parseChoiceSeq(); + break; + case Cp2: + next(); + break; + case WsD: + next_eat_ws(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Elem: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Nam: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case Empty: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Any: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Mix: + if( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case MixN2: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case Cp: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGCHOICE; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a NotationDecl [82]. + + Precondition: the beginning '<!' is already read and the head + stands on the 'N' of '<!NOTATION' +*/ +bool QXmlSimpleReader::parseNotationDecl() +{ + const signed char Init = 0; + const signed char Not = 1; // read NOTATION + const signed char Ws1 = 2; // eat whitespaces + const signed char Nam = 3; // read Name + const signed char Ws2 = 4; // eat whitespaces + const signed char ExtID = 5; // parse ExternalID + const signed char Ws3 = 6; // eat whitespaces + const signed char Done = 7; + + const signed char InpWs = 0; + const signed char InpGt = 1; // > + const signed char InpN = 2; // N + const signed char InpUnknown = 3; + + // use some kind of state machine for parsing + static signed char table[7][4] = { + /* InpWs InpGt InpN InpUnknown */ + { -1, -1, Not, -1 }, // Init + { Ws1, -1, -1, -1 }, // Not + { -1, -1, Nam, Nam }, // Ws1 + { Ws2, Done, -1, -1 }, // Nam + { -1, Done, ExtID, ExtID }, // Ws2 + { Ws3, Done, -1, -1 }, // ExtID + { -1, Done, -1, -1 } // Ws3 + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '>' ) { + input = InpGt; + } else if ( c == 'N' ) { + input = InpN; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Not: + parseOk = parseString( "NOTATION" ); + break; + case Ws1: + eat_ws(); + break; + case Nam: + parseOk = parseName(); + break; + case Ws2: + eat_ws(); + break; + case ExtID: + parseOk = parseExternalID( TRUE ); + break; + case Ws3: + eat_ws(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Not: + if ( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Nam: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case ExtID: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGEXTERNALID; + goto parseError; + } + // call the handler + if ( dtdHnd ) { + if ( !dtdHnd->notationDecl( name(), d->publicId, d->systemId ) ) { + d->error = dtdHnd->errorString(); + goto parseError; + } + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse choice [49] or seq [50]. + + Precondition: the beginning '('S? is already read and the head + stands on the first non-whitespace character after it. +*/ +bool QXmlSimpleReader::parseChoiceSeq() +{ + const signed char Init = 0; + const signed char Ws1 = 1; // eat whitespace + const signed char CS_ = 2; // choice or set + const signed char Ws2 = 3; // eat whitespace + const signed char More = 4; // more cp to read + const signed char Name = 5; // read name + const signed char Done = 6; // + + const signed char InpWs = 0; // S + const signed char InpOp = 1; // ( + const signed char InpCp = 2; // ) + const signed char InpQm = 3; // ? + const signed char InpAst = 4; // * + const signed char InpPlus = 5; // + + const signed char InpPipe = 6; // | + const signed char InpComm = 7; // , + const signed char InpUnknown = 8; + + // use some kind of state machine for parsing + static signed char table[6][9] = { + /* InpWs InpOp InpCp InpQm InpAst InpPlus InpPipe InpComm InpUnknown */ + { -1, Ws1, -1, -1, -1, -1, -1, -1, Name }, // Init + { -1, CS_, -1, -1, -1, -1, -1, -1, CS_ }, // Ws1 + { Ws2, -1, Done, Ws2, Ws2, Ws2, More, More, -1 }, // CS_ + { -1, -1, Done, -1, -1, -1, More, More, -1 }, // Ws2 + { -1, Ws1, -1, -1, -1, -1, -1, -1, Name }, // More (same as Init) + { Ws2, -1, Done, Ws2, Ws2, Ws2, More, More, -1 } // Name (same as CS_) + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '(' ) { + input = InpOp; + } else if ( c == ')' ) { + input = InpCp; + } else if ( c == '?' ) { + input = InpQm; + } else if ( c == '*' ) { + input = InpAst; + } else if ( c == '+' ) { + input = InpPlus; + } else if ( c == '|' ) { + input = InpPipe; + } else if ( c == ',' ) { + input = InpComm; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Ws1: + next_eat_ws(); + break; + case CS_: + parseOk = parseChoiceSeq(); + break; + case Ws2: + next_eat_ws(); + break; + case More: + next_eat_ws(); + break; + case Name: + parseOk = parseName(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case CS_: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGCHOICE; + goto parseError; + } + break; + case Name: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a EntityDecl [70]. + + Precondition: the beginning '<!E' is already read and the head + stand on the 'N' of '<!ENTITY' +*/ +bool QXmlSimpleReader::parseEntityDecl() +{ + const signed char Init = 0; + const signed char Ent = 1; // parse "ENTITY" + const signed char Ws1 = 2; // white space read + const signed char Name = 3; // parse name + const signed char Ws2 = 4; // white space read + const signed char EValue = 5; // parse entity value + const signed char ExtID = 6; // parse ExternalID + const signed char Ws3 = 7; // white space read + const signed char Ndata = 8; // parse "NDATA" + const signed char Ws4 = 9; // white space read + const signed char NNam = 10; // parse name + const signed char PEDec = 11; // parse PEDecl + const signed char Ws6 = 12; // white space read + const signed char PENam = 13; // parse name + const signed char Ws7 = 14; // white space read + const signed char PEVal = 15; // parse entity value + const signed char PEEID = 16; // parse ExternalID + const signed char WsE = 17; // white space read + const signed char EDDone = 19; // done, but also report an external, unparsed entity decl + const signed char Done = 18; + + const signed char InpWs = 0; // white space + const signed char InpPer = 1; // % + const signed char InpQuot = 2; // " or ' + const signed char InpGt = 3; // > + const signed char InpN = 4; // N + const signed char InpUnknown = 5; + + // use some kind of state machine for parsing + static signed char table[18][6] = { + /* InpWs InpPer InpQuot InpGt InpN InpUnknown */ + { -1, -1, -1, -1, Ent, -1 }, // Init + { Ws1, -1, -1, -1, -1, -1 }, // Ent + { -1, PEDec, -1, -1, Name, Name }, // Ws1 + { Ws2, -1, -1, -1, -1, -1 }, // Name + { -1, -1, EValue, -1, -1, ExtID }, // Ws2 + { WsE, -1, -1, Done, -1, -1 }, // EValue + { Ws3, -1, -1, EDDone,-1, -1 }, // ExtID + { -1, -1, -1, EDDone,Ndata, -1 }, // Ws3 + { Ws4, -1, -1, -1, -1, -1 }, // Ndata + { -1, -1, -1, -1, NNam, NNam }, // Ws4 + { WsE, -1, -1, Done, -1, -1 }, // NNam + { Ws6, -1, -1, -1, -1, -1 }, // PEDec + { -1, -1, -1, -1, PENam, PENam }, // Ws6 + { Ws7, -1, -1, -1, -1, -1 }, // PENam + { -1, -1, PEVal, -1, -1, PEEID }, // Ws7 + { WsE, -1, -1, Done, -1, -1 }, // PEVal + { WsE, -1, -1, Done, -1, -1 }, // PEEID + { -1, -1, -1, Done, -1, -1 } // WsE + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_S(c) ) { + input = InpWs; + } else if ( c == '%' ) { + input = InpPer; + } else if ( c == '"' || c == '\'' ) { + input = InpQuot; + } else if ( c == '>' ) { + input = InpGt; + } else if ( c == 'N' ) { + input = InpN; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Ent: + parseOk = parseString( "NTITY" ); + break; + case Ws1: + eat_ws(); + break; + case Name: + parseOk = parseName(); + break; + case Ws2: + eat_ws(); + break; + case EValue: + parseOk = parseEntityValue(); + break; + case ExtID: + parseOk = parseExternalID(); + break; + case Ws3: + eat_ws(); + break; + case Ndata: + parseOk = parseString( "NDATA" ); + break; + case Ws4: + eat_ws(); + break; + case NNam: + parseOk = parseName( TRUE ); + break; + case PEDec: + next(); + break; + case Ws6: + eat_ws(); + break; + case PENam: + parseOk = parseName(); + break; + case Ws7: + eat_ws(); + break; + case PEVal: + parseOk = parseEntityValue(); + break; + case PEEID: + parseOk = parseExternalID(); + break; + case WsE: + eat_ws(); + break; + case EDDone: + next(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Ent: + if ( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case Name: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case EValue: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGENTITYVALUE; + goto parseError; + } + if ( !entityExist( name() ) ) { + d->entities.insert( name(), string() ); + if ( declHnd ) { + if ( !declHnd->internalEntityDecl( name(), string() ) ) { + d->error = declHnd->errorString(); + goto parseError; + } + } + } + break; + case ExtID: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGEXTERNALID; + goto parseError; + } + break; + case Ndata: + if ( !parseOk ) { + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + break; + case NNam: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + if ( !entityExist( name() ) ) { + d->externEntities.insert( name(), QXmlSimpleReaderPrivate::ExternEntity( d->publicId, d->systemId, ref() ) ); + if ( dtdHnd ) { + if ( !dtdHnd->unparsedEntityDecl( name(), d->publicId, d->systemId, ref() ) ) { + d->error = declHnd->errorString(); + goto parseError; + } + } + } + break; + case PENam: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case PEVal: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGENTITYVALUE; + goto parseError; + } + if ( !entityExist( name() ) ) { + d->parameterEntities.insert( name(), string() ); + if ( declHnd ) { + if ( !declHnd->internalEntityDecl( QString("%")+name(), string() ) ) { + d->error = declHnd->errorString(); + goto parseError; + } + } + } + break; + case PEEID: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGEXTERNALID; + goto parseError; + } + if ( !entityExist( name() ) ) { + d->externParameterEntities.insert( name(), QXmlSimpleReaderPrivate::ExternParameterEntity( d->publicId, d->systemId ) ); + if ( declHnd ) { + if ( !declHnd->externalEntityDecl( QString("%")+name(), d->publicId, d->systemId ) ) { + d->error = declHnd->errorString(); + goto parseError; + } + } + } + break; + case EDDone: + if ( !entityExist( name() ) ) { + d->externEntities.insert( name(), QXmlSimpleReaderPrivate::ExternEntity( d->publicId, d->systemId, QString::null ) ); + if ( declHnd ) { + if ( !declHnd->externalEntityDecl( name(), d->publicId, d->systemId ) ) { + d->error = declHnd->errorString(); + goto parseError; + } + } + } + return TRUE; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a EntityValue [9] +*/ +bool QXmlSimpleReader::parseEntityValue() +{ + bool tmp; + + const signed char Init = 0; + const signed char Dq = 1; // EntityValue is double quoted + const signed char DqC = 2; // signed character + const signed char DqPER = 3; // PERefence + const signed char DqRef = 4; // Reference + const signed char Sq = 5; // EntityValue is double quoted + const signed char SqC = 6; // signed character + const signed char SqPER = 7; // PERefence + const signed char SqRef = 8; // Reference + const signed char Done = 9; + + const signed char InpDq = 0; // " + const signed char InpSq = 1; // ' + const signed char InpAmp = 2; // & + const signed char InpPer = 3; // % + const signed char InpUnknown = 4; + + // use some kind of state machine for parsing + static signed char table[9][5] = { + /* InpDq InpSq InpAmp InpPer InpUnknown */ + { Dq, Sq, -1, -1, -1 }, // Init + { Done, DqC, DqRef, DqPER, DqC }, // Dq + { Done, DqC, DqRef, DqPER, DqC }, // DqC + { Done, DqC, DqRef, DqPER, DqC }, // DqPER + { Done, DqC, DqRef, DqPER, DqC }, // DqRef + { SqC, Done, SqRef, SqPER, SqC }, // Sq + { SqC, Done, SqRef, SqPER, SqC }, // SqC + { SqC, Done, SqRef, SqPER, SqC }, // SqPER + { SqC, Done, SqRef, SqPER, SqC } // SqRef + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c == '"' ) { + input = InpDq; + } else if ( c == '\'' ) { + input = InpSq; + } else if ( c == '&' ) { + input = InpAmp; + } else if ( c == '%' ) { + input = InpPer; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Dq: + case Sq: + stringClear(); + next(); + break; + case DqC: + case SqC: + stringAddC(); + next(); + break; + case DqPER: + case SqPER: + parseOk = parsePEReference( InEntityValue ); + break; + case DqRef: + case SqRef: + parseOk = parseReference( tmp, InEntityValue ); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case DqPER: + case SqPER: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGDOCTYPE; + goto parseError; + } + break; + case DqRef: + case SqRef: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGREFERENCE; + goto parseError; + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a comment [15]. + + Precondition: the beginning '<!' of the comment is already read and the head + stands on the first '-' of '<!--'. + + If this funktion was successful, the head-position is on the first + character after the comment. +*/ +bool QXmlSimpleReader::parseComment() +{ + const signed char Init = 0; + const signed char Dash1 = 1; // the first dash was read + const signed char Dash2 = 2; // the second dash was read + const signed char Com = 3; // read comment + const signed char Com2 = 4; // read comment (help state) + const signed char ComE = 5; // finished reading comment + const signed char Done = 6; + + const signed char InpDash = 0; // - + const signed char InpGt = 1; // > + const signed char InpUnknown = 2; + + // use some kind of state machine for parsing + static signed char table[6][3] = { + /* InpDash InpGt InpUnknown */ + { Dash1, -1, -1 }, // Init + { Dash2, -1, -1 }, // Dash1 + { Com2, Com, Com }, // Dash2 + { Com2, Com, Com }, // Com + { ComE, Com, Com }, // Com2 + { -1, Done, -1 } // ComE + }; + signed char state = Init; + signed char input; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c == '-' ) { + input = InpDash; + } else if ( c == '>' ) { + input = InpGt; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Dash1: + next(); + break; + case Dash2: + next(); + break; + case Com: + stringAddC(); + next(); + break; + case Com2: + next(); + break; + case ComE: + next(); + break; + case Done: + next(); + break; + } + // no input is read after this + switch ( state ) { + case Dash2: + stringClear(); + break; + case Com2: + // if next character is not a dash than don't skip it + if ( c != '-' ) { + stringAddC( '-' ); + } + break; + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_ERRORPARSINGCOMMENT; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a Attribute [41]. + + Precondition: the head stands on the first character of the name of the + attribute (i.e. all whitespaces are already parsed). + + The head stand on the next character after the end quotes. The variable name + contains the name of the attribute and the variable string contains the value + of the attribute. +*/ +bool QXmlSimpleReader::parseAttribute() +{ + const signed char Init = 0; + const signed char PName = 1; // parse name + const signed char Ws = 2; // eat ws + const signed char Eq = 3; // the '=' was read + const signed char Quotes = 4; // " or ' were read + + const signed char InpNameBe = 0; + const signed char InpEq = 1; // = + const signed char InpDq = 2; // " + const signed char InpSq = 3; // ' + const signed char InpUnknown = 4; + + // use some kind of state machine for parsing + static signed char table[4][5] = { + /* InpNameBe InpEq InpDq InpSq InpUnknown */ + { PName, -1, -1, -1, -1 }, // Init + { -1, Eq, -1, -1, Ws }, // PName + { -1, Eq, -1, -1, -1 }, // Ws + { -1, -1, Quotes, Quotes, -1 } // Eq + }; + signed char state = Init; + signed char input; + bool parseOk = TRUE; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_NameBeginning(c) ) { + input = InpNameBe; + } else if ( c == '=' ) { + input = InpEq; + } else if ( c == '"' ) { + input = InpDq; + } else if ( c == '\'' ) { + input = InpSq; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case PName: + parseOk = parseName(); + break; + case Ws: + eat_ws(); + break; + case Eq: + next_eat_ws(); + break; + case Quotes: + parseOk = parseAttValue(); + break; + } + // no input is read after this + switch ( state ) { + case PName: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGNAME; + goto parseError; + } + break; + case Quotes: + if ( !parseOk ) { + d->error = XMLERR_ERRORPARSINGATTVALUE; + goto parseError; + } + // Done + return TRUE; + case -1: + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a Name [5] and store the name in name or ref (if useRef is TRUE). +*/ +bool QXmlSimpleReader::parseName( bool useRef ) +{ + const signed char Init = 0; + const signed char Name1 = 1; // parse first signed character of the name + const signed char Name = 2; // parse name + const signed char Done = 3; + + const signed char InpNameBe = 0; // name beginning signed characters + const signed char InpNameCh = 1; // NameChar without InpNameBe + const signed char InpUnknown = 2; + + // use some kind of state machine for parsing + static signed char table[3][3] = { + /* InpNameBe InpNameCh InpUnknown */ + { Name1, -1, -1 }, // Init + { Name, Name, Done }, // Name1 + { Name, Name, Done } // Name + }; + signed char state = Init; + signed char input; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_NameBeginning(c) ) { + input = InpNameBe; + } else if ( is_NameChar(c) ) { + input = InpNameCh; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case Name1: + if ( useRef ) { + refClear(); + refAddC(); + } else { + nameClear(); + nameAddC(); + } + next(); + break; + case Name: + if ( useRef ) { + refAddC(); + } else { + nameAddC(); + } + next(); + break; + } + // no input is read after this + switch ( state ) { + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a Nmtoken [7] and store the name in name. +*/ +bool QXmlSimpleReader::parseNmtoken() +{ + const signed char Init = 0; + const signed char NameF = 1; + const signed char Name = 2; + const signed char Done = 3; + + const signed char InpNameCh = 0; // NameChar without InpNameBe + const signed char InpUnknown = 1; + + // use some kind of state machine for parsing + static signed char table[3][2] = { + /* InpNameCh InpUnknown */ + { NameF, -1 }, // Init + { Name, Done }, // NameF + { Name, Done } // Name + }; + signed char state = Init; + signed char input; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( is_NameChar(c) ) { + input = InpNameCh; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case NameF: + nameClear(); + nameAddC(); + next(); + break; + case Name: + nameAddC(); + next(); + break; + } + // no input is read after this + switch ( state ) { + case Done: + return TRUE; + case -1: + // Error + d->error = XMLERR_LETTEREXPECTED; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Parse a Reference [67]. + + charDataRead is set to TRUE if the reference must not be parsed. The + character(s) which the reference mapped to are appended to string. The + head stands on the first character after the reference. + + charDataRead is set to FALSE if the reference must be parsed. The + charachter(s) which the reference mapped to are inserted at the reference + position. The head stands on the first character of the replacement). +*/ +bool QXmlSimpleReader::parseReference( bool &charDataRead, EntityRecognitionContext context ) +{ + // temporary variables + uint tmp; + bool ok; + + const signed char Init = 0; + const signed char SRef = 1; // start of a reference + const signed char ChRef = 2; // parse CharRef + const signed char ChDec = 3; // parse CharRef decimal + const signed char ChHexS = 4; // start CharRef hexadecimal + const signed char ChHex = 5; // parse CharRef hexadecimal + const signed char Name = 6; // parse name + const signed char DoneD = 7; // done CharRef decimal + const signed char DoneH = 8; // done CharRef hexadecimal + const signed char DoneN = 9; // done EntityRef + + const signed char InpAmp = 0; // & + const signed char InpSemi = 1; // ; + const signed char InpHash = 2; // # + const signed char InpX = 3; // x + const signed char InpNum = 4; // 0-9 + const signed char InpHex = 5; // a-f A-F + const signed char InpUnknown = 6; + + // use some kind of state machine for parsing + static signed char table[8][7] = { + /* InpAmp InpSemi InpHash InpX InpNum InpHex InpUnknown */ + { SRef, -1, -1, -1, -1, -1, -1 }, // Init + { -1, -1, ChRef, Name, Name, Name, Name }, // SRef + { -1, -1, -1, ChHexS, ChDec, -1, -1 }, // ChRef + { -1, DoneD, -1, -1, ChDec, -1, -1 }, // ChDec + { -1, -1, -1, -1, ChHex, ChHex, -1 }, // ChHexS + { -1, DoneH, -1, -1, ChHex, ChHex, -1 }, // ChHex + { -1, DoneN, -1, -1, -1, -1, -1 } // Name + }; + signed char state = Init; + signed char input; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c.row() ) { + input = InpUnknown; + } else if ( c.cell() == '&' ) { + input = InpAmp; + } else if ( c.cell() == ';' ) { + input = InpSemi; + } else if ( c.cell() == '#' ) { + input = InpHash; + } else if ( c.cell() == 'x' ) { + input = InpX; + } else if ( '0' <= c.cell() && c.cell() <= '9' ) { + input = InpNum; + } else if ( 'a' <= c.cell() && c.cell() <= 'f' ) { + input = InpHex; + } else if ( 'A' <= c.cell() && c.cell() <= 'F' ) { + input = InpHex; + } else { + input = InpUnknown; + } + + // set state according to input + state = table[state][input]; + + // do some actions according to state + switch ( state ) { + case SRef: + refClear(); + next(); + break; + case ChRef: + next(); + break; + case ChDec: + refAddC(); + next(); + break; + case ChHexS: + next(); + break; + case ChHex: + refAddC(); + next(); + break; + case Name: + // read the name into the ref + parseName( TRUE ); + break; + case DoneD: + tmp = ref().toUInt( &ok, 10 ); + if ( ok ) { + stringAddC( QChar(tmp) ); + } else { + d->error = XMLERR_ERRORPARSINGREFERENCE; + goto parseError; + } + charDataRead = TRUE; + next(); + break; + case DoneH: + tmp = ref().toUInt( &ok, 16 ); + if ( ok ) { + stringAddC( QChar(tmp) ); + } else { + d->error = XMLERR_ERRORPARSINGREFERENCE; + goto parseError; + } + charDataRead = TRUE; + next(); + break; + case DoneN: + if ( !processReference( charDataRead, context ) ) + goto parseError; + next(); + break; + } + // no input is read after this + switch ( state ) { + case DoneD: + return TRUE; + case DoneH: + return TRUE; + case DoneN: + return TRUE; + case -1: + // Error + d->error = XMLERR_ERRORPARSINGREFERENCE; + goto parseError; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + +/*! + Helper function for parseReference() +*/ +bool QXmlSimpleReader::processReference( bool &charDataRead, EntityRecognitionContext context ) +{ + QString reference = ref(); + if ( reference == "amp" ) { + if ( context == InEntityValue ) { + // Bypassed + stringAddC( '&' ); stringAddC( 'a' ); stringAddC( 'm' ); stringAddC( 'p' ); stringAddC( ';' ); + } else { + // Included or Included in literal + stringAddC( '&' ); + } + charDataRead = TRUE; + } else if ( reference == "lt" ) { + if ( context == InEntityValue ) { + // Bypassed + stringAddC( '&' ); stringAddC( 'l' ); stringAddC( 't' ); stringAddC( ';' ); + } else { + // Included or Included in literal + stringAddC( '<' ); + } + charDataRead = TRUE; + } else if ( reference == "gt" ) { + if ( context == InEntityValue ) { + // Bypassed + stringAddC( '&' ); stringAddC( 'g' ); stringAddC( 't' ); stringAddC( ';' ); + } else { + // Included or Included in literal + stringAddC( '>' ); + } + charDataRead = TRUE; + } else if ( reference == "apos" ) { + if ( context == InEntityValue ) { + // Bypassed + stringAddC( '&' ); stringAddC( 'a' ); stringAddC( 'p' ); stringAddC( 'o' ); stringAddC( 's' ); stringAddC( ';' ); + } else { + // Included or Included in literal + stringAddC( '\'' ); + } + charDataRead = TRUE; + } else if ( reference == "quot" ) { + if ( context == InEntityValue ) { + // Bypassed + stringAddC( '&' ); stringAddC( 'q' ); stringAddC( 'u' ); stringAddC( 'o' ); stringAddC( 't' ); stringAddC( ';' ); + } else { + // Included or Included in literal + stringAddC( '"' ); + } + charDataRead = TRUE; + } else { + QMap<QString,QString>::Iterator it; + it = d->entities.find( reference ); + if ( it != d->entities.end() ) { + // "Internal General" + switch ( context ) { + case InContent: + // Included + xmlRef = it.data() + xmlRef; + charDataRead = FALSE; + break; + case InAttributeValue: + // Included in literal + xmlRef = it.data().replace( QRegExp("\""), """ ).replace( QRegExp("'"), "'" ) + + xmlRef; + charDataRead = FALSE; + break; + case InEntityValue: + { + // Bypassed + stringAddC( '&' ); + for ( int i=0; i<(int)reference.length(); i++ ) { + stringAddC( reference[i] ); + } + stringAddC( ';'); + charDataRead = TRUE; + } + break; + case InDTD: + // Forbidden + d->error = XMLERR_INTERNALGENERALENTITYINDTD; + charDataRead = FALSE; + break; + } + } else { + QMap<QString,QXmlSimpleReaderPrivate::ExternEntity>::Iterator itExtern; + itExtern = d->externEntities.find( reference ); + if ( itExtern == d->externEntities.end() ) { + // entity not declared + // ### check this case for conformance + if ( context == InEntityValue ) { + // Bypassed + stringAddC( '&' ); + for ( int i=0; i<(int)reference.length(); i++ ) { + stringAddC( reference[i] ); + } + stringAddC( ';'); + charDataRead = TRUE; + } else { + if ( contentHnd ) { + if ( !contentHnd->skippedEntity( reference ) ) { + d->error = contentHnd->errorString(); + return FALSE; // error + } + } + } + } else if ( (*itExtern).notation.isNull() ) { + // "External Parsed General" + switch ( context ) { + case InContent: + // Included if validating + if ( contentHnd ) { + if ( !contentHnd->skippedEntity( reference ) ) { + d->error = contentHnd->errorString(); + return FALSE; // error + } + } + charDataRead = FALSE; + break; + case InAttributeValue: + // Forbidden + d->error = XMLERR_EXTERNALGENERALENTITYINAV; + charDataRead = FALSE; + break; + case InEntityValue: + { + // Bypassed + stringAddC( '&' ); + for ( int i=0; i<(int)reference.length(); i++ ) { + stringAddC( reference[i] ); + } + stringAddC( ';'); + charDataRead = TRUE; + } + break; + case InDTD: + // Forbidden + d->error = XMLERR_EXTERNALGENERALENTITYINDTD; + charDataRead = FALSE; + break; + } + } else { + // "Unparsed" + // ### notify for "Occurs as Attribute Value" missing (but this is no refence, anyway) + // Forbidden + d->error = XMLERR_UNPARSEDENTITYREFERENCE; + charDataRead = FALSE; + return FALSE; // error + } + } + } + return TRUE; // no error +} + + +/*! + Parse over a simple string. + + After the string was successfully parsed, the head is on the first + character after the string. +*/ +bool QXmlSimpleReader::parseString( const QString& s ) +{ + signed char Done = s.length(); + + const signed char InpCharExpected = 0; // the character that was expected + const signed char InpUnknown = 1; + + signed char state = 0; // state in this function is the position in the string s + signed char input; + + while ( TRUE ) { + + // get input + if ( atEnd() ) { + d->error = XMLERR_UNEXPECTEDEOF; + goto parseError; + } + if ( c == s[(int)state] ) { + input = InpCharExpected; + } else { + input = InpUnknown; + } + + // set state according to input + if ( input == InpCharExpected ) { + state++; + } else { + // Error + d->error = XMLERR_UNEXPECTEDCHARACTER; + goto parseError; + } + + // do some actions according to state + next(); + // no input is read after this + if ( state == Done ) { + return TRUE; + } + + } + + return TRUE; + +parseError: + reportParseError(); + return FALSE; +} + + +/*! + Inits the data values. +*/ +void QXmlSimpleReader::init( const QXmlInputSource& i ) +{ + xml = i.data(); + xmlLength = xml.length(); + xmlRef = ""; + + d->externParameterEntities.clear(); + d->parameterEntities.clear(); + d->externEntities.clear(); + d->entities.clear(); + + tags.clear(); + + d->doctype = ""; + d->xmlVersion = ""; + d->encoding = ""; + d->standalone = QXmlSimpleReaderPrivate::Unknown; + + lineNr = 0; + columnNr = -1; + pos = 0; + next(); + d->error = XMLERR_OK; +} + +/*! + Returns TRUE if a entity with the name \a e exists, + otherwise returns FALSE. +*/ +bool QXmlSimpleReader::entityExist( const QString& e ) const +{ + if ( d->parameterEntities.find(e) == d->parameterEntities.end() && + d->externParameterEntities.find(e) == d->externParameterEntities.end() ) { + return FALSE; + } else { + return TRUE; + } +} + +void QXmlSimpleReader::reportParseError() +{ + if ( errorHnd ) + errorHnd->fatalError( QXmlParseException( d->error, columnNr+1, lineNr+1 ) ); +} + +#endif //QT_NO_XML diff --git a/trunk/qtools/qxml.h b/trunk/qtools/qxml.h new file mode 100644 index 0000000..2f7567d --- /dev/null +++ b/trunk/qtools/qxml.h @@ -0,0 +1,671 @@ +/**************************************************************************** +** +** +** Definition of QXmlSimpleReader and related classes. +** +** Created : 000518 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the XML module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition licenses may use this +** file in accordance with the Qt Commercial License Agreement provided +** with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QXML_H +#define QXML_H + +#include <qmodules.h> + +#if !defined(QT_MODULE_XML) +#define QM_EXPORT +#else +#define QM_EXPORT Q_EXPORT +#endif + +#ifndef QT_H +#include <qtextstream.h> +#include <qfile.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qvaluestack.h> +#include <qmap.h> +#endif // QT_H + +#ifndef QT_NO_XML + +class QXmlNamespaceSupport; +class QXmlAttributes; +class QXmlContentHandler; +class QXmlDefaultHandler; +class QXmlDTDHandler; +class QXmlEntityResolver; +class QXmlErrorHandler; +class QXmlLexicalHandler; +class QXmlDeclHandler; +class QXmlInputSource; +class QXmlLocator; +class QXmlNamespaceSupport; +class QXmlParseException; + +class QXmlReader; +class QXmlSimpleReader; + +class QXmlSimpleReaderPrivate; +class QXmlNamespaceSupportPrivate; +class QXmlAttributesPrivate; +class QXmlInputSourcePrivate; +class QXmlParseExceptionPrivate; +class QXmlLocatorPrivate; +class QXmlDefaultHandlerPrivate; + + +// +// SAX Namespace Support +// + +#if defined(Q_TEMPLATEDLL) +// MOC_SKIP_BEGIN +template class QM_EXPORT QMap<QString, QString>; +template class QM_EXPORT QValueStack<QMap<QString, QString> >; +template class QM_EXPORT QValueStack<QString>; +// MOC_SKIP_END +#endif + +class QM_EXPORT QXmlNamespaceSupport +{ +public: + QXmlNamespaceSupport(); + ~QXmlNamespaceSupport(); + + void setPrefix( const QString&, const QString& ); + + QString prefix( const QString& ) const; + QString uri( const QString& ) const; + void splitName( const QString&, QString&, QString& ) const; + void processName( const QString&, bool, QString&, QString& ) const; + QStringList prefixes() const; + QStringList prefixes( const QString& ) const; + + void pushContext(); + void popContext(); + void reset(); +private: + QValueStack<QMap<QString, QString> > nsStack; + QMap<QString, QString> ns; + + QXmlNamespaceSupportPrivate *d; +}; + + +// +// SAX Attributes +// + +class QM_EXPORT QXmlAttributes +{ +public: + QXmlAttributes() {} + virtual ~QXmlAttributes() {} + + int index( const QString& qName ) const; + int index( const QString& uri, const QString& localPart ) const; + int length() const; + QString localName( int index ) const; + QString qName( int index ) const; + QString uri( int index ) const; + QString type( int index ) const; + QString type( const QString& qName ) const; + QString type( const QString& uri, const QString& localName ) const; + QString value( int index ) const; + QString value( const QString& qName ) const; + QString value( const QString& uri, const QString& localName ) const; + +private: + QStringList qnameList; + QStringList uriList; + QStringList localnameList; + QStringList valueList; + + QXmlAttributesPrivate *d; + + friend class QXmlSimpleReader; +}; + +// +// SAX Input Source +// + +class QM_EXPORT QXmlInputSource +{ +public: + QXmlInputSource(); + QXmlInputSource( QTextStream& stream ); + QXmlInputSource( QFile& file ); + virtual ~QXmlInputSource(); + + virtual const QString& data() const; + virtual void setData( const QString& d ); + +private: + void readInput( QByteArray& rawData ); + + QString input; + + QXmlInputSourcePrivate *d; +}; + +// +// SAX Exception Classes +// + +class QM_EXPORT QXmlParseException +{ +public: + QXmlParseException( const QString& name="", int c=-1, int l=-1, const QString& p="", const QString& s="" ) + : msg( name ), column( c ), line( l ), pub( p ), sys( s ) + { } + + int columnNumber() const; + int lineNumber() const; + QString publicId() const; + QString systemId() const; + QString message() const; + +private: + QString msg; + int column; + int line; + QString pub; + QString sys; + + QXmlParseExceptionPrivate *d; +}; + + +// +// XML Reader +// + +class QM_EXPORT QXmlReader +{ +public: + virtual ~QXmlReader() {} + virtual bool feature( const QString& name, bool *ok = 0 ) const = 0; + virtual void setFeature( const QString& name, bool value ) = 0; + virtual bool hasFeature( const QString& name ) const = 0; + virtual void* property( const QString& name, bool *ok = 0 ) const = 0; + virtual void setProperty( const QString& name, void* value ) = 0; + virtual bool hasProperty( const QString& name ) const = 0; + virtual void setEntityResolver( QXmlEntityResolver* handler ) = 0; + virtual QXmlEntityResolver* entityResolver() const = 0; + virtual void setDTDHandler( QXmlDTDHandler* handler ) = 0; + virtual QXmlDTDHandler* DTDHandler() const = 0; + virtual void setContentHandler( QXmlContentHandler* handler ) = 0; + virtual QXmlContentHandler* contentHandler() const = 0; + virtual void setErrorHandler( QXmlErrorHandler* handler ) = 0; + virtual QXmlErrorHandler* errorHandler() const = 0; + virtual void setLexicalHandler( QXmlLexicalHandler* handler ) = 0; + virtual QXmlLexicalHandler* lexicalHandler() const = 0; + virtual void setDeclHandler( QXmlDeclHandler* handler ) = 0; + virtual QXmlDeclHandler* declHandler() const = 0; + virtual bool parse( const QXmlInputSource& input ) = 0; +}; + +class QM_EXPORT QXmlSimpleReader : public QXmlReader +{ +public: + QXmlSimpleReader(); + virtual ~QXmlSimpleReader(); + + bool feature( const QString& name, bool *ok = 0 ) const; + void setFeature( const QString& name, bool value ); + bool hasFeature( const QString& name ) const; + + void* property( const QString& name, bool *ok = 0 ) const; + void setProperty( const QString& name, void* value ); + bool hasProperty( const QString& name ) const; + + void setEntityResolver( QXmlEntityResolver* handler ); + QXmlEntityResolver* entityResolver() const; + void setDTDHandler( QXmlDTDHandler* handler ); + QXmlDTDHandler* DTDHandler() const; + void setContentHandler( QXmlContentHandler* handler ); + QXmlContentHandler* contentHandler() const; + void setErrorHandler( QXmlErrorHandler* handler ); + QXmlErrorHandler* errorHandler() const; + void setLexicalHandler( QXmlLexicalHandler* handler ); + QXmlLexicalHandler* lexicalHandler() const; + void setDeclHandler( QXmlDeclHandler* handler ); + QXmlDeclHandler* declHandler() const; + + bool parse( const QXmlInputSource& input ); + +private: + // variables + QXmlContentHandler* contentHnd; + QXmlErrorHandler* errorHnd; + QXmlDTDHandler* dtdHnd; + QXmlEntityResolver* entityRes; + QXmlLexicalHandler* lexicalHnd; + QXmlDeclHandler* declHnd; + + QChar c; // the character at reading position + int lineNr; // number of line + int columnNr; // position in line + int pos; // position in string + + int namePos; + QChar nameArray[256]; // only used for names + QString nameValue; // only used for names + int refPos; + QChar refArray[256]; // only used for references + QString refValue; // only used for references + int stringPos; + QChar stringArray[256]; // used for any other strings that are parsed + QString stringValue; // used for any other strings that are parsed + + QString xml; + int xmlLength; + QString xmlRef; // used for parsing of entity references + + QValueStack<QString> tags; + + QXmlSimpleReaderPrivate* d; + + static const QChar QEOF; + + // inlines + virtual bool is_S( const QChar& ); + virtual bool is_Letter( const QChar& ); + virtual bool is_NameBeginning( const QChar& ); + virtual bool is_Digit( const QChar& ); + virtual bool is_CombiningChar( const QChar& ); + virtual bool is_Extender( const QChar& ); + virtual bool is_NameChar( const QChar& ); + + QString& string(); + void stringClear(); + void stringAddC(); + void stringAddC(const QChar&); + QString& name(); + void nameClear(); + void nameAddC(); + void nameAddC(const QChar&); + QString& ref(); + void refClear(); + void refAddC(); + void refAddC(const QChar&); + + // used by parseReference() and parsePEReference() + enum EntityRecognitionContext { InContent, InAttributeValue, InEntityValue, InDTD }; + + // private functions + void eat_ws(); + void next_eat_ws(); + + void next(); + bool atEnd(); + + void init( const QXmlInputSource& i ); + + bool entityExist( const QString& ) const; + + bool parseProlog(); + bool parseElement(); + bool parseElementEmptyTag( bool &t, QString &uri, QString &lname ); + bool parseElementETagBegin2(); + bool parseElementAttribute( QString &prefix, QString &uri, QString &lname ); + bool parseMisc(); + bool parseContent(); + + bool parsePI(bool xmldecl=FALSE); + bool parseDoctype(); + bool parseComment(); + + bool parseName( bool useRef=FALSE ); + bool parseNmtoken(); + bool parseAttribute(); + bool parseReference( bool &charDataRead, EntityRecognitionContext context ); + bool processReference( bool &charDataRead, EntityRecognitionContext context ); + + bool parseExternalID( bool allowPublicID = FALSE ); + bool parsePEReference( EntityRecognitionContext context ); + bool parseMarkupdecl(); + bool parseAttlistDecl(); + bool parseAttType(); + bool parseAttValue(); + bool parseElementDecl(); + bool parseNotationDecl(); + bool parseChoiceSeq(); + bool parseEntityDecl(); + bool parseEntityValue(); + + bool parseString( const QString& s ); + + void reportParseError(); + + friend class QXmlSimpleReaderPrivate; + friend class QXmlLocator; +}; + +// +// SAX Locator +// + +class QM_EXPORT QXmlLocator +{ +public: + QXmlLocator( QXmlSimpleReader* parent ) + { reader = parent; } + ~QXmlLocator() + { } + + int columnNumber(); + int lineNumber(); +// QString getPublicId() +// QString getSystemId() + +private: + QXmlSimpleReader* reader; + + QXmlLocatorPrivate *d; +}; + +// +// SAX handler classes +// + +class QM_EXPORT QXmlContentHandler +{ +public: + virtual ~QXmlContentHandler() {} + virtual void setDocumentLocator( QXmlLocator* locator ) = 0; + virtual bool startDocument() = 0; + virtual bool endDocument() = 0; + virtual bool startPrefixMapping( const QString& prefix, const QString& uri ) = 0; + virtual bool endPrefixMapping( const QString& prefix ) = 0; + virtual bool startElement( const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts ) = 0; + virtual bool endElement( const QString& namespaceURI, const QString& localName, const QString& qName ) = 0; + virtual bool characters( const QString& ch ) = 0; + virtual bool ignorableWhitespace( const QString& ch ) = 0; + virtual bool processingInstruction( const QString& target, const QString& data ) = 0; + virtual bool skippedEntity( const QString& name ) = 0; + virtual QString errorString() = 0; +}; + +class QM_EXPORT QXmlErrorHandler +{ +public: + virtual ~QXmlErrorHandler() {} + virtual bool warning( const QXmlParseException& exception ) = 0; + virtual bool error( const QXmlParseException& exception ) = 0; + virtual bool fatalError( const QXmlParseException& exception ) = 0; + virtual QString errorString() = 0; +}; + +class QM_EXPORT QXmlDTDHandler +{ +public: + virtual ~QXmlDTDHandler() {} + virtual bool notationDecl( const QString& name, const QString& publicId, const QString& systemId ) = 0; + virtual bool unparsedEntityDecl( const QString& name, const QString& publicId, const QString& systemId, const QString& notationName ) = 0; + virtual QString errorString() = 0; +}; + +class QM_EXPORT QXmlEntityResolver +{ +public: + virtual ~QXmlEntityResolver() {} + virtual bool resolveEntity( const QString& publicId, const QString& systemId, QXmlInputSource* ret ) = 0; + virtual QString errorString() = 0; +}; + +class QM_EXPORT QXmlLexicalHandler +{ +public: + virtual ~QXmlLexicalHandler() {} + virtual bool startDTD( const QString& name, const QString& publicId, const QString& systemId ) = 0; + virtual bool endDTD() = 0; +// virtual bool startEntity( const QString& name ) = 0; +// virtual bool endEntity( const QString& name ) = 0; + virtual bool startCDATA() = 0; + virtual bool endCDATA() = 0; + virtual bool comment( const QString& ch ) = 0; + virtual QString errorString() = 0; +}; + +class QM_EXPORT QXmlDeclHandler +{ +public: + virtual ~QXmlDeclHandler() {} + virtual bool attributeDecl( const QString& eName, const QString& aName, const QString& type, const QString& valueDefault, const QString& value ) = 0; + virtual bool internalEntityDecl( const QString& name, const QString& value ) = 0; + virtual bool externalEntityDecl( const QString& name, const QString& publicId, const QString& systemId ) = 0; + virtual QString errorString() = 0; +}; + + +class QM_EXPORT QXmlDefaultHandler : public QXmlContentHandler, public QXmlErrorHandler, public QXmlDTDHandler, public QXmlEntityResolver, public QXmlLexicalHandler, public QXmlDeclHandler +{ +public: + QXmlDefaultHandler() { } + virtual ~QXmlDefaultHandler() { } + + void setDocumentLocator( QXmlLocator* locator ); + bool startDocument(); + bool endDocument(); + bool startPrefixMapping( const QString& prefix, const QString& uri ); + bool endPrefixMapping( const QString& prefix ); + bool startElement( const QString& namespaceURI, const QString& localName, const QString& qName, const QXmlAttributes& atts ); + bool endElement( const QString& namespaceURI, const QString& localName, const QString& qName ); + bool characters( const QString& ch ); + bool ignorableWhitespace( const QString& ch ); + bool processingInstruction( const QString& target, const QString& data ); + bool skippedEntity( const QString& name ); + + bool warning( const QXmlParseException& exception ); + bool error( const QXmlParseException& exception ); + bool fatalError( const QXmlParseException& exception ); + + bool notationDecl( const QString& name, const QString& publicId, const QString& systemId ); + bool unparsedEntityDecl( const QString& name, const QString& publicId, const QString& systemId, const QString& notationName ); + + bool resolveEntity( const QString& publicId, const QString& systemId, QXmlInputSource* ret ); + + bool startDTD( const QString& name, const QString& publicId, const QString& systemId ); + bool endDTD(); +// bool startEntity( const QString& name ); +// bool endEntity( const QString& name ); + bool startCDATA(); + bool endCDATA(); + bool comment( const QString& ch ); + + bool attributeDecl( const QString& eName, const QString& aName, const QString& type, const QString& valueDefault, const QString& value ); + bool internalEntityDecl( const QString& name, const QString& value ); + bool externalEntityDecl( const QString& name, const QString& publicId, const QString& systemId ); + + QString errorString(); + +private: + QXmlDefaultHandlerPrivate *d; +}; + +#ifdef _WS_QWS_ +#ifdef QT_XML_CPP +#define inline +#else +#define QT_NO_XML_INLINE +#endif +#endif + +#ifndef QT_NO_XML_INLINE +// +// inlines +// + +inline bool QXmlSimpleReader::is_S(const QChar& ch) +{ return ch==' ' || ch=='\t' || ch=='\n' || ch=='\r'; } + +inline bool QXmlSimpleReader::is_Letter( const QChar& ch ) +{ return ch.isLetter(); } + +inline bool QXmlSimpleReader::is_NameBeginning( const QChar& ch ) +{ return ch=='_' || ch==':' || ch.isLetter(); } + +inline bool QXmlSimpleReader::is_Digit( const QChar& ch ) +{ return ch.isDigit(); } + +inline bool QXmlSimpleReader::is_CombiningChar( const QChar& ) +{ return FALSE; } + +inline bool QXmlSimpleReader::is_Extender( const QChar& ) +{ return FALSE; } + +inline bool QXmlSimpleReader::is_NameChar( const QChar& ch ) +{ + return ch=='.' || ch=='-' || ch=='_' || ch==':' || + is_Letter(ch) || is_Digit(ch) || + is_CombiningChar(ch) || is_Extender(ch); +} + +inline void QXmlSimpleReader::next() +{ + if ( !xmlRef.isEmpty() ) { + c = xmlRef[0]; + xmlRef.remove( 0, 1 ); + } else { + if ( c=='\n' || c=='\r' ) { + lineNr++; + columnNr = -1; + } + if ( pos >= xmlLength ) { + c = QEOF; + } else { + c = xml[pos]; + columnNr++; + pos++; + } + } +} + +inline bool QXmlSimpleReader::atEnd() +{ return c == QEOF; } + +inline void QXmlSimpleReader::eat_ws() +{ while ( !atEnd() && is_S(c) ) next(); } + +inline void QXmlSimpleReader::next_eat_ws() +{ next(); eat_ws(); } + + +// use buffers instead of QString::operator+= when single characters are read +inline QString& QXmlSimpleReader::string() +{ + stringValue += QString( stringArray, stringPos ); + stringPos = 0; + return stringValue; +} +inline QString& QXmlSimpleReader::name() +{ + nameValue += QString( nameArray, namePos ); + namePos = 0; + return nameValue; +} +inline QString& QXmlSimpleReader::ref() +{ + refValue += QString( refArray, refPos ); + refPos = 0; + return refValue; +} + +inline void QXmlSimpleReader::stringClear() +{ stringValue = ""; stringPos = 0; } +inline void QXmlSimpleReader::nameClear() +{ nameValue = ""; namePos = 0; } +inline void QXmlSimpleReader::refClear() +{ refValue = ""; refPos = 0; } + +inline void QXmlSimpleReader::stringAddC() +{ + if ( stringPos >= 256 ) { + stringValue += QString( stringArray, stringPos ); + stringPos = 0; + } + stringArray[stringPos++] = c; +} +inline void QXmlSimpleReader::nameAddC() +{ + if ( namePos >= 256 ) { + nameValue += QString( nameArray, namePos ); + namePos = 0; + } + nameArray[namePos++] = c; +} +inline void QXmlSimpleReader::refAddC() +{ + if ( refPos >= 256 ) { + refValue += QString( refArray, refPos ); + refPos = 0; + } + refArray[refPos++] = c; +} + +inline void QXmlSimpleReader::stringAddC(const QChar& ch) +{ + if ( stringPos >= 256 ) { + stringValue += QString( stringArray, stringPos ); + stringPos = 0; + } + stringArray[stringPos++] = ch; +} +inline void QXmlSimpleReader::nameAddC(const QChar& ch) +{ + if ( namePos >= 256 ) { + nameValue += QString( nameArray, namePos ); + namePos = 0; + } + nameArray[namePos++] = ch; +} +inline void QXmlSimpleReader::refAddC(const QChar& ch) +{ + if ( refPos >= 256 ) { + refValue += QString( refArray, refPos ); + refPos = 0; + } + refArray[refPos++] = ch; +} +#endif + +#ifdef _WS_QWS_ +#ifdef QT_XML_CPP +#undef inline +#endif +#endif + +#endif //QT_NO_XML + +#endif diff --git a/trunk/qtools/scstring.cpp b/trunk/qtools/scstring.cpp new file mode 100644 index 0000000..4a02320 --- /dev/null +++ b/trunk/qtools/scstring.cpp @@ -0,0 +1,792 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2004 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + +// with this switch you can choose between the original qcstring implementation, +// which implicitly shares data so copying is faster, but requires at least 12 bytes, and +// the new implementation in this file, which has a smaller footprint (only 4 bytes for +// an empty string), but always copies strings. +#define SMALLSTRING + +#include "qcstring.h" +#ifndef SMALLSTRING +#include "qcstring.cpp" +#else +#define SCString QCString + +#include <qstring.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <ctype.h> +#include <qregexp.h> +#include <qdatastream.h> + + +SCString::SCString(int size) +{ + if (size>0) + { + m_data = (char *)malloc(size); + if (m_data) + { + if (size>1) memset(m_data,' ',size-1); + m_data[size-1]='\0'; + } + } + else + { + m_data=0; + } +} + +SCString::SCString( const SCString &s ) +{ + duplicate(s); +} + +SCString::SCString( const char *str ) +{ + duplicate(str); +} + +SCString::SCString( const char *str, uint maxlen ) +{ + uint l; + if (str && ( l = QMIN(qstrlen(str),maxlen) )) + { + m_data=(char *)malloc(l+1); + strncpy(m_data,str,l+1); + m_data[l]='\0'; + } + else + { + m_data=0; + } +} + +SCString::~SCString() +{ + if (m_data) free(m_data); + m_data=0; +} + +SCString &SCString::assign( const char *str ) +{ + if (m_data==str) return *this; + if (m_data) free(m_data); + duplicate(str); + return *this; +} + +bool SCString::resize( uint newlen ) +{ + if (newlen==0) + { + if (m_data) { free(m_data); m_data=0; } + return TRUE; + } + if (m_data==0) // newlen>0 + { + m_data = (char *)malloc(newlen); + } + else + { + m_data = (char *)realloc(m_data,newlen); + } + if (m_data==0) return FALSE; + m_data[newlen-1]='\0'; + return TRUE; +} + +bool SCString::fill( char c, int len ) +{ + uint l=length(); + if (len<0) len=l; + if ((uint)len!=l) + { + if (m_data) free(m_data); + if (len>0) + { + m_data=(char *)malloc(len+1); + if (m_data==0) return FALSE; + m_data[len]='\0'; + } + else + { + m_data=0; + } + } + if (len>0) + { + uint i; + for (i=0;i<(uint)len;i++) m_data[i]=c; + } + return TRUE; +} + +SCString &SCString::sprintf( const char *format, ... ) +{ + va_list ap; + va_start( ap, format ); + uint l = length(); + const uint minlen=256; + if (l<minlen) + { + if (m_data) + m_data = (char *)realloc(m_data,minlen); + else + m_data = (char *)malloc(minlen); + } + vsprintf( m_data, format, ap ); + resize( qstrlen(m_data) + 1 ); // truncate + va_end( ap ); + return *this; +} + + +int SCString::find( char c, int index, bool cs ) const +{ + uint len = length(); + if ( m_data==0 || (uint)index>len ) // index outside string + return -1; + register const char *d; + if ( cs ) // case sensitive + { + d = strchr( m_data+index, c ); + } + else + { + d = m_data+index; + c = tolower( (uchar) c ); + while ( *d && tolower((uchar) *d) != c ) + d++; + if ( !*d && c ) // not found + d = 0; + } + return d ? (int)(d - m_data) : -1; +} + +int SCString::find( const char *str, int index, bool cs ) const +{ + uint l = length(); + if ( m_data==0 || (uint)index > l ) // index outside string + return -1; + if ( !str ) // no search string + return -1; + if ( !*str ) // zero-length search string + return index; + register const char *d; + if ( cs ) // case sensitive + { + d = strstr( m_data+index, str ); + } + else // case insensitive + { + d = m_data+index; + int len = qstrlen( str ); + while ( *d ) + { + if ( qstrnicmp(d, str, len) == 0 ) + break; + d++; + } + if ( !*d ) // not found + d = 0; + } + return d ? (int)(d - m_data) : -1; +} + +int SCString::find( const QRegExp &rx, int index ) const +{ + QString d = QString::fromLatin1( m_data ); + return d.find( rx, index ); +} + +int SCString::findRev( char c, int index, bool cs) const +{ + const char *b = m_data; + const char *d; + uint len = length(); + if ( b == 0 ) return -1; // empty string + if ( index < 0 ) // neg index ==> start from end + { + if ( len == 0 ) return -1; + if ( cs ) + { + d = strrchr( b, c ); + return d ? (int)(d - b) : -1; + } + index = len; + } + else if ( (uint)index > len ) // bad index + { + return -1; + } + d = b+index; + if ( cs ) // case sensitive + { + while ( d >= b && *d != c ) + d--; + } + else // case insensitive + { + c = tolower( (uchar) c ); + while ( d >= b && tolower((uchar) *d) != c ) + d--; + } + return d >= b ? (int)(d - b) : -1; +} + +int SCString::findRev( const char *str, int index, bool cs) const +{ + int slen = qstrlen(str); + uint len = length(); + if ( index < 0 ) // neg index ==> start from end + index = len-slen; + else if ( (uint)index > len ) // bad index + return -1; + else if ( (uint)(index + slen) > len ) // str would be too long + index = len - slen; + if ( index < 0 ) + return -1; + + register char *d = m_data + index; + if ( cs ) // case sensitive + { + for ( int i=index; i>=0; i-- ) + if ( qstrncmp(d--,str,slen)==0 ) + return i; + } + else // case insensitive + { + for ( int i=index; i>=0; i-- ) + if ( qstrnicmp(d--,str,slen)==0 ) + return i; + } + return -1; + +} + +int SCString::findRev( const QRegExp &rx, int index ) const +{ + QString d = QString::fromLatin1( m_data ); + return d.findRev( rx, index ); +} + +int SCString::contains( char c, bool cs ) const +{ + int count = 0; + char *d = m_data; + if ( !d ) + return 0; + if ( cs ) // case sensitive + { + while ( *d ) + if ( *d++ == c ) + count++; + } + else // case insensitive + { + c = tolower( (uchar) c ); + while ( *d ) { + if ( tolower((uchar) *d) == c ) + count++; + d++; + } + } + return count; +} + +int SCString::contains( const char *str, bool cs ) const +{ + int count = 0; + char *d = data(); + if ( !d ) + return 0; + int len = qstrlen( str ); + while ( *d ) // counts overlapping strings + { + if ( cs ) + { + if ( qstrncmp( d, str, len ) == 0 ) + count++; + } + else + { + if ( qstrnicmp(d, str, len) == 0 ) + count++; + } + d++; + } + return count; +} + +int SCString::contains( const QRegExp &rx ) const +{ + QString d = QString::fromLatin1( m_data ); + return d.contains( rx ); +} + +SCString SCString::left( uint len ) const +{ + if ( isEmpty() ) + { + return SCString(); + } + else if ( len >= length() ) + { + return *this; + } + else + { + SCString s( len+1 ); + strncpy( s.data(), m_data, len ); + *(s.data()+len) = '\0'; + return s; + } +} + +SCString SCString::right( uint len ) const +{ + if ( isEmpty() ) + { + return SCString(); + } + else + { + uint l = length(); + if ( len > l ) len = l; + char *p = m_data + (l - len); + return SCString( p ); + } +} + +SCString SCString::mid( uint index, uint len) const +{ + uint slen = length(); + if ( len == 0xffffffff ) len = slen-index; + if ( isEmpty() || index >= slen ) + { + return SCString(); + } + else + { + register char *p = data()+index; + SCString s( len+1 ); + strncpy( s.data(), p, len ); + *(s.data()+len) = '\0'; + return s; + } +} + +SCString SCString::lower() const +{ + SCString s( m_data ); + register char *p = s.data(); + if ( p ) + { + while ( *p ) + { + *p = tolower((uchar) *p); + p++; + } + } + return s; +} + +SCString SCString::upper() const +{ + SCString s( m_data ); + register char *p = s.data(); + if ( p ) { + while ( *p ) { + *p = toupper((uchar)*p); + p++; + } + } + return s; +} + +SCString SCString::stripWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + + register char *s = m_data; + int reslen = length(); + if ( !isspace((uchar) s[0]) && !isspace((uchar) s[reslen-1]) ) + return *this; // returns a copy + + SCString result(s); + s = result.data(); + int start = 0; + int end = reslen - 1; + while ( isspace((uchar) s[start]) ) // skip white space from start + start++; + if ( s[start] == '\0' ) + { // only white space + return SCString(); + } + while ( end && isspace((uchar) s[end]) ) // skip white space from end + end--; + end -= start - 1; + memmove( result.data(), &s[start], end ); + result.resize( end + 1 ); + return result; +} + +SCString SCString::simplifyWhiteSpace() const +{ + if ( isEmpty() ) // nothing to do + return *this; + + SCString result( length()+1 ); + char *from = data(); + char *to = result.data(); + char *first = to; + while ( TRUE ) + { + while ( *from && isspace((uchar) *from) ) + from++; + while ( *from && !isspace((uchar)*from) ) + *to++ = *from++; + if ( *from ) + *to++ = 0x20; // ' ' + else + break; + } + if ( to > first && *(to-1) == 0x20 ) + to--; + *to = '\0'; + result.resize( (int)((long)to - (long)result.data()) + 1 ); + return result; +} + +SCString &SCString::insert( uint index, const char *s ) +{ + int len = qstrlen(s); + if ( len == 0 ) + return *this; + uint olen = length(); + int nlen = olen + len; + if ( index >= olen ) // insert after end of string + { + m_data = (char *)realloc(m_data,nlen+index-olen+1); + if ( m_data ) + { + memset( m_data+olen, ' ', index-olen ); + memcpy( m_data+index, s, len+1 ); + } + } + else if ( (m_data = (char *)realloc(m_data,nlen+1)) ) // normal insert + { + memmove( m_data+index+len, m_data+index, olen-index+1 ); + memcpy( m_data+index, s, len ); + } + return *this; +} + +SCString &SCString::insert( uint index, char c ) // insert char +{ + char buf[2]; + buf[0] = c; + buf[1] = '\0'; + return insert( index, buf ); +} + +SCString& SCString::operator+=( const char *str ) +{ + if ( !str ) return *this; // nothing to append + uint len1 = length(); + uint len2 = qstrlen(str); + char *newData = (char *)realloc( m_data, len1 + len2 + 1 ); + if (newData) + { + m_data = newData; + memcpy( m_data + len1, str, len2 + 1 ); + } + return *this; +} + +SCString &SCString::operator+=( char c ) +{ + uint len = length(); + char *newData = (char *)realloc( m_data, length()+2 ); + if (newData) + { + m_data = newData; + m_data[len] = c; + m_data[len+1] = '\0'; + } + return *this; +} + +SCString &SCString::remove( uint index, uint len ) +{ + uint olen = length(); + if ( index + len >= olen ) // range problems + { + if ( index < olen ) // index ok + { + resize( index+1 ); + } + } + else if ( len != 0 ) + { + memmove( m_data+index, m_data+index+len, olen-index-len+1 ); + resize( olen-len+1 ); + } + return *this; +} + +SCString &SCString::replace( uint index, uint len, const char *s ) +{ + remove( index, len ); + insert( index, s ); + return *this; +} + +SCString &SCString::replace( const QRegExp &rx, const char *str ) +{ + QString d = QString::fromLatin1( m_data ); + QString r = QString::fromLatin1( str ); + d.replace( rx, r ); + return assign(d.ascii()); +} + +long SCString::toLong( bool *ok ) const +{ + QString s(m_data); + return s.toLong(ok); +} + +ulong SCString::toULong( bool *ok ) const +{ + QString s(m_data); + return s.toULong(ok); +} + +short SCString::toShort( bool *ok ) const +{ + QString s(m_data); + return s.toShort(ok); +} + +ushort SCString::toUShort( bool *ok ) const +{ + QString s(m_data); + return s.toUShort(ok); +} + +int SCString::toInt( bool *ok ) const +{ + QString s(m_data); + return s.toInt(ok); +} + +uint SCString::toUInt( bool *ok ) const +{ + QString s(m_data); + return s.toUInt(ok); +} + +SCString &SCString::setNum( long n ) +{ + char buf[20]; + register char *p = &buf[19]; + bool neg; + if ( n < 0 ) + { + neg = TRUE; + n = -n; + } + else + { + neg = FALSE; + } + *p = '\0'; + do + { + *--p = ((int)(n%10)) + '0'; + n /= 10; + } while ( n ); + if ( neg ) *--p = '-'; + operator=( p ); + return *this; +} + +SCString &SCString::setNum( ulong n ) +{ + char buf[20]; + register char *p = &buf[19]; + *p = '\0'; + do + { + *--p = ((int)(n%10)) + '0'; + n /= 10; + } while ( n ); + operator=( p ); + return *this; +} + +void SCString::msg_index( uint index ) +{ +#if defined(CHECK_RANGE) + qWarning( "SCString::at: Absolute index %d out of range", index ); +#else + Q_UNUSED( index ) +#endif +} + +bool SCString::stripPrefix(const char *prefix) +{ + if (prefix==0) return FALSE; + uint plen = qstrlen(prefix); + if (m_data && qstrncmp(prefix,m_data,plen)==0) // prefix matches + { + uint len = qstrlen(m_data); + uint newlen = len-plen+1; + qmemmove(m_data,m_data+plen,newlen); + resize(newlen); + return TRUE; + } + return FALSE; +} + +//--------------------------------------------------------------------------- + +void *qmemmove( void *dst, const void *src, uint len ) +{ + register char *d; + register char *s; + if ( dst > src ) { + d = (char *)dst + len - 1; + s = (char *)src + len - 1; + while ( len-- ) + *d-- = *s--; + } else if ( dst < src ) { + d = (char *)dst; + s = (char *)src; + while ( len-- ) + *d++ = *s++; + } + return dst; +} + +char *qstrdup( const char *str ) +{ + if ( !str ) + return 0; + char *dst = new char[strlen(str)+1]; + CHECK_PTR( dst ); + return strcpy( dst, str ); +} + +char *qstrncpy( char *dst, const char *src, uint len ) +{ + if ( !src ) + return 0; + strncpy( dst, src, len ); + if ( len > 0 ) + dst[len-1] = '\0'; + return dst; +} + +int qstricmp( const char *str1, const char *str2 ) +{ + register const uchar *s1 = (const uchar *)str1; + register const uchar *s2 = (const uchar *)str2; + int res; + uchar c; + if ( !s1 || !s2 ) + return s1 == s2 ? 0 : (int)((long)s2 - (long)s1); + for ( ; !(res = (c=tolower(*s1)) - tolower(*s2)); s1++, s2++ ) + if ( !c ) // strings are equal + break; + return res; +} + +int qstrnicmp( const char *str1, const char *str2, uint len ) +{ + register const uchar *s1 = (const uchar *)str1; + register const uchar *s2 = (const uchar *)str2; + int res; + uchar c; + if ( !s1 || !s2 ) + return (int)((long)s2 - (long)s1); + for ( ; len--; s1++, s2++ ) { + if ( (res = (c=tolower(*s1)) - tolower(*s2)) ) + return res; + if ( !c ) // strings are equal + break; + } + return 0; +} + +#ifndef QT_NO_DATASTREAM + +QDataStream &operator<<( QDataStream &s, const QByteArray &a ) +{ + return s.writeBytes( a.data(), a.size() ); +} + +QDataStream &operator>>( QDataStream &s, QByteArray &a ) +{ + Q_UINT32 len; + s >> len; // read size of array + if ( len == 0 || s.eof() ) { // end of file reached + a.resize( 0 ); + return s; + } + if ( !a.resize( (uint)len ) ) { // resize array +#if defined(CHECK_NULL) + qWarning( "QDataStream: Not enough memory to read QByteArray" ); +#endif + len = 0; + } + if ( len > 0 ) // not null array + s.readRawBytes( a.data(), (uint)len ); + return s; +} + +QDataStream &operator<<( QDataStream &s, const SCString &str ) +{ + return s.writeBytes( str.data(), str.size() ); +} + +QDataStream &operator>>( QDataStream &s, SCString &str ) +{ + Q_UINT32 len; + s >> len; // read size of string + if ( len == 0 || s.eof() ) { // end of file reached + str.resize( 0 ); + return s; + } + if ( !str.resize( (uint)len )) {// resize string +#if defined(CHECK_NULL) + qWarning( "QDataStream: Not enough memory to read QCString" ); +#endif + len = 0; + } + if ( len > 0 ) // not null array + s.readRawBytes( str.data(), (uint)len ); + return s; +} + +#endif //QT_NO_DATASTREAM + + + +#endif diff --git a/trunk/qtools/scstring.h b/trunk/qtools/scstring.h new file mode 100644 index 0000000..08de44b --- /dev/null +++ b/trunk/qtools/scstring.h @@ -0,0 +1,154 @@ +/****************************************************************************** + * + * Copyright (C) 1997-2004 by Dimitri van Heesch. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation under the terms of the GNU General Public License is hereby + * granted. No representations are made about the suitability of this software + * for any purpose. It is provided "as is" without express or implied warranty. + * See the GNU General Public License for more details. + * + * Documents produced by Doxygen are derivative works derived from the + * input used in their production; they are not affected by this license. + * + */ + +#ifndef SCSTRING_H +#define SCSTRING_H + +#include <stdlib.h> + +class QRegExp; + +/** This is an alternative implementation of QCString. It provides basically + * the same functions but uses less memory for administration. This class + * is just a wrapper around a plain C string requiring only 4 bytes "overhead". + * QCString features sharing of data and stores the string length, but + * requires 4 + 12 bytes for this (even for the empty string). As doxygen + * uses a LOT of string during a run it saves a lot of memory to use a + * more memory efficient implementation at the cost of relatively low + * runtime overhead. + */ +class SCString +{ +public: + SCString() : m_data(0) {} // make null string + SCString( const SCString &s ); + SCString( int size ); + SCString( const char *str ); + SCString( const char *str, uint maxlen ); + ~SCString(); + + SCString &operator=( const SCString &s );// deep copy + SCString &operator=( const char *str ); // deep copy + + bool isNull() const; + bool isEmpty() const; + uint length() const; + uint size() const { return m_data ? length()+1 : 0; } + char * data() const { return m_data; } + bool resize( uint newlen ); + bool truncate( uint pos ); + bool fill( char c, int len = -1 ); + + SCString copy() const; + + SCString &sprintf( const char *format, ... ); + + int find( char c, int index=0, bool cs=TRUE ) const; + int find( const char *str, int index=0, bool cs=TRUE ) const; + int find( const QRegExp &, int index=0 ) const; + int findRev( char c, int index=-1, bool cs=TRUE) const; + int findRev( const char *str, int index=-1, bool cs=TRUE) const; + int findRev( const QRegExp &, int index=-1 ) const; + int contains( char c, bool cs=TRUE ) const; + int contains( const char *str, bool cs=TRUE ) const; + int contains( const QRegExp & ) const; + bool stripPrefix(const char *prefix); + + SCString left( uint len ) const; + SCString right( uint len ) const; + SCString mid( uint index, uint len=0xffffffff) const; + + SCString lower() const; + SCString upper() const; + + SCString stripWhiteSpace() const; + SCString simplifyWhiteSpace() const; + + SCString &assign( const char *str ); + SCString &insert( uint index, const char * ); + SCString &insert( uint index, char ); + SCString &append( const char *s ); + SCString &prepend( const char *s ); + SCString &remove( uint index, uint len ); + SCString &replace( uint index, uint len, const char * ); + SCString &replace( const QRegExp &, const char * ); + + short toShort( bool *ok=0 ) const; + ushort toUShort( bool *ok=0 ) const; + int toInt( bool *ok=0 ) const; + uint toUInt( bool *ok=0 ) const; + long toLong( bool *ok=0 ) const; + ulong toULong( bool *ok=0 ) const; + + SCString &setNum( short ); + SCString &setNum( ushort ); + SCString &setNum( int ); + SCString &setNum( uint ); + SCString &setNum( long ); + SCString &setNum( ulong ); + QCString &setNum( float, char f='g', int prec=6 ); + QCString &setNum( double, char f='g', int prec=6 ); + + operator const char *() const; + SCString &operator+=( const char *str ); + SCString &operator+=( char c ); + char &at( uint index ) const; + char &operator[]( int i ) const { return at(i); } + + private: + static void msg_index( uint ); + void duplicate( const SCString &s ); + void duplicate( const char *str); + SCString &duplicate( const char *str, int); + + char * m_data; +}; + +inline char &SCString::at( uint index ) const +{ + return m_data[index]; +} + +inline void SCString::duplicate( const SCString &s ) +{ + if (!s.isEmpty()) + { + uint l = strlen(s.data()); + m_data = (char *)malloc(l+1); + if (m_data) memcpy(m_data,s.data(),l+1); + } + else + m_data=0; +} +inline void SCString::duplicate( const char *str) +{ + if (str && str[0]!='\0') + { + uint l = strlen(str); + m_data = (char *)malloc(l+1); + if (m_data) memcpy(m_data,str,l+1); + } + else + m_data=0; +} +inline SCString &SCString::duplicate( const char *str, int) +{ + if (m_data) free(m_data); + duplicate(str); + return *this; +} + +#endif + |